1082 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			1082 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| /**
 | |
|  * @package    Com_Highlights
 | |
|  * @author     Eddy Prosperi <eddy.prosperi@protocollicreativi.it>
 | |
|  * @copyright  2024 Eddy Prosperi
 | |
|  * @license    GNU General Public License versione 2 o successiva; vedi LICENSE.txt
 | |
|  */
 | |
| 
 | |
| define('MODIFIED', 1);
 | |
| define('NOT_MODIFIED', 2);
 | |
| 
 | |
| defined('_JEXEC') or die();
 | |
| 
 | |
| use \Joomla\CMS\Factory;
 | |
| use \Joomla\CMS\Language\Text;
 | |
| use \Joomla\CMS\Installer\Installer;
 | |
| use \Joomla\CMS\Installer\InstallerScript;
 | |
| 
 | |
| /**
 | |
|  * Updates the database structure of the component
 | |
|  *
 | |
|  * @version  Release: 0.2b
 | |
|  * @author   Component Creator <support@component-creator.com>
 | |
|  * @since    0.1b
 | |
|  */
 | |
| class com_highlightsInstallerScript extends InstallerScript
 | |
| {
 | |
| 	/**
 | |
| 	 * The title of the component (printed on installation and uninstallation messages)
 | |
| 	 *
 | |
| 	 * @var string
 | |
| 	 */
 | |
| 	protected $extension = 'Highlights';
 | |
| 
 | |
| 	/**
 | |
| 	 * The minimum Joomla! version required to install this extension
 | |
| 	 *
 | |
| 	 * @var   string
 | |
| 	 */
 | |
| 	protected $minimumJoomla = '4.0';
 | |
| 
 | |
| 	/**
 | |
| 	 * Method called before install/update the component. Note: This method won't be called during uninstall process.
 | |
| 	 *
 | |
| 	 * @param   string $type   Type of process [install | update]
 | |
| 	 * @param   mixed  $parent Object who called this method
 | |
| 	 *
 | |
| 	 * @return boolean True if the process should continue, false otherwise
 | |
|      * @throws Exception
 | |
| 	 */
 | |
| 	public function preflight($type, $parent)
 | |
| 	{
 | |
| 		$result = parent::preflight($type, $parent);
 | |
| 
 | |
| 		if (!$result)
 | |
| 		{
 | |
| 			return $result;
 | |
| 		}
 | |
| 
 | |
| 		// logic for preflight before install
 | |
| 		return $result;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Method to install the component
 | |
| 	 *
 | |
| 	 * @param   mixed $parent Object who called this method.
 | |
| 	 *
 | |
| 	 * @return void
 | |
| 	 *
 | |
| 	 * @since 0.2b
 | |
| 	 */
 | |
| 	public function install($parent)
 | |
| 	{
 | |
| 		$this->installDb($parent);
 | |
| 		$this->installPlugins($parent);
 | |
| 		$this->installModules($parent);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Method to update the DB of the component
 | |
| 	 *
 | |
| 	 * @param   mixed $parent Object who started the upgrading process
 | |
| 	 *
 | |
| 	 * @return void
 | |
| 	 *
 | |
| 	 * @since 0.2b
 | |
|      * @throws Exception
 | |
| 	 */
 | |
| 	private function installDb($parent)
 | |
| 	{
 | |
| 		$installation_folder = $parent->getParent()->getPath('source');
 | |
| 
 | |
| 		$app = Factory::getApplication();
 | |
| 
 | |
| 		if (function_exists('simplexml_load_file') && file_exists($installation_folder . '/installer/structure.xml'))
 | |
| 		{
 | |
| 			$component_data = simplexml_load_file($installation_folder . '/installer/structure.xml');
 | |
| 
 | |
| 			// Check if there are tables to import.
 | |
| 			foreach ($component_data->children() as $table)
 | |
| 			{
 | |
| 				$this->processTable($app, $table);
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			if (!function_exists('simplexml_load_file'))
 | |
| 			{
 | |
| 				$app->enqueueMessage(Text::_('This script needs \'simplexml_load_file\' to update the component'));
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				$app->enqueueMessage(Text::_('Structure file was not found.'));
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Process a table
 | |
| 	 *
 | |
| 	 * @param   CMSApplication  $app   Application object
 | |
| 	 * @param   SimpleXMLElement $table Table to process
 | |
| 	 *
 | |
| 	 * @return void
 | |
| 	 *
 | |
| 	 * @since 0.2b
 | |
| 	 */
 | |
| 	private function processTable($app, $table)
 | |
| 	{
 | |
| 		$db = Factory::getContainer()->get('DatabaseDriver');
 | |
| 
 | |
| 		$table_added = false;
 | |
| 
 | |
| 		if (isset($table['action']))
 | |
| 		{
 | |
| 			switch ($table['action'])
 | |
| 			{
 | |
| 				case 'add':
 | |
| 
 | |
| 					// Check if the table exists before create the statement
 | |
| 					if (!$this->existsTable($table['table_name']))
 | |
| 					{
 | |
| 						$create_statement = $this->generateCreateTableStatement($table);
 | |
| 						$db->setQuery($create_statement);
 | |
| 
 | |
| 						try
 | |
| 						{
 | |
| 							$db->execute();
 | |
| 							$app->enqueueMessage(
 | |
| 								Text::sprintf(
 | |
| 									'Table `%s` has been successfully created',
 | |
| 									(string) $table['table_name']
 | |
| 								)
 | |
| 							);
 | |
| 							$table_added = true;
 | |
| 						} catch (Exception $ex)
 | |
| 						{
 | |
| 							$app->enqueueMessage(
 | |
| 								Text::sprintf(
 | |
| 									'There was an error creating the table `%s`. Error: %s',
 | |
| 									(string) $table['table_name'],
 | |
| 									$ex->getMessage()
 | |
| 								), 'error'
 | |
| 							);
 | |
| 						}
 | |
| 					}
 | |
| 					break;
 | |
| 				case 'change':
 | |
| 
 | |
| 					// Check if the table exists first to avoid errors.
 | |
| 					if ($this->existsTable($table['old_name']) && !$this->existsTable($table['new_name']))
 | |
| 					{
 | |
| 						try
 | |
| 						{
 | |
| 							$db->renameTable($table['old_name'], $table['new_name']);
 | |
| 							$app->enqueueMessage(
 | |
| 								Text::sprintf(
 | |
| 									'Table `%s` was successfully renamed to `%s`',
 | |
| 									$table['old_name'],
 | |
| 									$table['new_name']
 | |
| 								)
 | |
| 							);
 | |
| 						} catch (Exception $ex)
 | |
| 						{
 | |
| 							$app->enqueueMessage(
 | |
| 								Text::sprintf(
 | |
| 									'There was an error renaming the table `%s`. Error: %s',
 | |
| 									$table['old_name'],
 | |
| 									$ex->getMessage()
 | |
| 								), 'error'
 | |
| 							);
 | |
| 						}
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						if (!$this->existsTable($table['table_name']))
 | |
| 						{
 | |
| 							// If the table does not exists, let's create it.
 | |
| 							$create_statement = $this->generateCreateTableStatement($table);
 | |
| 							$db->setQuery($create_statement);
 | |
| 
 | |
| 							try
 | |
| 							{
 | |
| 								$db->execute();
 | |
| 								$app->enqueueMessage(
 | |
| 									Text::sprintf('Table `%s` has been successfully created', $table['table_name'])
 | |
| 								);
 | |
| 								$table_added = true;
 | |
| 							} catch (Exception $ex)
 | |
| 							{
 | |
| 								$app->enqueueMessage(
 | |
| 									Text::sprintf(
 | |
| 										'There was an error creating the table `%s`. Error: %s',
 | |
| 										$table['table_name'],
 | |
| 										$ex->getMessage()
 | |
| 									), 'error'
 | |
| 								);
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 					break;
 | |
| 				case 'remove':
 | |
| 
 | |
| 					try
 | |
| 					{
 | |
| 						// We make sure that the table will be removed only if it exists specifying ifExists argument as true.
 | |
| 						$db->dropTable((string) $table['table_name'], true);
 | |
| 						$app->enqueueMessage(
 | |
| 							Text::sprintf('Table `%s` was successfully deleted', $table['table_name'])
 | |
| 						);
 | |
| 					} catch (Exception $ex)
 | |
| 					{
 | |
| 						$app->enqueueMessage(
 | |
| 							Text::sprintf(
 | |
| 								'There was an error deleting Table `%s`. Error: %s',
 | |
| 								$table['table_name'], $ex->getMessage()
 | |
| 							), 'error'
 | |
| 						);
 | |
| 					}
 | |
| 
 | |
| 					break;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// If the table wasn't added before, let's process the fields of the table
 | |
| 		if (!$table_added)
 | |
| 		{
 | |
| 			if ($this->existsTable($table['table_name']))
 | |
| 			{
 | |
| 				$this->executeFieldsUpdating($app, $table);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Checks if a certain exists on the current database
 | |
| 	 *
 | |
| 	 * @param   string $table_name Name of the table
 | |
| 	 *
 | |
| 	 * @return boolean True if it exists, false if it does not.
 | |
| 	 */
 | |
| 	private function existsTable($table_name)
 | |
| 	{
 | |
| 		$db = Factory::getContainer()->get('DatabaseDriver');
 | |
| 
 | |
| 		$table_name = str_replace('#__', $db->getPrefix(), (string) $table_name);
 | |
| 
 | |
| 		return in_array($table_name, $db->getTableList());
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Generates a 'CREATE TABLE' statement for the tables passed by argument.
 | |
| 	 *
 | |
| 	 * @param   SimpleXMLElement $table Table of the database
 | |
| 	 *
 | |
| 	 * @return string 'CREATE TABLE' statement
 | |
| 	 */
 | |
| 	private function generateCreateTableStatement($table)
 | |
| 	{
 | |
| 		$create_table_statement = '';
 | |
| 
 | |
| 		if (isset($table->field))
 | |
| 		{
 | |
| 			$fields = $table->children();
 | |
| 
 | |
| 			$fields_definitions = array();
 | |
| 			$indexes            = array();
 | |
| 
 | |
| 			$db = Factory::getContainer()->get('DatabaseDriver');
 | |
| 
 | |
| 			foreach ($fields as $field)
 | |
| 			{
 | |
| 				$field_definition = $this->generateColumnDeclaration($field);
 | |
| 
 | |
| 				if ($field_definition !== false)
 | |
| 				{
 | |
| 					$fields_definitions[] = $field_definition;
 | |
| 				}
 | |
| 
 | |
| 				if ($field['index'] == 'index')
 | |
| 				{
 | |
| 					$indexes[] = $field['field_name'];
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			foreach ($indexes as $index)
 | |
| 			{
 | |
| 				$fields_definitions[] = Text::sprintf(
 | |
| 					'INDEX %s (%s ASC)',
 | |
| 					$db->quoteName((string) $index), $index
 | |
| 				);
 | |
| 			}
 | |
| 
 | |
| 			// Avoid duplicate PK definition
 | |
|             if (strpos(implode(',', $fields_definitions), 'PRIMARY KEY') === false)
 | |
|             {
 | |
|                 $fields_definitions[] = 'PRIMARY KEY (`id`)';
 | |
|             }
 | |
| 
 | |
| 			$create_table_statement = Text::sprintf(
 | |
| 				'CREATE TABLE IF NOT EXISTS %s (%s)',
 | |
| 				$table['table_name'],
 | |
| 				implode(',', $fields_definitions)
 | |
| 			);
 | |
| 
 | |
| 			if(isset($table['storage_engine']) && !empty($table['storage_engine']))
 | |
| 			{
 | |
| 				$create_table_statement .= " ENGINE=" . $table['storage_engine'];
 | |
| 			}
 | |
| 			if(isset($table['collation']))
 | |
| 			{
 | |
| 				$create_table_statement .= " DEFAULT COLLATE=" . $table['collation'];
 | |
| 			}
 | |
| 		}
 | |
| 		return $create_table_statement;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Generate a column declaration
 | |
| 	 *
 | |
| 	 * @param   SimpleXMLElement $field Field data
 | |
| 	 *
 | |
| 	 * @return string Column declaration
 | |
| 	 */
 | |
| 	private function generateColumnDeclaration($field)
 | |
| 	{
 | |
| 		$db        = Factory::getContainer()->get('DatabaseDriver');
 | |
| 		$col_name  = $db->quoteName((string) $field['field_name']);
 | |
| 		$data_type = $this->getFieldType($field);
 | |
| 
 | |
| 		if ($data_type !== false)
 | |
| 		{
 | |
| 			$default_value = (isset($field['default'])) ? 'DEFAULT ' . $field['default'] : '';
 | |
| 
 | |
| 			$other_data = '';
 | |
| 
 | |
| 			if (isset($field['is_autoincrement']) && $field['is_autoincrement'] == 1)
 | |
| 			{
 | |
| 				$other_data .= ' AUTO_INCREMENT PRIMARY KEY';
 | |
| 			}
 | |
| 
 | |
| 			$comment_value = (isset($field['description'])) ? 'COMMENT ' . $db->quote((string) $field['description']) : '';
 | |
| 
 | |
| 			if(strtolower($field['field_type']) == 'datetime' || strtolower($field['field_type']) == 'text')
 | |
| 			{
 | |
| 				return Text::sprintf(
 | |
| 					'%s %s %s %s %s', $col_name, $data_type,
 | |
| 					$default_value, $other_data, $comment_value
 | |
| 				);
 | |
| 			}
 | |
| 
 | |
| 			if((isset($field['required']) && $field['required'] == 1)  || $field['field_name'] == 'id')
 | |
| 			{
 | |
| 				return Text::sprintf(
 | |
| 					'%s %s NOT NULL %s %s %s', $col_name, $data_type,
 | |
| 					$default_value, $other_data, $comment_value
 | |
| 				);
 | |
| 			}
 | |
| 
 | |
| 			return Text::sprintf(
 | |
| 				'%s %s NULL %s %s %s', $col_name, $data_type,
 | |
| 				$default_value, $other_data, $comment_value
 | |
| 			);
 | |
| 			
 | |
| 		}
 | |
| 
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Generates SQL field type of a field.
 | |
| 	 *
 | |
| 	 * @param   SimpleXMLElement $field Field information
 | |
| 	 *
 | |
| 	 * @return  mixed SQL string data type, false on failure.
 | |
| 	 */
 | |
| 	private function getFieldType($field)
 | |
| 	{
 | |
| 		$data_type = (string) $field['field_type'];
 | |
| 
 | |
| 		if (isset($field['field_length']) && ($this->allowsLengthField($data_type) || $data_type == 'ENUM'))
 | |
| 		{
 | |
| 			$data_type .= '(' . (string) $field['field_length'] . ')';
 | |
| 		}
 | |
| 
 | |
| 		return (!empty($data_type)) ? $data_type : false;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Check if a SQL type allows length values.
 | |
| 	 *
 | |
| 	 * @param   string $field_type SQL type
 | |
| 	 *
 | |
| 	 * @return boolean True if it allows length values, false if it does not.
 | |
| 	 */
 | |
| 	private function allowsLengthField($field_type)
 | |
| 	{
 | |
| 		$allow_length = array(
 | |
| 			'INT',
 | |
| 			'VARCHAR',
 | |
| 			'CHAR',
 | |
| 			'TINYINT',
 | |
| 			'SMALLINT',
 | |
| 			'MEDIUMINT',
 | |
| 			'INTEGER',
 | |
| 			'BIGINT',
 | |
| 			'FLOAT',
 | |
| 			'DOUBLE',
 | |
| 			'DECIMAL',
 | |
| 			'NUMERIC'
 | |
| 		);
 | |
| 
 | |
| 		return (in_array((string) $field_type, $allow_length));
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Updates all the fields related to a table.
 | |
| 	 *
 | |
| 	 * @param   CMSApplication  $app   Application Object
 | |
| 	 * @param   SimpleXMLElement $table Table information.
 | |
| 	 *
 | |
| 	 * @return void
 | |
| 	 */
 | |
| 	private function executeFieldsUpdating($app, $table)
 | |
| 	{
 | |
| 		if (isset($table->field))
 | |
| 		{
 | |
| 			foreach ($table->children() as $field)
 | |
| 			{
 | |
| 				$table_name = (string) $table['table_name'];
 | |
| 
 | |
| 				$this->processField($app, $table_name, $field);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Process a certain field.
 | |
| 	 *
 | |
| 	 * @param   CMSApplication  $app        Application object
 | |
| 	 * @param   string           $table_name The name of the table that contains the field.
 | |
| 	 * @param   SimpleXMLElement $field      Field Information.
 | |
| 	 *
 | |
| 	 * @return void
 | |
| 	 */
 | |
| 	private function processField($app, $table_name, $field)
 | |
| 	{
 | |
| 		$db = Factory::getContainer()->get('DatabaseDriver');
 | |
| 
 | |
| 		if (isset($field['action']))
 | |
| 		{
 | |
| 			switch ($field['action'])
 | |
| 			{
 | |
| 				case 'add':
 | |
| 					$result = $this->addField($table_name, $field);
 | |
| 
 | |
| 					if ($result === MODIFIED)
 | |
| 					{
 | |
| 						$app->enqueueMessage(
 | |
| 							Text::sprintf('Field `%s` has been successfully added', $field['field_name'])
 | |
| 						);
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						if ($result !== NOT_MODIFIED)
 | |
| 						{
 | |
| 							$app->enqueueMessage(
 | |
| 								Text::sprintf(
 | |
| 									'There was an error adding the field `%s`. Error: %s',
 | |
| 									$field['field_name'], $result
 | |
| 								), 'error'
 | |
| 							);
 | |
| 						}
 | |
| 					}
 | |
| 					break;
 | |
| 				case 'change':
 | |
| 
 | |
| 					if (isset($field['old_name']) && isset($field['new_name']))
 | |
| 					{
 | |
| 						if ($this->existsField($table_name, $field['old_name']) && !$this->existsField($table_name, $field['new_name']))
 | |
| 						{
 | |
| 							$renaming_statement = Text::sprintf(
 | |
| 								'ALTER TABLE %s CHANGE %s %s %s',
 | |
| 								$table_name, $db->quoteName($field['old_name']->__toString()),
 | |
| 								$db->quoteName($field['new_name']->__toString()),
 | |
| 								$this->getFieldType($field)
 | |
| 							);
 | |
| 							$db->setQuery($renaming_statement);
 | |
| 
 | |
| 							try
 | |
| 							{
 | |
| 								$db->execute();
 | |
| 								$app->enqueueMessage(
 | |
| 									Text::sprintf('Field `%s` has been successfully modified', $field['old_name'])
 | |
| 								);
 | |
| 							} catch (Exception $ex)
 | |
| 							{
 | |
| 								$app->enqueueMessage(
 | |
| 									Text::sprintf(
 | |
| 										'There was an error modifying the field `%s`. Error: %s',
 | |
| 										$field['field_name'],
 | |
| 										$ex->getMessage()
 | |
| 									), 'error'
 | |
| 								);
 | |
| 							}
 | |
| 						}
 | |
| 						else
 | |
| 						{
 | |
| 							$result = $this->addField($table_name, $field);
 | |
| 
 | |
| 							if ($result === MODIFIED)
 | |
| 							{
 | |
| 								$app->enqueueMessage(
 | |
| 									Text::sprintf('Field `%s` has been successfully modified', $field['field_name'])
 | |
| 								);
 | |
| 							}
 | |
| 							else
 | |
| 							{
 | |
| 								if ($result !== NOT_MODIFIED)
 | |
| 								{
 | |
| 									$app->enqueueMessage(
 | |
| 										Text::sprintf(
 | |
| 											'There was an error modifying the field `%s`. Error: %s',
 | |
| 											$field['field_name'], $result
 | |
| 										), 'error'
 | |
| 									);
 | |
| 								}
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						$result = $this->addField($table_name, $field);
 | |
| 
 | |
| 						if ($result === MODIFIED)
 | |
| 						{
 | |
| 							$app->enqueueMessage(
 | |
| 								Text::sprintf('Field `%s` has been successfully modified', $field['field_name'])
 | |
| 							);
 | |
| 						}
 | |
| 						else
 | |
| 						{
 | |
| 							if ($result !== NOT_MODIFIED)
 | |
| 							{
 | |
| 								$app->enqueueMessage(
 | |
| 									Text::sprintf(
 | |
| 										'There was an error modifying the field `%s`. Error: %s',
 | |
| 										$field['field_name'], $result
 | |
| 									), 'error'
 | |
| 								);
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 
 | |
| 					break;
 | |
| 				case 'remove':
 | |
| 
 | |
| 					// Check if the field exists first to prevent issue removing the field
 | |
| 					if ($this->existsField($table_name, $field['field_name']))
 | |
| 					{
 | |
| 						$drop_statement = Text::sprintf(
 | |
| 							'ALTER TABLE `%s` DROP COLUMN `%s`',
 | |
| 							$table_name, $field['field_name']
 | |
| 						);
 | |
| 						$db->setQuery($drop_statement);
 | |
| 
 | |
| 						try
 | |
| 						{
 | |
| 							$db->execute();
 | |
| 							$app->enqueueMessage(
 | |
| 								Text::sprintf('Field `%s` has been successfully deleted', $field['field_name'])
 | |
| 							);
 | |
| 						} catch (Exception $ex)
 | |
| 						{
 | |
| 							$app->enqueueMessage(
 | |
| 								Text::sprintf(
 | |
| 									'There was an error deleting the field `%s`. Error: %s',
 | |
| 									$field['field_name'],
 | |
| 									$ex->getMessage()
 | |
| 								), 'error'
 | |
| 							);
 | |
| 						}
 | |
| 					}
 | |
| 
 | |
| 					break;
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$result = $this->addField($table_name, $field);
 | |
| 
 | |
| 			if ($result === MODIFIED)
 | |
| 			{
 | |
| 				$app->enqueueMessage(
 | |
| 					Text::sprintf('Field `%s` has been successfully added', $field['field_name'])
 | |
| 				);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				if ($result !== NOT_MODIFIED)
 | |
| 				{
 | |
| 					$app->enqueueMessage(
 | |
| 						Text::sprintf(
 | |
| 							'There was an error adding the field `%s`. Error: %s',
 | |
| 							$field['field_name'], $result
 | |
| 						), 'error'
 | |
| 					);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Add a field if it does not exists or modify it if it does.
 | |
| 	 *
 | |
| 	 * @param   string           $table_name Table name
 | |
| 	 * @param   SimpleXMLElement $field      Field Information
 | |
| 	 *
 | |
| 	 * @return mixed Constant on success(self::$MODIFIED | self::$NOT_MODIFIED), error message if an error occurred
 | |
| 	 */
 | |
| 	private function addField($table_name, $field)
 | |
| 	{
 | |
| 		$db = Factory::getContainer()->get('DatabaseDriver');
 | |
| 
 | |
| 		$query_generated = false;
 | |
| 
 | |
| 		// Check if the field exists first to prevent issues adding the field
 | |
| 		if ($this->existsField($table_name, $field['field_name']))
 | |
| 		{
 | |
| 			if ($this->needsToUpdate($table_name, $field))
 | |
| 			{
 | |
| 				$change_statement = $this->generateChangeFieldStatement($table_name, $field);
 | |
| 				$db->setQuery($change_statement);
 | |
| 				$query_generated = true;
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$add_statement = $this->generateAddFieldStatement($table_name, $field);
 | |
| 			$db->setQuery($add_statement);
 | |
| 			$query_generated = true;
 | |
| 		}
 | |
| 
 | |
| 		if ($query_generated)
 | |
| 		{
 | |
| 			try
 | |
| 			{
 | |
| 				$db->execute();
 | |
| 
 | |
| 				return MODIFIED;
 | |
| 			} catch (Exception $ex)
 | |
| 			{
 | |
| 				return $ex->getMessage();
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return NOT_MODIFIED;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Checks if a field exists on a table
 | |
| 	 *
 | |
| 	 * @param   string $table_name Table name
 | |
| 	 * @param   string $field_name Field name
 | |
| 	 *
 | |
| 	 * @return boolean True if exists, false if it do
 | |
| 	 */
 | |
| 	private function existsField($table_name, $field_name)
 | |
| 	{
 | |
| 		$db = Factory::getContainer()->get('DatabaseDriver');
 | |
| 
 | |
| 		return in_array((string) $field_name, array_keys($db->getTableColumns($table_name)));
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Check if a field needs to be updated.
 | |
| 	 *
 | |
| 	 * @param   string           $table_name Table name
 | |
| 	 * @param   SimpleXMLElement $field      Field information
 | |
| 	 *
 | |
| 	 * @return boolean True if the field has to be updated, false otherwise
 | |
| 	 */
 | |
| 	private function needsToUpdate($table_name, $field)
 | |
| 	{
 | |
| 
 | |
| 		if(!isset($field['action']) || $field['field_name'] == 'id')
 | |
| 		{
 | |
| 			return false;
 | |
| 		}
 | |
| 		
 | |
| 		$db = Factory::getContainer()->get('DatabaseDriver');
 | |
| 
 | |
| 		$query = Text::sprintf(
 | |
| 			'SHOW FULL COLUMNS FROM `%s` WHERE Field LIKE %s', $table_name, $db->quote((string) $field['field_name'])
 | |
| 		);
 | |
| 		$db->setQuery($query);
 | |
| 
 | |
| 		$field_info = $db->loadObject();
 | |
| 
 | |
| 		if (strcasecmp($field_info->Type, $this->getFieldType($field)) !=0)
 | |
| 		{
 | |
| 			return true;
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			return false;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Generates an change column statement
 | |
| 	 *
 | |
| 	 * @param   string           $table_name Table name
 | |
| 	 * @param   SimpleXMLElement $field      Field Information
 | |
| 	 *
 | |
| 	 * @return string Change column statement
 | |
| 	 */
 | |
| 	private function generateChangeFieldStatement($table_name, $field)
 | |
| 	{
 | |
| 		$column_declaration = $this->generateColumnDeclaration($field);
 | |
| 
 | |
| 		return Text::sprintf('ALTER TABLE %s MODIFY %s', $table_name, $column_declaration);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Generates an add column statement
 | |
| 	 *
 | |
| 	 * @param   string           $table_name Table name
 | |
| 	 * @param   SimpleXMLElement $field      Field Information
 | |
| 	 *
 | |
| 	 * @return string Add column statement
 | |
| 	 */
 | |
| 	private function generateAddFieldStatement($table_name, $field)
 | |
| 	{
 | |
| 		$column_declaration = $this->generateColumnDeclaration($field);
 | |
| 
 | |
| 		return Text::sprintf('ALTER TABLE %s ADD %s', $table_name, $column_declaration);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Installs plugins for this component
 | |
| 	 *
 | |
| 	 * @param   mixed $parent Object who called the install/update method
 | |
| 	 *
 | |
| 	 * @return void
 | |
| 	 */
 | |
| 	private function installPlugins($parent)
 | |
| 	{
 | |
| 		$installation_folder = $parent->getParent()->getPath('source');
 | |
| 		$app                 = Factory::getApplication();
 | |
| 
 | |
| 		/* @var $plugins SimpleXMLElement */
 | |
| 		if (method_exists($parent, 'getManifest'))
 | |
| 		{
 | |
| 			$plugins = $parent->getManifest()->plugins;
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$plugins = $parent->get('manifest')->plugins;
 | |
| 		}
 | |
| 
 | |
| 		if (count($plugins->children()))
 | |
| 		{
 | |
| 			$db    = Factory::getContainer()->get('DatabaseDriver');
 | |
| 			$query = $db->getQuery(true);
 | |
| 
 | |
| 			foreach ($plugins->children() as $plugin)
 | |
| 			{
 | |
| 				$pluginName  = (string) $plugin['plugin'];
 | |
| 				$pluginGroup = (string) $plugin['group'];
 | |
| 				$path        = $installation_folder . '/plugins/' . $pluginGroup . '/' . $pluginName;
 | |
| 				$installer   = new Installer;
 | |
| 
 | |
| 				if (!$this->isAlreadyInstalled('plugin', $pluginName, $pluginGroup))
 | |
| 				{
 | |
| 					$result = $installer->install($path);
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					$result = $installer->update($path);
 | |
| 				}
 | |
| 
 | |
| 				if ($result)
 | |
| 				{
 | |
| 					$app->enqueueMessage('Plugin ' . $pluginName . ' was installed successfully');
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					$app->enqueueMessage('There was an issue installing the plugin ' . $pluginName,
 | |
| 						'error');
 | |
| 				}
 | |
| 
 | |
| 				$query
 | |
| 					->clear()
 | |
| 					->update('#__extensions')
 | |
| 					->set('enabled = 1')
 | |
| 					->where(
 | |
| 						array(
 | |
| 							'type LIKE ' . $db->quote('plugin'),
 | |
| 							'element LIKE ' . $db->quote($pluginName),
 | |
| 							'folder LIKE ' . $db->quote($pluginGroup)
 | |
| 						)
 | |
| 					);
 | |
| 				$db->setQuery($query);
 | |
| 				$db->execute();
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Check if an extension is already installed in the system
 | |
| 	 *
 | |
| 	 * @param   string $type   Extension type
 | |
| 	 * @param   string $name   Extension name
 | |
| 	 * @param   mixed  $folder Extension folder(for plugins)
 | |
| 	 *
 | |
| 	 * @return boolean
 | |
| 	 */
 | |
| 	private function isAlreadyInstalled($type, $name, $folder = null)
 | |
| 	{
 | |
| 		$result = false;
 | |
| 
 | |
| 		switch ($type)
 | |
| 		{
 | |
| 			case 'plugin':
 | |
| 				$result = file_exists(JPATH_PLUGINS . '/' . $folder . '/' . $name);
 | |
| 				break;
 | |
| 			case 'module':
 | |
| 				$result = file_exists(JPATH_SITE . '/modules/' . $name);
 | |
| 				break;
 | |
| 		}
 | |
| 
 | |
| 		return $result;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Installs plugins for this component
 | |
| 	 *
 | |
| 	 * @param   mixed $parent Object who called the install/update method
 | |
| 	 *
 | |
| 	 * @return void
 | |
| 	 */
 | |
| 	private function installModules($parent)
 | |
| 	{
 | |
| 		$installation_folder = $parent->getParent()->getPath('source');
 | |
| 		$app                 = Factory::getApplication();
 | |
| 
 | |
| 		if (method_exists($parent, 'getManifest'))
 | |
| 		{
 | |
| 			$modules = $parent->getManifest()->modules;
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$modules = $parent->get('manifest')->modules;
 | |
| 		}
 | |
| 
 | |
| 		if (!empty($modules))
 | |
| 		{
 | |
| 
 | |
| 			if (count($modules->children()))
 | |
| 			{
 | |
| 				foreach ($modules->children() as $module)
 | |
| 				{
 | |
| 					$moduleName = (string) $module['module'];
 | |
| 					$path       = $installation_folder . '/modules/' . $moduleName;
 | |
| 					$installer  = new Installer;
 | |
| 
 | |
| 					if (!$this->isAlreadyInstalled('module', $moduleName))
 | |
| 					{
 | |
| 						$result = $installer->install($path);
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						$result = $installer->update($path);
 | |
| 					}
 | |
| 
 | |
| 					if ($result)
 | |
| 					{
 | |
| 						$app->enqueueMessage('Module ' . $moduleName . ' was installed successfully');
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						$app->enqueueMessage('There was an issue installing the module ' . $moduleName,
 | |
| 							'error');
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Method to update the component
 | |
| 	 *
 | |
| 	 * @param   mixed $parent Object who called this method.
 | |
| 	 *
 | |
| 	 * @return void
 | |
| 	 */
 | |
| 	public function update($parent)
 | |
| 	{
 | |
| 		$this->installDb($parent);
 | |
| 		$this->installPlugins($parent);
 | |
| 		$this->installModules($parent);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Method to uninstall the component
 | |
| 	 *
 | |
| 	 * @param   mixed $parent Object who called this method.
 | |
| 	 *
 | |
| 	 * @return void
 | |
| 	 */
 | |
| 	public function uninstall($parent)
 | |
| 	{
 | |
| 		$this->uninstallPlugins($parent);
 | |
| 		$this->uninstallModules($parent);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Uninstalls plugins
 | |
| 	 *
 | |
| 	 * @param   mixed $parent Object who called the uninstall method
 | |
| 	 *
 | |
| 	 * @return void
 | |
| 	 */
 | |
| 	private function uninstallPlugins($parent)
 | |
| 	{
 | |
| 		$app     = Factory::getApplication();
 | |
| 
 | |
| 		if (method_exists($parent, 'getManifest'))
 | |
| 		{
 | |
| 			$plugins = $parent->getManifest()->plugins;
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$plugins = $parent->get('manifest')->plugins;
 | |
| 		}
 | |
| 
 | |
| 		if (count($plugins->children()))
 | |
| 		{
 | |
| 			$db    = Factory::getContainer()->get('DatabaseDriver');
 | |
| 			$query = $db->getQuery(true);
 | |
| 
 | |
| 			foreach ($plugins->children() as $plugin)
 | |
| 			{
 | |
| 				$pluginName  = (string) $plugin['plugin'];
 | |
| 				$pluginGroup = (string) $plugin['group'];
 | |
| 				$query
 | |
| 					->clear()
 | |
| 					->select('extension_id')
 | |
| 					->from('#__extensions')
 | |
| 					->where(
 | |
| 						array(
 | |
| 							'type LIKE ' . $db->quote('plugin'),
 | |
| 							'element LIKE ' . $db->quote($pluginName),
 | |
| 							'folder LIKE ' . $db->quote($pluginGroup)
 | |
| 						)
 | |
| 					);
 | |
| 				$db->setQuery($query);
 | |
| 				$extension = $db->loadResult();
 | |
| 
 | |
| 				if (!empty($extension))
 | |
| 				{
 | |
| 					$installer = new Installer;
 | |
| 					$result    = $installer->uninstall('plugin', $extension);
 | |
| 
 | |
| 					if ($result)
 | |
| 					{
 | |
| 						$app->enqueueMessage('Plugin ' . $pluginName . ' was uninstalled successfully');
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						$app->enqueueMessage('There was an issue uninstalling the plugin ' . $pluginName,
 | |
| 							'error');
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Uninstalls plugins
 | |
| 	 *
 | |
| 	 * @param   mixed $parent Object who called the uninstall method
 | |
| 	 *
 | |
| 	 * @return void
 | |
| 	 */
 | |
| 	private function uninstallModules($parent)
 | |
| 	{
 | |
| 		$app = Factory::getApplication();
 | |
| 
 | |
| 		if (method_exists($parent, 'getManifest'))
 | |
| 		{
 | |
| 			$modules = $parent->getManifest()->modules;
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$modules = $parent->get('manifest')->modules;
 | |
| 		}
 | |
| 
 | |
| 		if (!empty($modules))
 | |
| 		{
 | |
| 
 | |
| 			if (count($modules->children()))
 | |
| 			{
 | |
| 				$db    = Factory::getContainer()->get('DatabaseDriver');
 | |
| 				$query = $db->getQuery(true);
 | |
| 
 | |
| 				foreach ($modules->children() as $plugin)
 | |
| 				{
 | |
| 					$moduleName = (string) $plugin['module'];
 | |
| 					$query
 | |
| 						->clear()
 | |
| 						->select('extension_id')
 | |
| 						->from('#__extensions')
 | |
| 						->where(
 | |
| 							array(
 | |
| 								'type LIKE ' . $db->quote('module'),
 | |
| 								'element LIKE ' . $db->quote($moduleName)
 | |
| 							)
 | |
| 						);
 | |
| 					$db->setQuery($query);
 | |
| 					$extension = $db->loadResult();
 | |
| 
 | |
| 					if (!empty($extension))
 | |
| 					{
 | |
| 						$installer = new Installer;
 | |
| 						$result    = $installer->uninstall('module', $extension);
 | |
| 
 | |
| 						if ($result)
 | |
| 						{
 | |
| 							$app->enqueueMessage('Module ' . $moduleName . ' was uninstalled successfully');
 | |
| 						}
 | |
| 						else
 | |
| 						{
 | |
| 							$app->enqueueMessage('There was an issue uninstalling the module ' . $moduleName,
 | |
| 								'error');
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @param   string $type   type
 | |
| 	 * @param   string $parent parent
 | |
| 	 *
 | |
| 	 * @return boolean
 | |
| 	 * @since Kunena
 | |
| 	 */
 | |
| 	public function postflight($type, $parent)
 | |
| 	{
 | |
| 		
 | |
| 
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	
 | |
| }
 |