From bf6655a534a6775d30cafa67bd801276bda1d98d Mon Sep 17 00:00:00 2001 From: polo Date: Tue, 13 Aug 2024 23:45:21 +0200 Subject: =?UTF-8?q?VERSION=200.2=20doctrine=20ORM=20et=20entit=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dbal/src/Schema/AbstractSchemaManager.php | 864 +++++++++++++++++++++ 1 file changed, 864 insertions(+) create mode 100644 vendor/doctrine/dbal/src/Schema/AbstractSchemaManager.php (limited to 'vendor/doctrine/dbal/src/Schema/AbstractSchemaManager.php') diff --git a/vendor/doctrine/dbal/src/Schema/AbstractSchemaManager.php b/vendor/doctrine/dbal/src/Schema/AbstractSchemaManager.php new file mode 100644 index 0000000..9730797 --- /dev/null +++ b/vendor/doctrine/dbal/src/Schema/AbstractSchemaManager.php @@ -0,0 +1,864 @@ + + * + * @throws Exception + */ + public function listDatabases(): array + { + return array_map(function (array $row): string { + return $this->_getPortableDatabaseDefinition($row); + }, $this->connection->fetchAllAssociative( + $this->platform->getListDatabasesSQL(), + )); + } + + /** + * Returns a list of the names of all schemata in the current database. + * + * @return list + * + * @throws Exception + */ + public function listSchemaNames(): array + { + throw NotSupported::new(__METHOD__); + } + + /** + * Lists the available sequences for this connection. + * + * @return array + * + * @throws Exception + */ + public function listSequences(): array + { + return $this->filterAssetNames( + array_map(function (array $row): Sequence { + return $this->_getPortableSequenceDefinition($row); + }, $this->connection->fetchAllAssociative( + $this->platform->getListSequencesSQL( + $this->getDatabase(__METHOD__), + ), + )), + ); + } + + /** + * Lists the columns for a given table. + * + * In contrast to other libraries and to the old version of Doctrine, + * this column definition does try to contain the 'primary' column for + * the reason that it is not portable across different RDBMS. Use + * {@see listTableIndexes($tableName)} to retrieve the primary key + * of a table. Where a RDBMS specifies more details, these are held + * in the platformDetails array. + * + * @return array + * + * @throws Exception + */ + public function listTableColumns(string $table): array + { + $database = $this->getDatabase(__METHOD__); + + return $this->_getPortableTableColumnList( + $table, + $database, + $this->selectTableColumns($database, $this->normalizeName($table)) + ->fetchAllAssociative(), + ); + } + + /** + * Lists the indexes for a given table returning an array of Index instances. + * + * Keys of the portable indexes list are all lower-cased. + * + * @return array + * + * @throws Exception + */ + public function listTableIndexes(string $table): array + { + $database = $this->getDatabase(__METHOD__); + $table = $this->normalizeName($table); + + return $this->_getPortableTableIndexesList( + $this->selectIndexColumns( + $database, + $table, + )->fetchAllAssociative(), + $table, + ); + } + + /** + * Returns true if all the given tables exist. + * + * @param array $names + * + * @throws Exception + */ + public function tablesExist(array $names): bool + { + $names = array_map('strtolower', $names); + + return count($names) === count(array_intersect($names, array_map('strtolower', $this->listTableNames()))); + } + + public function tableExists(string $tableName): bool + { + return $this->tablesExist([$tableName]); + } + + /** + * Returns a list of all tables in the current database. + * + * @return array + * + * @throws Exception + */ + public function listTableNames(): array + { + return $this->filterAssetNames( + array_map(function (array $row): string { + return $this->_getPortableTableDefinition($row); + }, $this->selectTableNames( + $this->getDatabase(__METHOD__), + )->fetchAllAssociative()), + ); + } + + /** + * Filters asset names if they are configured to return only a subset of all + * the found elements. + * + * @param array $assetNames + * + * @return array + */ + private function filterAssetNames(array $assetNames): array + { + $filter = $this->connection->getConfiguration()->getSchemaAssetsFilter(); + + return array_values(array_filter($assetNames, $filter)); + } + + /** + * Lists the tables for this connection. + * + * @return list + * + * @throws Exception + */ + public function listTables(): array + { + $database = $this->getDatabase(__METHOD__); + + $tableColumnsByTable = $this->fetchTableColumnsByTable($database); + $indexColumnsByTable = $this->fetchIndexColumnsByTable($database); + $foreignKeyColumnsByTable = $this->fetchForeignKeyColumnsByTable($database); + $tableOptionsByTable = $this->fetchTableOptionsByTable($database); + + $filter = $this->connection->getConfiguration()->getSchemaAssetsFilter(); + $tables = []; + + foreach ($tableColumnsByTable as $tableName => $tableColumns) { + if (! $filter($tableName)) { + continue; + } + + $tables[] = new Table( + $tableName, + $this->_getPortableTableColumnList($tableName, $database, $tableColumns), + $this->_getPortableTableIndexesList($indexColumnsByTable[$tableName] ?? [], $tableName), + [], + $this->_getPortableTableForeignKeysList($foreignKeyColumnsByTable[$tableName] ?? []), + $tableOptionsByTable[$tableName] ?? [], + ); + } + + return $tables; + } + + /** + * An extension point for those platforms where case sensitivity of the object name depends on whether it's quoted. + * + * Such platforms should convert a possibly quoted name into a value of the corresponding case. + */ + protected function normalizeName(string $name): string + { + $identifier = new Identifier($name); + + return $identifier->getName(); + } + + /** + * Selects names of tables in the specified database. + * + * @throws Exception + */ + abstract protected function selectTableNames(string $databaseName): Result; + + /** + * Selects definitions of table columns in the specified database. If the table name is specified, narrows down + * the selection to this table. + * + * @throws Exception + */ + abstract protected function selectTableColumns(string $databaseName, ?string $tableName = null): Result; + + /** + * Selects definitions of index columns in the specified database. If the table name is specified, narrows down + * the selection to this table. + * + * @throws Exception + */ + abstract protected function selectIndexColumns(string $databaseName, ?string $tableName = null): Result; + + /** + * Selects definitions of foreign key columns in the specified database. If the table name is specified, + * narrows down the selection to this table. + * + * @throws Exception + */ + abstract protected function selectForeignKeyColumns(string $databaseName, ?string $tableName = null): Result; + + /** + * Fetches definitions of table columns in the specified database and returns them grouped by table name. + * + * @return array>> + * + * @throws Exception + */ + protected function fetchTableColumnsByTable(string $databaseName): array + { + return $this->fetchAllAssociativeGrouped($this->selectTableColumns($databaseName)); + } + + /** + * Fetches definitions of index columns in the specified database and returns them grouped by table name. + * + * @return array>> + * + * @throws Exception + */ + protected function fetchIndexColumnsByTable(string $databaseName): array + { + return $this->fetchAllAssociativeGrouped($this->selectIndexColumns($databaseName)); + } + + /** + * Fetches definitions of foreign key columns in the specified database and returns them grouped by table name. + * + * @return array>> + * + * @throws Exception + */ + protected function fetchForeignKeyColumnsByTable(string $databaseName): array + { + return $this->fetchAllAssociativeGrouped( + $this->selectForeignKeyColumns($databaseName), + ); + } + + /** + * Fetches table options for the tables in the specified database and returns them grouped by table name. + * If the table name is specified, narrows down the selection to this table. + * + * @return array> + * + * @throws Exception + */ + abstract protected function fetchTableOptionsByTable(string $databaseName, ?string $tableName = null): array; + + /** + * Introspects the table with the given name. + * + * @throws Exception + */ + public function introspectTable(string $name): Table + { + $columns = $this->listTableColumns($name); + + if ($columns === []) { + throw TableDoesNotExist::new($name); + } + + return new Table( + $name, + $columns, + $this->listTableIndexes($name), + [], + $this->listTableForeignKeys($name), + $this->getTableOptions($name), + ); + } + + /** + * Lists the views this connection has. + * + * @return list + * + * @throws Exception + */ + public function listViews(): array + { + return array_map(function (array $row): View { + return $this->_getPortableViewDefinition($row); + }, $this->connection->fetchAllAssociative( + $this->platform->getListViewsSQL( + $this->getDatabase(__METHOD__), + ), + )); + } + + /** + * Lists the foreign keys for the given table. + * + * @return array + * + * @throws Exception + */ + public function listTableForeignKeys(string $table): array + { + $database = $this->getDatabase(__METHOD__); + + return $this->_getPortableTableForeignKeysList( + $this->selectForeignKeyColumns( + $database, + $this->normalizeName($table), + )->fetchAllAssociative(), + ); + } + + /** + * @return array + * + * @throws Exception + */ + private function getTableOptions(string $name): array + { + $normalizedName = $this->normalizeName($name); + + return $this->fetchTableOptionsByTable( + $this->getDatabase(__METHOD__), + $normalizedName, + )[$normalizedName] ?? []; + } + + /* drop*() Methods */ + + /** + * Drops a database. + * + * NOTE: You can not drop the database this SchemaManager is currently connected to. + * + * @throws Exception + */ + public function dropDatabase(string $database): void + { + $this->connection->executeStatement( + $this->platform->getDropDatabaseSQL($database), + ); + } + + /** + * Drops a schema. + * + * @throws Exception + */ + public function dropSchema(string $schemaName): void + { + $this->connection->executeStatement( + $this->platform->getDropSchemaSQL($schemaName), + ); + } + + /** + * Drops the given table. + * + * @throws Exception + */ + public function dropTable(string $name): void + { + $this->connection->executeStatement( + $this->platform->getDropTableSQL($name), + ); + } + + /** + * Drops the index from the given table. + * + * @throws Exception + */ + public function dropIndex(string $index, string $table): void + { + $this->connection->executeStatement( + $this->platform->getDropIndexSQL($index, $table), + ); + } + + /** + * Drops a foreign key from a table. + * + * @throws Exception + */ + public function dropForeignKey(string $name, string $table): void + { + $this->connection->executeStatement( + $this->platform->getDropForeignKeySQL($name, $table), + ); + } + + /** + * Drops a sequence with a given name. + * + * @throws Exception + */ + public function dropSequence(string $name): void + { + $this->connection->executeStatement( + $this->platform->getDropSequenceSQL($name), + ); + } + + /** + * Drops the unique constraint from the given table. + * + * @throws Exception + */ + public function dropUniqueConstraint(string $name, string $tableName): void + { + $this->connection->executeStatement( + $this->platform->getDropUniqueConstraintSQL($name, $tableName), + ); + } + + /** + * Drops a view. + * + * @throws Exception + */ + public function dropView(string $name): void + { + $this->connection->executeStatement( + $this->platform->getDropViewSQL($name), + ); + } + + /* create*() Methods */ + + /** @throws Exception */ + public function createSchemaObjects(Schema $schema): void + { + $this->executeStatements($schema->toSql($this->platform)); + } + + /** + * Creates a new database. + * + * @throws Exception + */ + public function createDatabase(string $database): void + { + $this->connection->executeStatement( + $this->platform->getCreateDatabaseSQL($database), + ); + } + + /** + * Creates a new table. + * + * @throws Exception + */ + public function createTable(Table $table): void + { + $this->executeStatements($this->platform->getCreateTableSQL($table)); + } + + /** + * Creates a new sequence. + * + * @throws Exception + */ + public function createSequence(Sequence $sequence): void + { + $this->connection->executeStatement( + $this->platform->getCreateSequenceSQL($sequence), + ); + } + + /** + * Creates a new index on a table. + * + * @param string $table The name of the table on which the index is to be created. + * + * @throws Exception + */ + public function createIndex(Index $index, string $table): void + { + $this->connection->executeStatement( + $this->platform->getCreateIndexSQL($index, $table), + ); + } + + /** + * Creates a new foreign key. + * + * @param ForeignKeyConstraint $foreignKey The ForeignKey instance. + * @param string $table The name of the table on which the foreign key is to be created. + * + * @throws Exception + */ + public function createForeignKey(ForeignKeyConstraint $foreignKey, string $table): void + { + $this->connection->executeStatement( + $this->platform->getCreateForeignKeySQL($foreignKey, $table), + ); + } + + /** + * Creates a unique constraint on a table. + * + * @throws Exception + */ + public function createUniqueConstraint(UniqueConstraint $uniqueConstraint, string $tableName): void + { + $this->connection->executeStatement( + $this->platform->getCreateUniqueConstraintSQL($uniqueConstraint, $tableName), + ); + } + + /** + * Creates a new view. + * + * @throws Exception + */ + public function createView(View $view): void + { + $this->connection->executeStatement( + $this->platform->getCreateViewSQL( + $view->getQuotedName($this->platform), + $view->getSql(), + ), + ); + } + + /** @throws Exception */ + public function dropSchemaObjects(Schema $schema): void + { + $this->executeStatements($schema->toDropSql($this->platform)); + } + + /** + * Alters an existing schema. + * + * @throws Exception + */ + public function alterSchema(SchemaDiff $schemaDiff): void + { + $this->executeStatements($this->platform->getAlterSchemaSQL($schemaDiff)); + } + + /** + * Migrates an existing schema to a new schema. + * + * @throws Exception + */ + public function migrateSchema(Schema $newSchema): void + { + $schemaDiff = $this->createComparator() + ->compareSchemas($this->introspectSchema(), $newSchema); + + $this->alterSchema($schemaDiff); + } + + /* alterTable() Methods */ + + /** + * Alters an existing tables schema. + * + * @throws Exception + */ + public function alterTable(TableDiff $tableDiff): void + { + $this->executeStatements($this->platform->getAlterTableSQL($tableDiff)); + } + + /** + * Renames a given table to another name. + * + * @throws Exception + */ + public function renameTable(string $name, string $newName): void + { + $this->connection->executeStatement( + $this->platform->getRenameTableSQL($name, $newName), + ); + } + + /** + * Methods for filtering return values of list*() methods to convert + * the native DBMS data definition to a portable Doctrine definition + */ + + /** @param array $database */ + protected function _getPortableDatabaseDefinition(array $database): string + { + throw NotSupported::new(__METHOD__); + } + + /** @param array $sequence */ + protected function _getPortableSequenceDefinition(array $sequence): Sequence + { + throw NotSupported::new(__METHOD__); + } + + /** + * Independent of the database the keys of the column list result are lowercased. + * + * The name of the created column instance however is kept in its case. + * + * @param array> $tableColumns + * + * @return array + * + * @throws Exception + */ + protected function _getPortableTableColumnList(string $table, string $database, array $tableColumns): array + { + $list = []; + foreach ($tableColumns as $tableColumn) { + $column = $this->_getPortableTableColumnDefinition($tableColumn); + + $name = strtolower($column->getQuotedName($this->platform)); + $list[$name] = $column; + } + + return $list; + } + + /** + * Gets Table Column Definition. + * + * @param array $tableColumn + * + * @throws Exception + */ + abstract protected function _getPortableTableColumnDefinition(array $tableColumn): Column; + + /** + * Aggregates and groups the index results according to the required data result. + * + * @param array> $tableIndexes + * + * @return array + * + * @throws Exception + */ + protected function _getPortableTableIndexesList(array $tableIndexes, string $tableName): array + { + $result = []; + foreach ($tableIndexes as $tableIndex) { + $indexName = $keyName = $tableIndex['key_name']; + if ($tableIndex['primary']) { + $keyName = 'primary'; + } + + $keyName = strtolower($keyName); + + if (! isset($result[$keyName])) { + $options = [ + 'lengths' => [], + ]; + + if (isset($tableIndex['where'])) { + $options['where'] = $tableIndex['where']; + } + + $result[$keyName] = [ + 'name' => $indexName, + 'columns' => [], + 'unique' => ! $tableIndex['non_unique'], + 'primary' => $tableIndex['primary'], + 'flags' => $tableIndex['flags'] ?? [], + 'options' => $options, + ]; + } + + $result[$keyName]['columns'][] = $tableIndex['column_name']; + $result[$keyName]['options']['lengths'][] = $tableIndex['length'] ?? null; + } + + $indexes = []; + foreach ($result as $indexKey => $data) { + $indexes[$indexKey] = new Index( + $data['name'], + $data['columns'], + $data['unique'], + $data['primary'], + $data['flags'], + $data['options'], + ); + } + + return $indexes; + } + + /** @param array $table */ + abstract protected function _getPortableTableDefinition(array $table): string; + + /** @param array $view */ + abstract protected function _getPortableViewDefinition(array $view): View; + + /** + * @param array> $tableForeignKeys + * + * @return array + */ + protected function _getPortableTableForeignKeysList(array $tableForeignKeys): array + { + $list = []; + + foreach ($tableForeignKeys as $value) { + $list[] = $this->_getPortableTableForeignKeyDefinition($value); + } + + return $list; + } + + /** @param array $tableForeignKey */ + abstract protected function _getPortableTableForeignKeyDefinition(array $tableForeignKey): ForeignKeyConstraint; + + /** + * @param array $sql + * + * @throws Exception + */ + private function executeStatements(array $sql): void + { + foreach ($sql as $query) { + $this->connection->executeStatement($query); + } + } + + /** + * Returns a {@see Schema} instance representing the current database schema. + * + * @throws Exception + */ + public function introspectSchema(): Schema + { + $schemaNames = []; + + if ($this->platform->supportsSchemas()) { + $schemaNames = $this->listSchemaNames(); + } + + $sequences = []; + + if ($this->platform->supportsSequences()) { + $sequences = $this->listSequences(); + } + + $tables = $this->listTables(); + + return new Schema($tables, $sequences, $this->createSchemaConfig(), $schemaNames); + } + + /** + * Creates the configuration for this schema. + * + * @throws Exception + */ + public function createSchemaConfig(): SchemaConfig + { + $schemaConfig = new SchemaConfig(); + $schemaConfig->setMaxIdentifierLength($this->platform->getMaxIdentifierLength()); + + $params = $this->connection->getParams(); + if (! isset($params['defaultTableOptions'])) { + $params['defaultTableOptions'] = []; + } + + if (! isset($params['defaultTableOptions']['charset']) && isset($params['charset'])) { + $params['defaultTableOptions']['charset'] = $params['charset']; + } + + $schemaConfig->setDefaultTableOptions($params['defaultTableOptions']); + + return $schemaConfig; + } + + /** @throws Exception */ + private function getDatabase(string $methodName): string + { + $database = $this->connection->getDatabase(); + + if ($database === null) { + throw DatabaseRequired::new($methodName); + } + + return $database; + } + + public function createComparator(): Comparator + { + return new Comparator($this->platform); + } + + /** + * @return array>> + * + * @throws Exception + */ + private function fetchAllAssociativeGrouped(Result $result): array + { + $data = []; + + foreach ($result->fetchAllAssociative() as $row) { + $tableName = $this->_getPortableTableDefinition($row); + $data[$tableName][] = $row; + } + + return $data; + } +} -- cgit v1.2.3