Robbo
Well-known member
This is the start of an abstract class to make creating installers easier for developers. What I am about to post hasn't even been tested yet but it gives you an idea of where I am going with it, I would like for developers to add their input (and changes when I add to git) to make our lives easier.
It handles content types nicely (haven't added everything there yet) including cleaning up old data when you remove one. It also has add and remove table column methods which check if columns exist for you.
You extend this class and create a method for each version id. _installVersion1, _installVersion2, _uninstallVersion1 etc. If you ignore the abstract class it is overall a nice OO class to work with (no staticness).
PHP:
<?php
abstract class XenTrader_Installer_Abstract
{
protected $_db;
protected $_existingAddon;
protected $_addonData;
protected $_rebuildContentCache = false;
public function __construct($existingAddon, $addonData)
{
$this->_db = XenForo_Application::get('db');
$this->_existingAddon = $existingAddon;
$this->_addonData = $addonData;
}
public function __destruct()
{
if ($this->_rebuildContentCache)
{
XenForo_Model::create('XenForo_Model_ContentType')->rebuildContentTypeCache();
}
}
public static function intall($existingAddon, $addonData)
{
$installer = new self($existingAddon, $addonData);
return $installer->runInstall();
}
public static function uninstall($existingAddon, $addonData)
{
$installer = new self($existingAddon, $addonData);
return $installer->runUninstall();
}
public function runInstall()
{
$start = 1;
if ($this->_existingAddon)
$start += $this->_existingAddon['version_id'];
for ($v = $start; $v <= $this->_addonData['version_id']; ++$v)
$this->_callVersionMethod($v);
return true;
}
public function runUninstall()
{
for ($v = $this->_existingAddon['version_id']; $v >= 0; --$v)
$this->_callVersionMethod($v, true);
return true;
}
protected function _callVersionMethod($version, $uninstall = false)
{
if (method_exists($this, '_' . ($uninstall ? 'un' : '') . 'installVersion' . $version))
$this->{'_' . ($uninstall ? 'un' : '') . 'installVersion' . $version}();
}
protected function _bulkAddContentType(array $types)
{
if (!is_array($types))
return;
foreach ($types as $type => $pairs)
{
if (!is_array($pairs))
continue;
foreach ($pairs as $name => $value)
$this->_addContentType($type, $name, $value);
}
}
protected function _addContentType($type, $name, $value)
{
$this->_rebuildContentCache = true;
if (!$this->_db->fetchRow('SELECT * FROM xf_content_type_field WHERE content_type = ? AND field_name = ?', array($type, $name)))
$this->_db->insert('xf_content_type_field', array(
'content_type' => $type,
'field_name' => $name,
'field_value' => $value)
);
if (!$this->_db->fetchRow('SELECT * FROM xf_content_type WHERE content_type = ?', $type))
$this->db->insert('xf_content_type', array('content_type' => $type, 'addon_id' => $this->_addonData['addon_id'], 'fields' => ''));
}
protected function _removeContentType($type, $name = null)
{
$this->_rebuildContentCache = true;
$handlers = array(
'alert_handler_class' => 'xf_user_alert',
'news_feed_handler_class' => 'xf_news_feed',
'report_handler_class' => array('xf_report', '_removeReportComments'),
// TODO: add the rest of the possible handlers
);
$single = false;
if ($name && isset($handlers[$name]))
$single = $handlers[$name];
else
$name = '*';
$this->_db->delete('xf_content_type', array('content_type = ?' => $type));
$this->_db->delete('xf_content_type_field', array('content_type = ? AND field_name = ?' => array($type, $name)));
if ($single)
{
if (is_array($single))
{
if (method_exists($this, $single[1]))
$this->$single[1]($type);
$single = $single[0];
}
$this->_db->delete($single, array('content_type = ?' => $type));
return;
}
foreach ($handlers as $handle)
{
if (is_array($handle))
{
if (method_exists($this, $handle[1]))
$this->$handle[1]($type);
$handle = $handle[0];
}
$this->_db->delete($handle, array('content_type = ?' => $type));
}
}
protected function _removeReportComments($type)
{
$reportIds = $this->_db->fetchCol('SELECT report_id FROM xf_report WHERE content_type = ?', $type);
if (!empty($reportIds))
$this->_db->delete('xf_report_comment', array('report_id IN (' . implode(',', $reportIds) . ')'));
}
protected function _addTableColumn($table, $field, $info, $after = '')
{
$columns = $this->_db->describeTable($table);
if (isset($columns[$field]))
return;
if (isset($columns[$after]))
$info .= ' AFTER ' . $after;
$this->_db->query("ALTER TABLE '$table' ADD '$field' $info");
}
protected function _removeTableColumn($table, $field)
{
$columns = $this->_db->describeTable($table);
if (isset($columns[$field]))
{
$this->_db->query("ALERT TABLE '$table' DROP '$field'");
}
}
}
It handles content types nicely (haven't added everything there yet) including cleaning up old data when you remove one. It also has add and remove table column methods which check if columns exist for you.
You extend this class and create a method for each version id. _installVersion1, _installVersion2, _uninstallVersion1 etc. If you ignore the abstract class it is overall a nice OO class to work with (no staticness).