diff options
Diffstat (limited to 'vendor/doctrine/dbal/src/Schema/AbstractSchemaManager.php')
-rw-r--r-- | vendor/doctrine/dbal/src/Schema/AbstractSchemaManager.php | 864 |
1 files changed, 864 insertions, 0 deletions
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 @@ | |||
1 | <?php | ||
2 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Doctrine\DBAL\Schema; | ||
6 | |||
7 | use Doctrine\DBAL\Connection; | ||
8 | use Doctrine\DBAL\Exception; | ||
9 | use Doctrine\DBAL\Exception\DatabaseRequired; | ||
10 | use Doctrine\DBAL\Platforms\AbstractPlatform; | ||
11 | use Doctrine\DBAL\Platforms\Exception\NotSupported; | ||
12 | use Doctrine\DBAL\Result; | ||
13 | use Doctrine\DBAL\Schema\Exception\TableDoesNotExist; | ||
14 | |||
15 | use function array_filter; | ||
16 | use function array_intersect; | ||
17 | use function array_map; | ||
18 | use function array_values; | ||
19 | use function count; | ||
20 | use function strtolower; | ||
21 | |||
22 | /** | ||
23 | * Base class for schema managers. Schema managers are used to inspect and/or | ||
24 | * modify the database schema/structure. | ||
25 | * | ||
26 | * @template-covariant T of AbstractPlatform | ||
27 | */ | ||
28 | abstract class AbstractSchemaManager | ||
29 | { | ||
30 | /** @param T $platform */ | ||
31 | public function __construct(protected Connection $connection, protected AbstractPlatform $platform) | ||
32 | { | ||
33 | } | ||
34 | |||
35 | /** | ||
36 | * Lists the available databases for this connection. | ||
37 | * | ||
38 | * @return array<int, string> | ||
39 | * | ||
40 | * @throws Exception | ||
41 | */ | ||
42 | public function listDatabases(): array | ||
43 | { | ||
44 | return array_map(function (array $row): string { | ||
45 | return $this->_getPortableDatabaseDefinition($row); | ||
46 | }, $this->connection->fetchAllAssociative( | ||
47 | $this->platform->getListDatabasesSQL(), | ||
48 | )); | ||
49 | } | ||
50 | |||
51 | /** | ||
52 | * Returns a list of the names of all schemata in the current database. | ||
53 | * | ||
54 | * @return list<string> | ||
55 | * | ||
56 | * @throws Exception | ||
57 | */ | ||
58 | public function listSchemaNames(): array | ||
59 | { | ||
60 | throw NotSupported::new(__METHOD__); | ||
61 | } | ||
62 | |||
63 | /** | ||
64 | * Lists the available sequences for this connection. | ||
65 | * | ||
66 | * @return array<int, Sequence> | ||
67 | * | ||
68 | * @throws Exception | ||
69 | */ | ||
70 | public function listSequences(): array | ||
71 | { | ||
72 | return $this->filterAssetNames( | ||
73 | array_map(function (array $row): Sequence { | ||
74 | return $this->_getPortableSequenceDefinition($row); | ||
75 | }, $this->connection->fetchAllAssociative( | ||
76 | $this->platform->getListSequencesSQL( | ||
77 | $this->getDatabase(__METHOD__), | ||
78 | ), | ||
79 | )), | ||
80 | ); | ||
81 | } | ||
82 | |||
83 | /** | ||
84 | * Lists the columns for a given table. | ||
85 | * | ||
86 | * In contrast to other libraries and to the old version of Doctrine, | ||
87 | * this column definition does try to contain the 'primary' column for | ||
88 | * the reason that it is not portable across different RDBMS. Use | ||
89 | * {@see listTableIndexes($tableName)} to retrieve the primary key | ||
90 | * of a table. Where a RDBMS specifies more details, these are held | ||
91 | * in the platformDetails array. | ||
92 | * | ||
93 | * @return array<string, Column> | ||
94 | * | ||
95 | * @throws Exception | ||
96 | */ | ||
97 | public function listTableColumns(string $table): array | ||
98 | { | ||
99 | $database = $this->getDatabase(__METHOD__); | ||
100 | |||
101 | return $this->_getPortableTableColumnList( | ||
102 | $table, | ||
103 | $database, | ||
104 | $this->selectTableColumns($database, $this->normalizeName($table)) | ||
105 | ->fetchAllAssociative(), | ||
106 | ); | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * Lists the indexes for a given table returning an array of Index instances. | ||
111 | * | ||
112 | * Keys of the portable indexes list are all lower-cased. | ||
113 | * | ||
114 | * @return array<string, Index> | ||
115 | * | ||
116 | * @throws Exception | ||
117 | */ | ||
118 | public function listTableIndexes(string $table): array | ||
119 | { | ||
120 | $database = $this->getDatabase(__METHOD__); | ||
121 | $table = $this->normalizeName($table); | ||
122 | |||
123 | return $this->_getPortableTableIndexesList( | ||
124 | $this->selectIndexColumns( | ||
125 | $database, | ||
126 | $table, | ||
127 | )->fetchAllAssociative(), | ||
128 | $table, | ||
129 | ); | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * Returns true if all the given tables exist. | ||
134 | * | ||
135 | * @param array<int, string> $names | ||
136 | * | ||
137 | * @throws Exception | ||
138 | */ | ||
139 | public function tablesExist(array $names): bool | ||
140 | { | ||
141 | $names = array_map('strtolower', $names); | ||
142 | |||
143 | return count($names) === count(array_intersect($names, array_map('strtolower', $this->listTableNames()))); | ||
144 | } | ||
145 | |||
146 | public function tableExists(string $tableName): bool | ||
147 | { | ||
148 | return $this->tablesExist([$tableName]); | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * Returns a list of all tables in the current database. | ||
153 | * | ||
154 | * @return array<int, string> | ||
155 | * | ||
156 | * @throws Exception | ||
157 | */ | ||
158 | public function listTableNames(): array | ||
159 | { | ||
160 | return $this->filterAssetNames( | ||
161 | array_map(function (array $row): string { | ||
162 | return $this->_getPortableTableDefinition($row); | ||
163 | }, $this->selectTableNames( | ||
164 | $this->getDatabase(__METHOD__), | ||
165 | )->fetchAllAssociative()), | ||
166 | ); | ||
167 | } | ||
168 | |||
169 | /** | ||
170 | * Filters asset names if they are configured to return only a subset of all | ||
171 | * the found elements. | ||
172 | * | ||
173 | * @param array<int, mixed> $assetNames | ||
174 | * | ||
175 | * @return array<int, mixed> | ||
176 | */ | ||
177 | private function filterAssetNames(array $assetNames): array | ||
178 | { | ||
179 | $filter = $this->connection->getConfiguration()->getSchemaAssetsFilter(); | ||
180 | |||
181 | return array_values(array_filter($assetNames, $filter)); | ||
182 | } | ||
183 | |||
184 | /** | ||
185 | * Lists the tables for this connection. | ||
186 | * | ||
187 | * @return list<Table> | ||
188 | * | ||
189 | * @throws Exception | ||
190 | */ | ||
191 | public function listTables(): array | ||
192 | { | ||
193 | $database = $this->getDatabase(__METHOD__); | ||
194 | |||
195 | $tableColumnsByTable = $this->fetchTableColumnsByTable($database); | ||
196 | $indexColumnsByTable = $this->fetchIndexColumnsByTable($database); | ||
197 | $foreignKeyColumnsByTable = $this->fetchForeignKeyColumnsByTable($database); | ||
198 | $tableOptionsByTable = $this->fetchTableOptionsByTable($database); | ||
199 | |||
200 | $filter = $this->connection->getConfiguration()->getSchemaAssetsFilter(); | ||
201 | $tables = []; | ||
202 | |||
203 | foreach ($tableColumnsByTable as $tableName => $tableColumns) { | ||
204 | if (! $filter($tableName)) { | ||
205 | continue; | ||
206 | } | ||
207 | |||
208 | $tables[] = new Table( | ||
209 | $tableName, | ||
210 | $this->_getPortableTableColumnList($tableName, $database, $tableColumns), | ||
211 | $this->_getPortableTableIndexesList($indexColumnsByTable[$tableName] ?? [], $tableName), | ||
212 | [], | ||
213 | $this->_getPortableTableForeignKeysList($foreignKeyColumnsByTable[$tableName] ?? []), | ||
214 | $tableOptionsByTable[$tableName] ?? [], | ||
215 | ); | ||
216 | } | ||
217 | |||
218 | return $tables; | ||
219 | } | ||
220 | |||
221 | /** | ||
222 | * An extension point for those platforms where case sensitivity of the object name depends on whether it's quoted. | ||
223 | * | ||
224 | * Such platforms should convert a possibly quoted name into a value of the corresponding case. | ||
225 | */ | ||
226 | protected function normalizeName(string $name): string | ||
227 | { | ||
228 | $identifier = new Identifier($name); | ||
229 | |||
230 | return $identifier->getName(); | ||
231 | } | ||
232 | |||
233 | /** | ||
234 | * Selects names of tables in the specified database. | ||
235 | * | ||
236 | * @throws Exception | ||
237 | */ | ||
238 | abstract protected function selectTableNames(string $databaseName): Result; | ||
239 | |||
240 | /** | ||
241 | * Selects definitions of table columns in the specified database. If the table name is specified, narrows down | ||
242 | * the selection to this table. | ||
243 | * | ||
244 | * @throws Exception | ||
245 | */ | ||
246 | abstract protected function selectTableColumns(string $databaseName, ?string $tableName = null): Result; | ||
247 | |||
248 | /** | ||
249 | * Selects definitions of index columns in the specified database. If the table name is specified, narrows down | ||
250 | * the selection to this table. | ||
251 | * | ||
252 | * @throws Exception | ||
253 | */ | ||
254 | abstract protected function selectIndexColumns(string $databaseName, ?string $tableName = null): Result; | ||
255 | |||
256 | /** | ||
257 | * Selects definitions of foreign key columns in the specified database. If the table name is specified, | ||
258 | * narrows down the selection to this table. | ||
259 | * | ||
260 | * @throws Exception | ||
261 | */ | ||
262 | abstract protected function selectForeignKeyColumns(string $databaseName, ?string $tableName = null): Result; | ||
263 | |||
264 | /** | ||
265 | * Fetches definitions of table columns in the specified database and returns them grouped by table name. | ||
266 | * | ||
267 | * @return array<string,list<array<string,mixed>>> | ||
268 | * | ||
269 | * @throws Exception | ||
270 | */ | ||
271 | protected function fetchTableColumnsByTable(string $databaseName): array | ||
272 | { | ||
273 | return $this->fetchAllAssociativeGrouped($this->selectTableColumns($databaseName)); | ||
274 | } | ||
275 | |||
276 | /** | ||
277 | * Fetches definitions of index columns in the specified database and returns them grouped by table name. | ||
278 | * | ||
279 | * @return array<string,list<array<string,mixed>>> | ||
280 | * | ||
281 | * @throws Exception | ||
282 | */ | ||
283 | protected function fetchIndexColumnsByTable(string $databaseName): array | ||
284 | { | ||
285 | return $this->fetchAllAssociativeGrouped($this->selectIndexColumns($databaseName)); | ||
286 | } | ||
287 | |||
288 | /** | ||
289 | * Fetches definitions of foreign key columns in the specified database and returns them grouped by table name. | ||
290 | * | ||
291 | * @return array<string, list<array<string, mixed>>> | ||
292 | * | ||
293 | * @throws Exception | ||
294 | */ | ||
295 | protected function fetchForeignKeyColumnsByTable(string $databaseName): array | ||
296 | { | ||
297 | return $this->fetchAllAssociativeGrouped( | ||
298 | $this->selectForeignKeyColumns($databaseName), | ||
299 | ); | ||
300 | } | ||
301 | |||
302 | /** | ||
303 | * Fetches table options for the tables in the specified database and returns them grouped by table name. | ||
304 | * If the table name is specified, narrows down the selection to this table. | ||
305 | * | ||
306 | * @return array<string,array<string,mixed>> | ||
307 | * | ||
308 | * @throws Exception | ||
309 | */ | ||
310 | abstract protected function fetchTableOptionsByTable(string $databaseName, ?string $tableName = null): array; | ||
311 | |||
312 | /** | ||
313 | * Introspects the table with the given name. | ||
314 | * | ||
315 | * @throws Exception | ||
316 | */ | ||
317 | public function introspectTable(string $name): Table | ||
318 | { | ||
319 | $columns = $this->listTableColumns($name); | ||
320 | |||
321 | if ($columns === []) { | ||
322 | throw TableDoesNotExist::new($name); | ||
323 | } | ||
324 | |||
325 | return new Table( | ||
326 | $name, | ||
327 | $columns, | ||
328 | $this->listTableIndexes($name), | ||
329 | [], | ||
330 | $this->listTableForeignKeys($name), | ||
331 | $this->getTableOptions($name), | ||
332 | ); | ||
333 | } | ||
334 | |||
335 | /** | ||
336 | * Lists the views this connection has. | ||
337 | * | ||
338 | * @return list<View> | ||
339 | * | ||
340 | * @throws Exception | ||
341 | */ | ||
342 | public function listViews(): array | ||
343 | { | ||
344 | return array_map(function (array $row): View { | ||
345 | return $this->_getPortableViewDefinition($row); | ||
346 | }, $this->connection->fetchAllAssociative( | ||
347 | $this->platform->getListViewsSQL( | ||
348 | $this->getDatabase(__METHOD__), | ||
349 | ), | ||
350 | )); | ||
351 | } | ||
352 | |||
353 | /** | ||
354 | * Lists the foreign keys for the given table. | ||
355 | * | ||
356 | * @return array<int|string, ForeignKeyConstraint> | ||
357 | * | ||
358 | * @throws Exception | ||
359 | */ | ||
360 | public function listTableForeignKeys(string $table): array | ||
361 | { | ||
362 | $database = $this->getDatabase(__METHOD__); | ||
363 | |||
364 | return $this->_getPortableTableForeignKeysList( | ||
365 | $this->selectForeignKeyColumns( | ||
366 | $database, | ||
367 | $this->normalizeName($table), | ||
368 | )->fetchAllAssociative(), | ||
369 | ); | ||
370 | } | ||
371 | |||
372 | /** | ||
373 | * @return array<string, mixed> | ||
374 | * | ||
375 | * @throws Exception | ||
376 | */ | ||
377 | private function getTableOptions(string $name): array | ||
378 | { | ||
379 | $normalizedName = $this->normalizeName($name); | ||
380 | |||
381 | return $this->fetchTableOptionsByTable( | ||
382 | $this->getDatabase(__METHOD__), | ||
383 | $normalizedName, | ||
384 | )[$normalizedName] ?? []; | ||
385 | } | ||
386 | |||
387 | /* drop*() Methods */ | ||
388 | |||
389 | /** | ||
390 | * Drops a database. | ||
391 | * | ||
392 | * NOTE: You can not drop the database this SchemaManager is currently connected to. | ||
393 | * | ||
394 | * @throws Exception | ||
395 | */ | ||
396 | public function dropDatabase(string $database): void | ||
397 | { | ||
398 | $this->connection->executeStatement( | ||
399 | $this->platform->getDropDatabaseSQL($database), | ||
400 | ); | ||
401 | } | ||
402 | |||
403 | /** | ||
404 | * Drops a schema. | ||
405 | * | ||
406 | * @throws Exception | ||
407 | */ | ||
408 | public function dropSchema(string $schemaName): void | ||
409 | { | ||
410 | $this->connection->executeStatement( | ||
411 | $this->platform->getDropSchemaSQL($schemaName), | ||
412 | ); | ||
413 | } | ||
414 | |||
415 | /** | ||
416 | * Drops the given table. | ||
417 | * | ||
418 | * @throws Exception | ||
419 | */ | ||
420 | public function dropTable(string $name): void | ||
421 | { | ||
422 | $this->connection->executeStatement( | ||
423 | $this->platform->getDropTableSQL($name), | ||
424 | ); | ||
425 | } | ||
426 | |||
427 | /** | ||
428 | * Drops the index from the given table. | ||
429 | * | ||
430 | * @throws Exception | ||
431 | */ | ||
432 | public function dropIndex(string $index, string $table): void | ||
433 | { | ||
434 | $this->connection->executeStatement( | ||
435 | $this->platform->getDropIndexSQL($index, $table), | ||
436 | ); | ||
437 | } | ||
438 | |||
439 | /** | ||
440 | * Drops a foreign key from a table. | ||
441 | * | ||
442 | * @throws Exception | ||
443 | */ | ||
444 | public function dropForeignKey(string $name, string $table): void | ||
445 | { | ||
446 | $this->connection->executeStatement( | ||
447 | $this->platform->getDropForeignKeySQL($name, $table), | ||
448 | ); | ||
449 | } | ||
450 | |||
451 | /** | ||
452 | * Drops a sequence with a given name. | ||
453 | * | ||
454 | * @throws Exception | ||
455 | */ | ||
456 | public function dropSequence(string $name): void | ||
457 | { | ||
458 | $this->connection->executeStatement( | ||
459 | $this->platform->getDropSequenceSQL($name), | ||
460 | ); | ||
461 | } | ||
462 | |||
463 | /** | ||
464 | * Drops the unique constraint from the given table. | ||
465 | * | ||
466 | * @throws Exception | ||
467 | */ | ||
468 | public function dropUniqueConstraint(string $name, string $tableName): void | ||
469 | { | ||
470 | $this->connection->executeStatement( | ||
471 | $this->platform->getDropUniqueConstraintSQL($name, $tableName), | ||
472 | ); | ||
473 | } | ||
474 | |||
475 | /** | ||
476 | * Drops a view. | ||
477 | * | ||
478 | * @throws Exception | ||
479 | */ | ||
480 | public function dropView(string $name): void | ||
481 | { | ||
482 | $this->connection->executeStatement( | ||
483 | $this->platform->getDropViewSQL($name), | ||
484 | ); | ||
485 | } | ||
486 | |||
487 | /* create*() Methods */ | ||
488 | |||
489 | /** @throws Exception */ | ||
490 | public function createSchemaObjects(Schema $schema): void | ||
491 | { | ||
492 | $this->executeStatements($schema->toSql($this->platform)); | ||
493 | } | ||
494 | |||
495 | /** | ||
496 | * Creates a new database. | ||
497 | * | ||
498 | * @throws Exception | ||
499 | */ | ||
500 | public function createDatabase(string $database): void | ||
501 | { | ||
502 | $this->connection->executeStatement( | ||
503 | $this->platform->getCreateDatabaseSQL($database), | ||
504 | ); | ||
505 | } | ||
506 | |||
507 | /** | ||
508 | * Creates a new table. | ||
509 | * | ||
510 | * @throws Exception | ||
511 | */ | ||
512 | public function createTable(Table $table): void | ||
513 | { | ||
514 | $this->executeStatements($this->platform->getCreateTableSQL($table)); | ||
515 | } | ||
516 | |||
517 | /** | ||
518 | * Creates a new sequence. | ||
519 | * | ||
520 | * @throws Exception | ||
521 | */ | ||
522 | public function createSequence(Sequence $sequence): void | ||
523 | { | ||
524 | $this->connection->executeStatement( | ||
525 | $this->platform->getCreateSequenceSQL($sequence), | ||
526 | ); | ||
527 | } | ||
528 | |||
529 | /** | ||
530 | * Creates a new index on a table. | ||
531 | * | ||
532 | * @param string $table The name of the table on which the index is to be created. | ||
533 | * | ||
534 | * @throws Exception | ||
535 | */ | ||
536 | public function createIndex(Index $index, string $table): void | ||
537 | { | ||
538 | $this->connection->executeStatement( | ||
539 | $this->platform->getCreateIndexSQL($index, $table), | ||
540 | ); | ||
541 | } | ||
542 | |||
543 | /** | ||
544 | * Creates a new foreign key. | ||
545 | * | ||
546 | * @param ForeignKeyConstraint $foreignKey The ForeignKey instance. | ||
547 | * @param string $table The name of the table on which the foreign key is to be created. | ||
548 | * | ||
549 | * @throws Exception | ||
550 | */ | ||
551 | public function createForeignKey(ForeignKeyConstraint $foreignKey, string $table): void | ||
552 | { | ||
553 | $this->connection->executeStatement( | ||
554 | $this->platform->getCreateForeignKeySQL($foreignKey, $table), | ||
555 | ); | ||
556 | } | ||
557 | |||
558 | /** | ||
559 | * Creates a unique constraint on a table. | ||
560 | * | ||
561 | * @throws Exception | ||
562 | */ | ||
563 | public function createUniqueConstraint(UniqueConstraint $uniqueConstraint, string $tableName): void | ||
564 | { | ||
565 | $this->connection->executeStatement( | ||
566 | $this->platform->getCreateUniqueConstraintSQL($uniqueConstraint, $tableName), | ||
567 | ); | ||
568 | } | ||
569 | |||
570 | /** | ||
571 | * Creates a new view. | ||
572 | * | ||
573 | * @throws Exception | ||
574 | */ | ||
575 | public function createView(View $view): void | ||
576 | { | ||
577 | $this->connection->executeStatement( | ||
578 | $this->platform->getCreateViewSQL( | ||
579 | $view->getQuotedName($this->platform), | ||
580 | $view->getSql(), | ||
581 | ), | ||
582 | ); | ||
583 | } | ||
584 | |||
585 | /** @throws Exception */ | ||
586 | public function dropSchemaObjects(Schema $schema): void | ||
587 | { | ||
588 | $this->executeStatements($schema->toDropSql($this->platform)); | ||
589 | } | ||
590 | |||
591 | /** | ||
592 | * Alters an existing schema. | ||
593 | * | ||
594 | * @throws Exception | ||
595 | */ | ||
596 | public function alterSchema(SchemaDiff $schemaDiff): void | ||
597 | { | ||
598 | $this->executeStatements($this->platform->getAlterSchemaSQL($schemaDiff)); | ||
599 | } | ||
600 | |||
601 | /** | ||
602 | * Migrates an existing schema to a new schema. | ||
603 | * | ||
604 | * @throws Exception | ||
605 | */ | ||
606 | public function migrateSchema(Schema $newSchema): void | ||
607 | { | ||
608 | $schemaDiff = $this->createComparator() | ||
609 | ->compareSchemas($this->introspectSchema(), $newSchema); | ||
610 | |||
611 | $this->alterSchema($schemaDiff); | ||
612 | } | ||
613 | |||
614 | /* alterTable() Methods */ | ||
615 | |||
616 | /** | ||
617 | * Alters an existing tables schema. | ||
618 | * | ||
619 | * @throws Exception | ||
620 | */ | ||
621 | public function alterTable(TableDiff $tableDiff): void | ||
622 | { | ||
623 | $this->executeStatements($this->platform->getAlterTableSQL($tableDiff)); | ||
624 | } | ||
625 | |||
626 | /** | ||
627 | * Renames a given table to another name. | ||
628 | * | ||
629 | * @throws Exception | ||
630 | */ | ||
631 | public function renameTable(string $name, string $newName): void | ||
632 | { | ||
633 | $this->connection->executeStatement( | ||
634 | $this->platform->getRenameTableSQL($name, $newName), | ||
635 | ); | ||
636 | } | ||
637 | |||
638 | /** | ||
639 | * Methods for filtering return values of list*() methods to convert | ||
640 | * the native DBMS data definition to a portable Doctrine definition | ||
641 | */ | ||
642 | |||
643 | /** @param array<string, string> $database */ | ||
644 | protected function _getPortableDatabaseDefinition(array $database): string | ||
645 | { | ||
646 | throw NotSupported::new(__METHOD__); | ||
647 | } | ||
648 | |||
649 | /** @param array<string, mixed> $sequence */ | ||
650 | protected function _getPortableSequenceDefinition(array $sequence): Sequence | ||
651 | { | ||
652 | throw NotSupported::new(__METHOD__); | ||
653 | } | ||
654 | |||
655 | /** | ||
656 | * Independent of the database the keys of the column list result are lowercased. | ||
657 | * | ||
658 | * The name of the created column instance however is kept in its case. | ||
659 | * | ||
660 | * @param array<int, array<string, mixed>> $tableColumns | ||
661 | * | ||
662 | * @return array<string, Column> | ||
663 | * | ||
664 | * @throws Exception | ||
665 | */ | ||
666 | protected function _getPortableTableColumnList(string $table, string $database, array $tableColumns): array | ||
667 | { | ||
668 | $list = []; | ||
669 | foreach ($tableColumns as $tableColumn) { | ||
670 | $column = $this->_getPortableTableColumnDefinition($tableColumn); | ||
671 | |||
672 | $name = strtolower($column->getQuotedName($this->platform)); | ||
673 | $list[$name] = $column; | ||
674 | } | ||
675 | |||
676 | return $list; | ||
677 | } | ||
678 | |||
679 | /** | ||
680 | * Gets Table Column Definition. | ||
681 | * | ||
682 | * @param array<string, mixed> $tableColumn | ||
683 | * | ||
684 | * @throws Exception | ||
685 | */ | ||
686 | abstract protected function _getPortableTableColumnDefinition(array $tableColumn): Column; | ||
687 | |||
688 | /** | ||
689 | * Aggregates and groups the index results according to the required data result. | ||
690 | * | ||
691 | * @param array<int, array<string, mixed>> $tableIndexes | ||
692 | * | ||
693 | * @return array<string, Index> | ||
694 | * | ||
695 | * @throws Exception | ||
696 | */ | ||
697 | protected function _getPortableTableIndexesList(array $tableIndexes, string $tableName): array | ||
698 | { | ||
699 | $result = []; | ||
700 | foreach ($tableIndexes as $tableIndex) { | ||
701 | $indexName = $keyName = $tableIndex['key_name']; | ||
702 | if ($tableIndex['primary']) { | ||
703 | $keyName = 'primary'; | ||
704 | } | ||
705 | |||
706 | $keyName = strtolower($keyName); | ||
707 | |||
708 | if (! isset($result[$keyName])) { | ||
709 | $options = [ | ||
710 | 'lengths' => [], | ||
711 | ]; | ||
712 | |||
713 | if (isset($tableIndex['where'])) { | ||
714 | $options['where'] = $tableIndex['where']; | ||
715 | } | ||
716 | |||
717 | $result[$keyName] = [ | ||
718 | 'name' => $indexName, | ||
719 | 'columns' => [], | ||
720 | 'unique' => ! $tableIndex['non_unique'], | ||
721 | 'primary' => $tableIndex['primary'], | ||
722 | 'flags' => $tableIndex['flags'] ?? [], | ||
723 | 'options' => $options, | ||
724 | ]; | ||
725 | } | ||
726 | |||
727 | $result[$keyName]['columns'][] = $tableIndex['column_name']; | ||
728 | $result[$keyName]['options']['lengths'][] = $tableIndex['length'] ?? null; | ||
729 | } | ||
730 | |||
731 | $indexes = []; | ||
732 | foreach ($result as $indexKey => $data) { | ||
733 | $indexes[$indexKey] = new Index( | ||
734 | $data['name'], | ||
735 | $data['columns'], | ||
736 | $data['unique'], | ||
737 | $data['primary'], | ||
738 | $data['flags'], | ||
739 | $data['options'], | ||
740 | ); | ||
741 | } | ||
742 | |||
743 | return $indexes; | ||
744 | } | ||
745 | |||
746 | /** @param array<string, string> $table */ | ||
747 | abstract protected function _getPortableTableDefinition(array $table): string; | ||
748 | |||
749 | /** @param array<string, mixed> $view */ | ||
750 | abstract protected function _getPortableViewDefinition(array $view): View; | ||
751 | |||
752 | /** | ||
753 | * @param array<int|string, array<string, mixed>> $tableForeignKeys | ||
754 | * | ||
755 | * @return array<int, ForeignKeyConstraint> | ||
756 | */ | ||
757 | protected function _getPortableTableForeignKeysList(array $tableForeignKeys): array | ||
758 | { | ||
759 | $list = []; | ||
760 | |||
761 | foreach ($tableForeignKeys as $value) { | ||
762 | $list[] = $this->_getPortableTableForeignKeyDefinition($value); | ||
763 | } | ||
764 | |||
765 | return $list; | ||
766 | } | ||
767 | |||
768 | /** @param array<string, mixed> $tableForeignKey */ | ||
769 | abstract protected function _getPortableTableForeignKeyDefinition(array $tableForeignKey): ForeignKeyConstraint; | ||
770 | |||
771 | /** | ||
772 | * @param array<int, string> $sql | ||
773 | * | ||
774 | * @throws Exception | ||
775 | */ | ||
776 | private function executeStatements(array $sql): void | ||
777 | { | ||
778 | foreach ($sql as $query) { | ||
779 | $this->connection->executeStatement($query); | ||
780 | } | ||
781 | } | ||
782 | |||
783 | /** | ||
784 | * Returns a {@see Schema} instance representing the current database schema. | ||
785 | * | ||
786 | * @throws Exception | ||
787 | */ | ||
788 | public function introspectSchema(): Schema | ||
789 | { | ||
790 | $schemaNames = []; | ||
791 | |||
792 | if ($this->platform->supportsSchemas()) { | ||
793 | $schemaNames = $this->listSchemaNames(); | ||
794 | } | ||
795 | |||
796 | $sequences = []; | ||
797 | |||
798 | if ($this->platform->supportsSequences()) { | ||
799 | $sequences = $this->listSequences(); | ||
800 | } | ||
801 | |||
802 | $tables = $this->listTables(); | ||
803 | |||
804 | return new Schema($tables, $sequences, $this->createSchemaConfig(), $schemaNames); | ||
805 | } | ||
806 | |||
807 | /** | ||
808 | * Creates the configuration for this schema. | ||
809 | * | ||
810 | * @throws Exception | ||
811 | */ | ||
812 | public function createSchemaConfig(): SchemaConfig | ||
813 | { | ||
814 | $schemaConfig = new SchemaConfig(); | ||
815 | $schemaConfig->setMaxIdentifierLength($this->platform->getMaxIdentifierLength()); | ||
816 | |||
817 | $params = $this->connection->getParams(); | ||
818 | if (! isset($params['defaultTableOptions'])) { | ||
819 | $params['defaultTableOptions'] = []; | ||
820 | } | ||
821 | |||
822 | if (! isset($params['defaultTableOptions']['charset']) && isset($params['charset'])) { | ||
823 | $params['defaultTableOptions']['charset'] = $params['charset']; | ||
824 | } | ||
825 | |||
826 | $schemaConfig->setDefaultTableOptions($params['defaultTableOptions']); | ||
827 | |||
828 | return $schemaConfig; | ||
829 | } | ||
830 | |||
831 | /** @throws Exception */ | ||
832 | private function getDatabase(string $methodName): string | ||
833 | { | ||
834 | $database = $this->connection->getDatabase(); | ||
835 | |||
836 | if ($database === null) { | ||
837 | throw DatabaseRequired::new($methodName); | ||
838 | } | ||
839 | |||
840 | return $database; | ||
841 | } | ||
842 | |||
843 | public function createComparator(): Comparator | ||
844 | { | ||
845 | return new Comparator($this->platform); | ||
846 | } | ||
847 | |||
848 | /** | ||
849 | * @return array<string,list<array<string,mixed>>> | ||
850 | * | ||
851 | * @throws Exception | ||
852 | */ | ||
853 | private function fetchAllAssociativeGrouped(Result $result): array | ||
854 | { | ||
855 | $data = []; | ||
856 | |||
857 | foreach ($result->fetchAllAssociative() as $row) { | ||
858 | $tableName = $this->_getPortableTableDefinition($row); | ||
859 | $data[$tableName][] = $row; | ||
860 | } | ||
861 | |||
862 | return $data; | ||
863 | } | ||
864 | } | ||