FOF30\Database\Installer::updateSchema PHP Method

updateSchema() public method

Creates or updates the database schema
public updateSchema ( ) : void
return void
    public function updateSchema()
    {
        // Get the schema XML file
        $xml = $this->findSchemaXml();
        if (empty($xml)) {
            return;
        }
        // Make sure there are SQL commands in this file
        if (!$xml->sql) {
            return;
        }
        // Walk the sql > action tags to find all tables
        /** @var SimpleXMLElement $actions */
        $actions = $xml->sql->children();
        /**
         * The meta/autocollation node defines if I should automatically apply the correct collation (utf8 or utf8mb4)
         * to the database tables managed by the schema updater. When enabled (default) the queries are automatically
         * converted to the correct collation (utf8mb4_unicode_ci or utf8_general_ci) depending on whether your Joomla!
         * and MySQL server support Multibyte UTF-8 (UTF8MB4). Moreover, if UTF8MB4 is supported, all CREATE TABLE
         * queries are analyzed and the tables referenced in them are auto-converted to the proper utf8mb4 collation.
         */
        $autoCollationConversion = true;
        if ($xml->meta->autocollation) {
            $value = (string) $xml->meta->autocollation;
            $value = trim($value);
            $value = strtolower($value);
            $autoCollationConversion = in_array($value, array('true', '1', 'on', 'yes'));
        }
        $hasUtf8mb4Support = method_exists($this->db, 'hasUTF8mb4Support') && $this->db->hasUTF8mb4Support();
        $tablesToConvert = array();
        // If we have an uppercase db prefix we can expect CREATE TABLE fail because we cannot detect reliably
        // the existence of database tables. See https://github.com/joomla/joomla-cms/issues/10928#issuecomment-228549658
        $prefix = $this->db->getPrefix();
        $canFailCreateTable = preg_match('/[A-Z]/', $prefix);
        /** @var SimpleXMLElement $action */
        foreach ($actions as $action) {
            // Get the attributes
            $attributes = $action->attributes();
            // Get the table / view name
            $table = $attributes->table ? (string) $attributes->table : '';
            if (empty($table)) {
                continue;
            }
            // Am I allowed to let this action fail?
            $canFailAction = $attributes->canfail ? $attributes->canfail : 0;
            // Evaluate conditions
            $shouldExecute = true;
            /** @var SimpleXMLElement $node */
            foreach ($action->children() as $node) {
                if ($node->getName() == 'condition') {
                    // Get the operator
                    $operator = $node->attributes()->operator ? (string) $node->attributes()->operator : 'and';
                    $operator = empty($operator) ? 'and' : $operator;
                    $condition = $this->conditionMet($table, $node);
                    switch ($operator) {
                        case 'not':
                            $shouldExecute = $shouldExecute && !$condition;
                            break;
                        case 'or':
                            $shouldExecute = $shouldExecute || $condition;
                            break;
                        case 'nor':
                            $shouldExecute = !$shouldExecute && !$condition;
                            break;
                        case 'xor':
                            $shouldExecute = ($shouldExecute xor $condition);
                            break;
                        case 'maybe':
                            $shouldExecute = $condition ? true : $shouldExecute;
                            break;
                        default:
                            $shouldExecute = $shouldExecute && $condition;
                            break;
                    }
                }
                // DO NOT USE BOOLEAN SHORT CIRCUIT EVALUATION!
                // if (!$shouldExecute) break;
            }
            // Do I have to only collect the tables from CREATE TABLE queries?
            $onlyCollectTables = !$shouldExecute && $autoCollationConversion && $hasUtf8mb4Support;
            // Make sure all conditions are met OR I have to collect tables from CREATE TABLE queries.
            if (!$shouldExecute && !$onlyCollectTables) {
                continue;
            }
            // Execute queries
            foreach ($action->children() as $node) {
                if ($node->getName() == 'query') {
                    $query = (string) $node;
                    if ($autoCollationConversion && $hasUtf8mb4Support) {
                        $this->extractTablesToConvert($query, $tablesToConvert);
                    }
                    // If we're only collecting tables do not run the queries
                    if ($onlyCollectTables) {
                        continue;
                    }
                    $canFail = $node->attributes->canfail ? (string) $node->attributes->canfail : $canFailAction;
                    if (is_string($canFail)) {
                        $canFail = strtoupper($canFail);
                    }
                    $canFail = in_array($canFail, array(true, 1, 'YES', 'TRUE'));
                    // Do I need to automatically convert the collation of all CREATE / ALTER queries?
                    if ($autoCollationConversion) {
                        if ($hasUtf8mb4Support) {
                            // We have UTF8MB4 support. Convert all queries to UTF8MB4.
                            $query = $this->convertUtf8QueryToUtf8mb4($query);
                        } else {
                            // We do not have UTF8MB4 support. Convert all queries to plain old UTF8.
                            $query = $this->convertUtf8mb4QueryToUtf8($query);
                        }
                    }
                    $this->db->setQuery($query);
                    try {
                        $this->db->execute();
                    } catch (Exception $e) {
                        // Special consideration for CREATE TABLE commands on uppercase prefix databases.
                        if ($canFailCreateTable && stripos($query, 'CREATE TABLE') !== false) {
                            $canFail = true;
                        }
                        // If we are not allowed to fail, throw back the exception we caught
                        if (!$canFail) {
                            throw $e;
                        }
                    }
                }
            }
        }
        // Auto-convert the collation of tables if we are told to do so, have utf8mb4 support and a list of tables.
        if ($autoCollationConversion && $hasUtf8mb4Support && !empty($tablesToConvert)) {
            $this->convertTablesToUtf8mb4($tablesToConvert);
        }
    }

Usage Example

Esempio n. 1
0
 /**
  * Make sure the #__akeeba_common table exists or create it from scratch
  *
  * @return  $this
  */
 public function checkAndFixCommonTables()
 {
     $db = $this->container->db;
     $dbInstaller = new Installer($db, JPATH_ADMINISTRATOR . '/components/com_ars/sql/common');
     $dbInstaller->updateSchema();
     return $this;
 }
All Usage Examples Of FOF30\Database\Installer::updateSchema