@my wife Roline van der Merwe @copyright Copyright (C) 2015. All Rights Reserved @license GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html Builds Complex Joomla Components /-----------------------------------------------------------------------------------------------------------------------------*/ // No direct access to this file defined('_JEXEC') or die('Restricted access'); use Joomla\CMS\Factory; use VDM\Joomla\Utilities\StringHelper; use VDM\Joomla\Utilities\JsonHelper; use VDM\Joomla\Utilities\GetHelper; use VDM\Joomla\Utilities\ArrayHelper; /** * Mapping class */ class Mapping { /** * Some default fields */ protected $buildcompsql; public $id; public $name_code; public $addadmin_views; public $addSql = array(); public $source = array(); public $sql = array(); /** * The map of the needed fields and views */ public $map; /** * The app to load messages mostly */ public $app; /** * The needed set of keys needed to set */ protected $setting = array('id' => 'default', 'buildcompsql' => 'base64', 'name_code' => 'safeString'); /** * The needed set of keys needed to set */ protected $notRequiered = array('id', 'asset_id', 'published', 'created_by', 'modified_by', 'created', 'modified', 'checked_out','checked_out_time', 'version', 'hits', 'access', 'ordering', 'metakey', 'metadesc', 'metadata', 'params'); /** * The datatypes and it linked field types (basic) * (TODO) We may need to set this dynamicly */ protected $dataTypes = array( 'VARCHAR' => 'Text', 'CHAR' => 'Text', 'MEDIUMTEXT' => 'Textarea', 'LONGTEXT' => 'Textarea', 'TEXT' => 'Textarea', 'DATETIME' => 'Calendar', 'DATE' => 'Text', 'TIME' => 'Text', 'TINYINT' => 'Text', 'BIGINT' => 'Text', 'INT' => 'Text', 'FLOAT' => 'Text', 'DECIMAL' => 'Text', 'DOUBLE' => 'Text'); /** * The datasize identifiers */ protected $dataSize = array( 'CHAR', 'VARCHAR', 'INT', 'TINYINT', 'BIGINT', 'FLOAT', 'DECIMAL', 'DOUBLE'); /** * The default identifiers */ protected $defaults = array(0, 1, "CURRENT_TIMESTAMP", "DATETIME"); // Other /** * The sizes identifiers */ protected $sizes = array("1", "7", "10", "11", "50", "64", "100", "255", "1024", "2048"); // Other /** * Constructor */ public function __construct($data = false) { // set the app to insure messages can be set $this->app = Factory::getApplication(); // check that we have data if (ArrayHelper::check($data)) { // make sure we have an id if (isset($data['id']) && $data['id'] > 0) { if (isset($data['buildcomp']) && 1 == $data['buildcomp'] && isset($data['buildcompsql'])) { foreach ($data as $key => $value) { if (isset($this->setting[$key])) { switch($this->setting[$key]) { case 'base64': // set needed value $this->$key = base64_decode((string) $value); break; case 'json': // set needed value $this->$key = json_decode((string) $value, true); break; case 'safeString': // set needed value $this->$key = StringHelper::check($value); break; default : $this->$key = $value; break; } } } // get linked admin views $addadmin_views = GetHelper::var('component_admin_views', $data['id'], 'joomla_component', 'addadmin_views'); if (JsonHelper::check($addadmin_views)) { $this->addadmin_views = json_decode((string)$addadmin_views, true); } // set the map of the views needed if ($this->setMap()) { return true; } $this->app->enqueueMessage( JText::_('No "CREATE TABLE.." were found, please check your sql.'), 'Error' ); return false; } return false; // not set so just return without any error } $this->app->enqueueMessage( JText::_('Please try again, this error usualy happens if it is a new component, beacues we need a component ID to do this build with your sql dump.'), 'Error' ); return false; } $this->app->enqueueMessage( JText::_('Could not find the data needed to continue.'), 'Error' ); return false; } /** * The mapping function * To Map the views and fields that are needed */ protected function setMap() { // start parsing the sql dump data $queries = JDatabaseDriver::splitSql($this->buildcompsql); if (ArrayHelper::check($queries)) { foreach ($queries as $query) { // only use create table queries if (strpos($query, 'CREATE TABLE IF NOT EXISTS') !== false || strpos($query, 'CREATE TABLE') !== false) { if ($tableName = $this->getTableName($query)) { // now get the fields/columns of this view/table if ($fields = $this->getFields($query)) { // make sure it is all lower case from here on $tableName = strtolower($tableName); $this->map[$tableName] = $fields; } } else { continue; } } // get the insert data if set if (strpos($query, 'INSERT INTO `') !== false) { if ($tableName = $this->getTableName($query)) { $this->addSql[$tableName] = 1; $this->source[$tableName] = 2; $this->sql[$tableName] = $query; } } } // check if the mapping was done if (ArrayHelper::check($this->map)) { return true; } } return false; } /** * Get the table name */ protected function getTableName(&$query) { if (strpos($query, '`#__') !== false) { // get table name $tableName = GetHelper::between($query, '`#__', "`"); } elseif (strpos($query, "'#__") !== false) { // get table name $tableName = GetHelper::between($query, "'#__", "'"); } // if it still was not found if (!isset($tableName) || !ComponentbuilderHelper::checkString($tableName)) { // skip this query return false; } // clean the table name (so only view name remain) if (strpos($tableName, $this->name_code) !== false) { $tableName = trim(str_replace($this->name_code, '', $tableName), '_'); } // if found if (ComponentbuilderHelper::checkString($tableName)) { return $tableName; } // skip this query return false; } /** * Get the field details */ protected function getFields(&$query) { $rows = array_map('trim', explode(PHP_EOL, $query)); $fields = array(); foreach ($rows as $row) { // make sure we have a lower case string $row = strtoupper($row); $field = array(); $name = ''; if (0 === strpos($row, '`')) { // get field name $name = GetHelper::between($row, '`', '`'); } if (0 === strpos($row, "'")) { // get field name $name = GetHelper::between($row, "'", "'"); } // check if the name was found if (ComponentbuilderHelper::checkString($name)) { // insure we have the name in lower case from here on $name = strtolower($name); // only continue if field is requered if (in_array($name, $this->notRequiered)) { continue; } // check if the field type is found if ($fieldType = $this->getType($row, $field, $name)) { $field['row'] = $row; $field['name'] = $name; $field['label'] = StringHelper::check($name, 'W'); $field['fieldType'] = $fieldType; $field['size'] = $this->getSize($row, $field); $field['sizeOther'] = ''; if (!in_array($field['size'], $this->sizes)) { if (ComponentbuilderHelper::checkString($field['size'])) { $field['sizeOther'] = $field['size']; $field['size'] = 'Other'; } } $field['default'] = $this->getDefault($row); $field['defaultOther'] = ''; if (!in_array($field['default'], $this->defaults)) { if (ComponentbuilderHelper::checkString($field['default'])) { $field['defaultOther'] = $field['default']; $field['default'] = 'Other'; } } $field['null'] = $this->getNullValue($row, $field); // check if field is a key $field['key'] = $this->getKeyStatus($rows, $name); // load to fields $fields[] = $field; } } } if (ArrayHelper::check($fields)) { return $fields; } return false; } /** * Get the field types */ protected function getType($row, &$field, &$name) { // first remove field name $row = str_replace($name, '', $row); // get the data type first foreach ($this->dataTypes as $type => $fieldType) { if (strpos($row, $type) !== false) { $field['dataType'] = $type; return $fieldType; } } return false; } /** * Get the field size */ protected function getSize(&$row, $field) { if (in_array($field['dataType'], $this->dataSize)) { return GetHelper::between($row, $field['dataType'].'(', ')'); } return ''; } /** * Get the field default */ protected function getDefault(&$row) { // get default value if (strpos($row, 'DEFAULT "') !== false) // to sure it this is correct... { return GetHelper::between($row, 'DEFAULT "', '"'); } // get default value if (strpos($row, "DEFAULT '") !== false) { return GetHelper::between($row, "DEFAULT '", "'"); } return ''; } /** * Get the field Null Value */ protected function getNullValue(&$row, &$field) { // get the result of null if (strpos($row, 'NOT NULL') !== false) { return 'NOT NULL'; } if (strpos($row, 'DEFAULT NULL') !== false) { $field['default'] = 'NULL'; return ''; } return 'NULL'; } /** * Get the field key status */ protected function getKeyStatus(&$rows, &$name) { // get the data type first foreach ($rows as $row) { if (strpos($row, 'UNIQUE KEY ') !== false && stripos($row, $name) !== false) { return 1; } if ((strpos($row, 'PRIMARY KEY ') !== false && stripos($row, $name) !== false) || (strpos($row, 'KEY ') !== false && stripos($row, $name) !== false)) { return 2; } } return 0; } }