/** * Look for table definition modifications and apply to real table * * @param $tableName * @param $definition * * @throws \Phalcon\Db\Exception */ public function morphTable($tableName, $definition) { $defaultSchema = Utils::resolveDbSchema(self::$_databaseConfig); $tableExists = self::$_connection->tableExists($tableName, $defaultSchema); if (isset($definition['columns'])) { if (count($definition['columns']) == 0) { throw new DbException('Table must have at least one column'); } $fields = []; foreach ($definition['columns'] as $tableColumn) { if (!is_object($tableColumn)) { throw new DbException('Table must have at least one column'); } /** * @var \Phalcon\Db\ColumnInterface $tableColumn * @var \Phalcon\Db\ColumnInterface[] $fields */ $fields[$tableColumn->getName()] = $tableColumn; } if ($tableExists == true) { $localFields = []; /** * @var \Phalcon\Db\ColumnInterface[] $description * @var \Phalcon\Db\ColumnInterface[] $localFields */ $description = self::$_connection->describeColumns($tableName, $defaultSchema); foreach ($description as $field) { $localFields[$field->getName()] = $field; } foreach ($fields as $fieldName => $tableColumn) { /** * @var \Phalcon\Db\ColumnInterface $tableColumn * @var \Phalcon\Db\ColumnInterface[] $localFields */ if (!isset($localFields[$fieldName])) { self::$_connection->addColumn($tableName, $tableColumn->getSchemaName(), $tableColumn); } else { $changed = false; if ($localFields[$fieldName]->getType() != $tableColumn->getType()) { $changed = true; } if ($localFields[$fieldName]->getSize() != $tableColumn->getSize()) { $changed = true; } if ($tableColumn->isNotNull() != $localFields[$fieldName]->isNotNull()) { $changed = true; } if ($tableColumn->getDefault() != $localFields[$fieldName]->getDefault()) { $changed = true; } if ($changed == true) { self::$_connection->modifyColumn($tableName, $tableColumn->getSchemaName(), $tableColumn, $tableColumn); } } } foreach ($localFields as $fieldName => $localField) { if (!isset($fields[$fieldName])) { self::$_connection->dropColumn($tableName, null, $fieldName); } } } else { self::$_connection->createTable($tableName, $defaultSchema, $definition); if (method_exists($this, 'afterCreateTable')) { $this->afterCreateTable(); } } } if (isset($definition['references'])) { if ($tableExists == true) { $references = []; foreach ($definition['references'] as $tableReference) { $references[$tableReference->getName()] = $tableReference; } $localReferences = []; $activeReferences = self::$_connection->describeReferences($tableName, $defaultSchema); foreach ($activeReferences as $activeReference) { $localReferences[$activeReference->getName()] = ['referencedTable' => $activeReference->getReferencedTable(), 'columns' => $activeReference->getColumns(), 'referencedColumns' => $activeReference->getReferencedColumns()]; } foreach ($definition['references'] as $tableReference) { if (!isset($localReferences[$tableReference->getName()])) { self::$_connection->addForeignKey($tableName, $tableReference->getSchemaName(), $tableReference); } else { $changed = false; if ($tableReference->getReferencedTable() != $localReferences[$tableReference->getName()]['referencedTable']) { $changed = true; } if ($changed == false) { if (count($tableReference->getColumns()) != count($localReferences[$tableReference->getName()]['columns'])) { $changed = true; } } if ($changed == false) { if (count($tableReference->getReferencedColumns()) != count($localReferences[$tableReference->getName()]['referencedColumns'])) { $changed = true; } } if ($changed == false) { foreach ($tableReference->getColumns() as $columnName) { if (!in_array($columnName, $localReferences[$tableReference->getName()]['columns'])) { $changed = true; break; } } } if ($changed == false) { foreach ($tableReference->getReferencedColumns() as $columnName) { if (!in_array($columnName, $localReferences[$tableReference->getName()]['referencedColumns'])) { $changed = true; break; } } } if ($changed == true) { self::$_connection->dropForeignKey($tableName, $tableReference->getSchemaName(), $tableReference->getName()); self::$_connection->addForeignKey($tableName, $tableReference->getSchemaName(), $tableReference); } } } foreach ($localReferences as $referenceName => $reference) { if (!isset($references[$referenceName])) { self::$_connection->dropForeignKey($tableName, null, $referenceName); } } } } if (isset($definition['indexes'])) { if ($tableExists == true) { $indexes = []; foreach ($definition['indexes'] as $tableIndex) { $indexes[$tableIndex->getName()] = $tableIndex; } $localIndexes = []; $actualIndexes = self::$_connection->describeIndexes($tableName, $defaultSchema); foreach ($actualIndexes as $actualIndex) { $localIndexes[$actualIndex->getName()] = $actualIndex->getColumns(); } foreach ($definition['indexes'] as $tableIndex) { if (!isset($localIndexes[$tableIndex->getName()])) { if ($tableIndex->getName() == 'PRIMARY') { self::$_connection->addPrimaryKey($tableName, $tableColumn->getSchemaName(), $tableIndex); } else { self::$_connection->addIndex($tableName, $tableColumn->getSchemaName(), $tableIndex); } } else { $changed = false; if (count($tableIndex->getColumns()) != count($localIndexes[$tableIndex->getName()])) { $changed = true; } else { foreach ($tableIndex->getColumns() as $columnName) { if (!in_array($columnName, $localIndexes[$tableIndex->getName()])) { $changed = true; break; } } } if ($changed == true) { if ($tableIndex->getName() == 'PRIMARY') { self::$_connection->dropPrimaryKey($tableName, $tableColumn->getSchemaName()); self::$_connection->addPrimaryKey($tableName, $tableColumn->getSchemaName(), $tableIndex); } else { self::$_connection->dropIndex($tableName, $tableColumn->getSchemaName(), $tableIndex->getName()); self::$_connection->addIndex($tableName, $tableColumn->getSchemaName(), $tableIndex); } } } } foreach ($localIndexes as $indexName => $indexColumns) { if (!isset($indexes[$indexName])) { self::$_connection->dropIndex($tableName, null, $indexName); } } } } }