123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- <?php
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- namespace Magento\Framework\Setup\Declaration\Schema\Db;
- use Magento\Framework\Phrase;
- use Magento\Framework\Setup\Declaration\Schema\Dto\Column;
- use Magento\Framework\Setup\Declaration\Schema\Dto\ElementFactory;
- use Magento\Framework\Setup\Declaration\Schema\Dto\Schema;
- use Magento\Framework\Setup\Declaration\Schema\Dto\Table;
- use Magento\Framework\Setup\Declaration\Schema\Sharding;
- use Magento\Framework\Setup\Exception;
- /**
- * This type of builder is responsible for converting ENTIRE data, that comes from db
- * into DTO`s format, with aggregation root: Schema.
- *
- * Note: SchemaBuilder can not be used for one structural element, like column or constraint
- * because it should have references to other DTO objects.
- * In order to convert build only 1 structural element use directly it factory.
- *
- * @see Schema
- * @inheritdoc
- */
- class SchemaBuilder
- {
- /**
- * @var ElementFactory
- */
- private $elementFactory;
- /**
- * @var DbSchemaReaderInterface
- */
- private $dbSchemaReader;
- /**
- * @var Sharding
- */
- private $sharding;
- /**
- * @var array
- */
- private $tables;
- /**
- * Constructor.
- *
- * @param ElementFactory $elementFactory
- * @param DbSchemaReaderInterface $dbSchemaReader
- * @param Sharding $sharding
- */
- public function __construct(
- ElementFactory $elementFactory,
- DbSchemaReaderInterface $dbSchemaReader,
- Sharding $sharding
- ) {
- $this->elementFactory = $elementFactory;
- $this->dbSchemaReader = $dbSchemaReader;
- $this->sharding = $sharding;
- }
- /**
- * @inheritdoc
- */
- public function build(Schema $schema)
- {
- foreach ($this->sharding->getResources() as $resource) {
- foreach ($this->dbSchemaReader->readTables($resource) as $tableName) {
- $columns = [];
- $indexes = [];
- $constraints = [];
- $tableOptions = $this->dbSchemaReader->getTableOptions($tableName, $resource);
- $columnsData = $this->dbSchemaReader->readColumns($tableName, $resource);
- $indexesData = $this->dbSchemaReader->readIndexes($tableName, $resource);
- $constrainsData = $this->dbSchemaReader->readConstraints($tableName, $resource);
- /**
- * @var Table $table
- */
- $table = $this->elementFactory->create(
- 'table',
- [
- 'name' => $tableName,
- 'resource' => $resource,
- 'engine' => strtolower($tableOptions['engine']),
- 'comment' => $tableOptions['comment'] === '' ? null : $tableOptions['comment'],
- 'charset' => $tableOptions['charset'],
- 'collation' => $tableOptions['collation']
- ]
- );
- // Process columns
- foreach ($columnsData as $columnData) {
- $columnData['table'] = $table;
- $column = $this->elementFactory->create($columnData['type'], $columnData);
- $columns[$column->getName()] = $column;
- }
- $table->addColumns($columns);
- //Process indexes
- foreach ($indexesData as $indexData) {
- $indexData['table'] = $table;
- $indexData['columns'] = $this->resolveInternalRelations($columns, $indexData);
- $index = $this->elementFactory->create('index', $indexData);
- $indexes[$index->getName()] = $index;
- }
- //Process internal constraints
- foreach ($constrainsData as $constraintData) {
- $constraintData['table'] = $table;
- $constraintData['columns'] = $this->resolveInternalRelations($columns, $constraintData);
- $constraint = $this->elementFactory->create($constraintData['type'], $constraintData);
- $constraints[$constraint->getName()] = $constraint;
- }
- $table->addIndexes($indexes);
- $table->addConstraints($constraints);
- $this->tables[$table->getName()] = $table;
- }
- }
- $this->processReferenceKeys($this->tables, $schema);
- return $schema;
- }
- /**
- * Process references for all tables. Schema validation required.
- *
- * @param Table[] $tables
- * @param Schema $schema
- */
- private function processReferenceKeys(array $tables, Schema $schema)
- {
- foreach ($tables as $table) {
- $tableName = $table->getName();
- if ($schema->getTableByName($tableName) instanceof Table) {
- continue;
- }
- $referencesData = $this->dbSchemaReader->readReferences($tableName, $table->getResource());
- $references = [];
- foreach ($referencesData as $referenceData) {
- //Prepare reference data
- $referenceData['table'] = $table;
- $referenceTableName = $referenceData['referenceTable'];
- $referenceData['column'] = $table->getColumnByName($referenceData['column']);
- $referenceData['referenceTable'] = $this->tables[$referenceTableName];
- $referenceData['referenceColumn'] = $referenceData['referenceTable']->getColumnByName(
- $referenceData['referenceColumn']
- );
- $references[$referenceData['name']] = $this->elementFactory->create('foreign', $referenceData);
- //We need to instantiate tables in order of references tree
- if (isset($tables[$referenceTableName]) && $referenceTableName !== $tableName) {
- $this->processReferenceKeys([$referenceTableName => $tables[$referenceTableName]], $schema);
- unset($tables[$referenceTableName]);
- }
- }
- $table->addConstraints($references);
- $schema->addTable($table);
- }
- }
- /**
- * Retrieve column objects from names.
- *
- * @param Column[] $columns
- * @param array $data
- * @return Column[]
- * @throws Exception
- */
- private function resolveInternalRelations(array $columns, array $data)
- {
- if (!is_array($data['column'])) {
- throw new Exception(
- new Phrase("Cannot find columns for internal index")
- );
- }
- $referenceColumns = [];
- foreach ($data['column'] as $columnName) {
- if (!isset($columns[$columnName])) {
- $tableName = isset($data['table']) ? $data['table']->getName() : '';
- trigger_error(
- new Phrase(
- 'Column %1 does not exist for index/constraint %2 in table %3.',
- [
- $columnName,
- $data['name'],
- $tableName
- ]
- ),
- E_USER_WARNING
- );
- } else {
- $referenceColumns[] = $columns[$columnName];
- }
- }
- return $referenceColumns;
- }
- }
|