AbstractSchemaManager::dropIndex()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 7
ccs 3
cts 4
cp 0.75
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 2.0625
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\DBAL\Schema;
6
7
use Doctrine\DBAL\Connection;
8
use Doctrine\DBAL\ConnectionException;
9
use Doctrine\DBAL\DBALException;
10
use Doctrine\DBAL\Event\SchemaColumnDefinitionEventArgs;
11
use Doctrine\DBAL\Event\SchemaIndexDefinitionEventArgs;
12
use Doctrine\DBAL\Events;
13
use Doctrine\DBAL\Exception\DatabaseRequired;
14
use Doctrine\DBAL\Platforms\AbstractPlatform;
15
use Doctrine\DBAL\Platforms\Exception\NotSupported;
16
use Throwable;
17
use function array_filter;
18
use function array_intersect;
19
use function array_map;
20
use function array_shift;
21
use function array_values;
22
use function assert;
23
use function count;
24
use function preg_match;
25
use function strtolower;
26
27
/**
28
 * Base class for schema managers. Schema managers are used to inspect and/or
29
 * modify the database schema/structure.
30
 */
31
abstract class AbstractSchemaManager
32
{
33
    /**
34
     * Holds instance of the Doctrine connection for this schema manager.
35
     *
36
     * @var Connection
37
     */
38
    protected $_conn;
39
40
    /**
41
     * Holds instance of the database platform used for this schema manager.
42
     *
43
     * @var AbstractPlatform
44
     */
45
    protected $_platform;
46
47
    /**
48
     * Constructor. Accepts the Connection instance to manage the schema for.
49
     */
50 1338
    public function __construct(Connection $conn, ?AbstractPlatform $platform = null)
51
    {
52 1338
        $this->_conn     = $conn;
53 1338
        $this->_platform = $platform ?? $this->_conn->getDatabasePlatform();
54 1338
    }
55
56
    /**
57
     * Returns the associated platform.
58
     */
59 389
    public function getDatabasePlatform() : AbstractPlatform
60
    {
61 389
        return $this->_platform;
62
    }
63
64
    /**
65
     * Tries any method on the schema manager. Normally a method throws an
66
     * exception when your DBMS doesn't support it or if an error occurs.
67
     * This method allows you to try and method on your SchemaManager
68
     * instance and will return false if it does not work or is not supported.
69
     *
70
     * <code>
71
     * $result = $sm->tryMethod('dropView', 'view_name');
72
     * </code>
73
     *
74
     * @param mixed ...$arguments
75
     *
76
     * @return mixed
77
     */
78 3175
    public function tryMethod(string $method, ...$arguments)
79
    {
80
        try {
81 3175
            return $this->$method(...$arguments);
82 1560
        } catch (Throwable $e) {
83 1560
            return false;
84
        }
85
    }
86
87
    /**
88
     * Lists the available databases for this connection.
89
     *
90
     * @return array<int, string>
91
     */
92 41
    public function listDatabases() : array
93
    {
94 41
        $sql = $this->_platform->getListDatabasesSQL();
95
96 40
        $databases = $this->_conn->fetchAll($sql);
97
98 40
        return $this->_getPortableDatabasesList($databases);
99
    }
100
101
    /**
102
     * Returns a list of all namespaces in the current database.
103
     *
104
     * @return array<int, string>
105
     */
106 14
    public function listNamespaceNames() : array
107
    {
108 14
        $sql = $this->_platform->getListNamespacesSQL();
109
110 14
        $namespaces = $this->_conn->fetchAll($sql);
111
112 14
        return $this->getPortableNamespacesList($namespaces);
113
    }
114
115
    /**
116
     * Lists the available sequences for this connection.
117
     *
118
     * @return array<int, Sequence>
119
     */
120 47
    public function listSequences(?string $database = null) : array
121
    {
122 47
        $database = $this->ensureDatabase(
123 47
            $database ?? $this->_conn->getDatabase(),
124 47
            __METHOD__
125
        );
126
127 47
        $sql = $this->_platform->getListSequencesSQL($database);
128
129 47
        $sequences = $this->_conn->fetchAll($sql);
130
131 47
        return $this->filterAssetNames($this->_getPortableSequencesList($sequences));
132
    }
133
134
    /**
135
     * Lists the columns for a given table.
136
     *
137
     * In contrast to other libraries and to the old version of Doctrine,
138
     * this column definition does try to contain the 'primary' field for
139
     * the reason that it is not portable across different RDBMS. Use
140
     * {@see listTableIndexes($tableName)} to retrieve the primary key
141
     * of a table. Where a RDBMS specifies more details, these are held
142
     * in the platformDetails array.
143
     *
144
     * @return array<string, Column>
145
     */
146 1562
    public function listTableColumns(string $table, ?string $database = null) : array
147
    {
148 1562
        $database = $this->ensureDatabase(
149 1562
            $database ?? $this->_conn->getDatabase(),
150 1562
            __METHOD__
151
        );
152
153 1550
        $sql = $this->_platform->getListTableColumnsSQL($table, $database);
154
155 1550
        $tableColumns = $this->_conn->fetchAll($sql);
156
157 1550
        return $this->_getPortableTableColumnList($table, $database, $tableColumns);
158
    }
159
160
    /**
161
     * Lists the indexes for a given table returning an array of Index instances.
162
     *
163
     * Keys of the portable indexes list are all lower-cased.
164
     *
165
     * @return array<string, Index>
166
     */
167 1349
    public function listTableIndexes(string $table) : array
168
    {
169 1349
        $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
170
171 1349
        $tableIndexes = $this->_conn->fetchAll($sql);
172
173 1349
        return $this->_getPortableTableIndexesList($tableIndexes, $table);
174
    }
175
176
    /**
177
     * Returns true if all the given tables exist.
178
     *
179
     * @param array<int, string> $tableNames
180
     */
181 178
    public function tablesExist(array $tableNames) : bool
182
    {
183 178
        $tableNames = array_map('strtolower', $tableNames);
184
185 178
        return count($tableNames) === count(array_intersect($tableNames, array_map('strtolower', $this->listTableNames())));
186
    }
187
188 178
    public function tableExists(string $tableName) : bool
189
    {
190 178
        return $this->tablesExist([$tableName]);
191
    }
192
193
    /**
194
     * Returns a list of all tables in the current database.
195
     *
196
     * @return array<int, string>
197
     */
198 314
    public function listTableNames() : array
199
    {
200 314
        $sql = $this->_platform->getListTablesSQL();
201
202 314
        $tables     = $this->_conn->fetchAll($sql);
203 314
        $tableNames = $this->_getPortableTablesList($tables);
204
205 314
        return $this->filterAssetNames($tableNames);
206
    }
207
208
    /**
209
     * Filters asset names if they are configured to return only a subset of all
210
     * the found elements.
211
     *
212
     * @param array<int, mixed> $assetNames
213
     *
214
     * @return array<int, mixed>
215
     */
216 363
    protected function filterAssetNames(array $assetNames) : array
217
    {
218 363
        $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter();
219 363
        if ($filter === null) {
220 358
            return $assetNames;
221
        }
222
223 5
        return array_values(array_filter($assetNames, $filter));
224
    }
225
226
    /**
227
     * Lists the tables for this connection.
228
     *
229
     * @return array<int, Table>
230
     */
231 128
    public function listTables() : array
232
    {
233 128
        $tableNames = $this->listTableNames();
234
235 128
        $tables = [];
236 128
        foreach ($tableNames as $tableName) {
237 106
            $tables[] = $this->listTableDetails($tableName);
238
        }
239
240 128
        return $tables;
241
    }
242
243 1320
    public function listTableDetails(string $tableName) : Table
244
    {
245 1320
        $columns     = $this->listTableColumns($tableName);
246 1320
        $foreignKeys = [];
247
248 1320
        if ($this->_platform->supportsForeignKeyConstraints()) {
249 1320
            $foreignKeys = $this->listTableForeignKeys($tableName);
250
        }
251
252 1320
        $indexes = $this->listTableIndexes($tableName);
253
254 1320
        return new Table($tableName, $columns, $indexes, [], $foreignKeys, []);
255
    }
256
257
    /**
258
     * Lists the views this connection has.
259
     *
260
     * @return array<string, View>
261
     */
262 22
    public function listViews() : array
263
    {
264 22
        $database = $this->ensureDatabase(
265 22
            $this->_conn->getDatabase(),
266 22
            __METHOD__
267
        );
268
269 22
        $sql   = $this->_platform->getListViewsSQL($database);
270 22
        $views = $this->_conn->fetchAll($sql);
271
272 22
        return $this->_getPortableViewsList($views);
273
    }
274
275
    /**
276
     * Lists the foreign keys for the given table.
277
     *
278
     * @return array<int|string, ForeignKeyConstraint>
279
     */
280 1310
    public function listTableForeignKeys(string $table, ?string $database = null) : array
281
    {
282 1310
        if ($database === null) {
283 1310
            $database = $this->_conn->getDatabase();
284
        }
285
286 1310
        $sql              = $this->_platform->getListTableForeignKeysSQL($table, $database);
287 1310
        $tableForeignKeys = $this->_conn->fetchAll($sql);
288
289 1310
        return $this->_getPortableTableForeignKeysList($tableForeignKeys);
290
    }
291
292
    /* drop*() Methods */
293
294
    /**
295
     * Drops a database.
296
     *
297
     * NOTE: You can not drop the database this SchemaManager is currently connected to.
298
     */
299 52
    public function dropDatabase(string $database) : void
300
    {
301 52
        $this->_execSql($this->_platform->getDropDatabaseSQL($database));
302 32
    }
303
304
    /**
305
     * Drops the given table.
306
     */
307 3235
    public function dropTable(string $tableName) : void
308
    {
309 3235
        $this->_execSql($this->_platform->getDropTableSQL($tableName));
310 1840
    }
311
312
    /**
313
     * Drops the index from the given table.
314
     *
315
     * @param Index|string $index The name of the index.
316
     * @param Table|string $table The name of the table.
317
     */
318 22
    public function dropIndex($index, $table) : void
319
    {
320 22
        if ($index instanceof Index) {
321
            $index = $index->getQuotedName($this->_platform);
322
        }
323
324 22
        $this->_execSql($this->_platform->getDropIndexSQL($index, $table));
325 22
    }
326
327
    /**
328
     * Drops the constraint from the given table.
329
     *
330
     * @param Table|string $table The name of the table.
331
     */
332
    public function dropConstraint(Constraint $constraint, $table) : void
333
    {
334
        $this->_execSql($this->_platform->getDropConstraintSQL($constraint, $table));
335
    }
336
337
    /**
338
     * Drops a foreign key from a table.
339
     *
340
     * @param ForeignKeyConstraint|string $foreignKey The name of the foreign key.
341
     * @param Table|string                $table      The name of the table with the foreign key.
342
     */
343
    public function dropForeignKey($foreignKey, $table) : void
344
    {
345
        $this->_execSql($this->_platform->getDropForeignKeySQL($foreignKey, $table));
346
    }
347
348
    /**
349
     * Drops a sequence with a given name.
350
     */
351 16
    public function dropSequence(string $name) : void
352
    {
353 16
        $this->_execSql($this->_platform->getDropSequenceSQL($name));
354
    }
355
356
    /**
357
     * Drops a view.
358
     */
359 27
    public function dropView(string $name) : void
360
    {
361 27
        $this->_execSql($this->_platform->getDropViewSQL($name));
362
    }
363
364
    /* create*() Methods */
365
366
    /**
367
     * Creates a new database.
368
     */
369 50
    public function createDatabase(string $database) : void
370
    {
371 50
        $this->_execSql($this->_platform->getCreateDatabaseSQL($database));
372 50
    }
373
374
    /**
375
     * Creates a new table.
376
     */
377 3193
    public function createTable(Table $table) : void
378
    {
379 3193
        $createFlags = AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS;
380 3193
        $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags));
381 3097
    }
382
383
    /**
384
     * Creates a new sequence.
385
     *
386
     * @throws ConnectionException If something fails at database level.
387
     */
388 39
    public function createSequence(Sequence $sequence) : void
389
    {
390 39
        $this->_execSql($this->_platform->getCreateSequenceSQL($sequence));
391 34
    }
392
393
    /**
394
     * Creates a constraint on a table.
395
     *
396
     * @param Table|string $table
397
     */
398 1
    public function createConstraint(Constraint $constraint, $table) : void
399
    {
400 1
        $this->_execSql($this->_platform->getCreateConstraintSQL($constraint, $table));
401 1
    }
402
403
    /**
404
     * Creates a new index on a table.
405
     *
406
     * @param Table|string $table The name of the table on which the index is to be created.
407
     */
408 22
    public function createIndex(Index $index, $table) : void
409
    {
410 22
        $this->_execSql($this->_platform->getCreateIndexSQL($index, $table));
411 22
    }
412
413
    /**
414
     * Creates a new foreign key.
415
     *
416
     * @param ForeignKeyConstraint $foreignKey The ForeignKey instance.
417
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
418
     */
419 42
    public function createForeignKey(ForeignKeyConstraint $foreignKey, $table) : void
420
    {
421 42
        $this->_execSql($this->_platform->getCreateForeignKeySQL($foreignKey, $table));
422 42
    }
423
424
    /**
425
     * Creates a new view.
426
     */
427 27
    public function createView(View $view) : void
428
    {
429 27
        $this->_execSql($this->_platform->getCreateViewSQL($view->getQuotedName($this->_platform), $view->getSql()));
430 27
    }
431
432
    /* dropAndCreate*() Methods */
433
434
    /**
435
     * Drops and creates a constraint.
436
     *
437
     * @see dropConstraint()
438
     * @see createConstraint()
439
     *
440
     * @param Table|string $table
441
     */
442
    public function dropAndCreateConstraint(Constraint $constraint, $table) : void
443
    {
444
        $this->tryMethod('dropConstraint', $constraint, $table);
445
        $this->createConstraint($constraint, $table);
446
    }
447
448
    /**
449
     * Drops and creates a new index on a table.
450
     *
451
     * @param Table|string $table The name of the table on which the index is to be created.
452
     */
453 22
    public function dropAndCreateIndex(Index $index, $table) : void
454
    {
455 22
        $this->tryMethod('dropIndex', $index->getQuotedName($this->_platform), $table);
456 22
        $this->createIndex($index, $table);
457 22
    }
458
459
    /**
460
     * Drops and creates a new foreign key.
461
     *
462
     * @param ForeignKeyConstraint $foreignKey An associative array that defines properties of the foreign key to be created.
463
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
464
     */
465
    public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table) : void
466
    {
467
        $this->tryMethod('dropForeignKey', $foreignKey, $table);
468
        $this->createForeignKey($foreignKey, $table);
469
    }
470
471
    /**
472
     * Drops and create a new sequence.
473
     *
474
     * @throws ConnectionException If something fails at database level.
475
     */
476 16
    public function dropAndCreateSequence(Sequence $sequence) : void
477
    {
478 16
        $this->tryMethod('dropSequence', $sequence->getQuotedName($this->_platform));
479 16
        $this->createSequence($sequence);
480 16
    }
481
482
    /**
483
     * Drops and creates a new table.
484
     */
485 2614
    public function dropAndCreateTable(Table $table) : void
486
    {
487 2614
        $this->tryMethod('dropTable', $table->getQuotedName($this->_platform));
488 2614
        $this->createTable($table);
489 2614
    }
490
491
    /**
492
     * Drops and creates a new database.
493
     */
494 53
    public function dropAndCreateDatabase(string $database) : void
495
    {
496 53
        $this->tryMethod('dropDatabase', $database);
497 53
        $this->createDatabase($database);
498 53
    }
499
500
    /**
501
     * Drops and creates a new view.
502
     */
503 27
    public function dropAndCreateView(View $view) : void
504
    {
505 27
        $this->tryMethod('dropView', $view->getQuotedName($this->_platform));
506 27
        $this->createView($view);
507 27
    }
508
509
    /* alterTable() Methods */
510
511
    /**
512
     * Alters an existing tables schema.
513
     */
514 305
    public function alterTable(TableDiff $tableDiff) : void
515
    {
516 305
        $queries = $this->_platform->getAlterTableSQL($tableDiff);
517
518 305
        foreach ($queries as $ddlQuery) {
519 297
            $this->_execSql($ddlQuery);
520
        }
521 305
    }
522
523
    /**
524
     * Renames a given table to another name.
525
     */
526 1
    public function renameTable(string $name, string $newName) : void
527
    {
528 1
        $tableDiff          = new TableDiff($name);
529 1
        $tableDiff->newName = $newName;
530 1
        $this->alterTable($tableDiff);
531 1
    }
532
533
    /**
534
     * Methods for filtering return values of list*() methods to convert
535
     * the native DBMS data definition to a portable Doctrine definition
536
     */
537
538
    /**
539
     * @param array<int, mixed> $databases
540
     *
541
     * @return array<int, string>
542
     */
543 40
    protected function _getPortableDatabasesList(array $databases) : array
544
    {
545 40
        $list = [];
546 40
        foreach ($databases as $value) {
547 40
            $list[] = $this->_getPortableDatabaseDefinition($value);
548
        }
549
550 40
        return $list;
551
    }
552
553
    /**
554
     * Converts a list of namespace names from the native DBMS data definition to a portable Doctrine definition.
555
     *
556
     * @param array<int, array<int, mixed>> $namespaces The list of namespace names in the native DBMS data definition.
557
     *
558
     * @return array<int, string>
559
     */
560 14
    protected function getPortableNamespacesList(array $namespaces) : array
561
    {
562 14
        $namespacesList = [];
563
564 14
        foreach ($namespaces as $namespace) {
565 14
            $namespacesList[] = $this->getPortableNamespaceDefinition($namespace);
566
        }
567
568 14
        return $namespacesList;
569
    }
570
571
    /**
572
     * @param array<string, string> $database
573
     */
574
    protected function _getPortableDatabaseDefinition(array $database) : string
575
    {
576
        assert(! empty($database));
577
578
        return array_shift($database);
579
    }
580
581
    /**
582
     * Converts a namespace definition from the native DBMS data definition to a portable Doctrine definition.
583
     *
584
     * @param array<string|int, mixed> $namespace The native DBMS namespace definition.
585
     */
586
    protected function getPortableNamespaceDefinition(array $namespace) : string
587
    {
588
        return array_shift($namespace);
589
    }
590
591
    /**
592
     * @param array<int, array<string, mixed>> $sequences
593
     *
594
     * @return array<int, Sequence>
595
     */
596 17
    protected function _getPortableSequencesList(array $sequences) : array
597
    {
598 17
        $list = [];
599
600 17
        foreach ($sequences as $value) {
601 17
            $list[] = $this->_getPortableSequenceDefinition($value);
602
        }
603
604 17
        return $list;
605
    }
606
607
    /**
608
     * @param array<string, mixed> $sequence
609
     *
610
     * @throws DBALException
611
     */
612
    protected function _getPortableSequenceDefinition(array $sequence) : Sequence
613
    {
614
        throw NotSupported::new('Sequences');
615
    }
616
617
    /**
618
     * Independent of the database the keys of the column list result are lowercased.
619
     *
620
     * The name of the created column instance however is kept in its case.
621
     *
622
     * @param array<int, array<string, mixed>> $tableColumns
623
     *
624
     * @return array<string, Column>
625
     */
626 1550
    protected function _getPortableTableColumnList(string $table, string $database, array $tableColumns) : array
627
    {
628 1550
        $eventManager = $this->_platform->getEventManager();
629
630 1550
        $list = [];
631 1550
        foreach ($tableColumns as $tableColumn) {
632 1538
            $column           = null;
633 1538
            $defaultPrevented = false;
634
635 1538
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaColumnDefinition)) {
636 22
                $eventArgs = new SchemaColumnDefinitionEventArgs($tableColumn, $table, $database, $this->_conn);
637 22
                $eventManager->dispatchEvent(Events::onSchemaColumnDefinition, $eventArgs);
638
639 22
                $defaultPrevented = $eventArgs->isDefaultPrevented();
640 22
                $column           = $eventArgs->getColumn();
641
            }
642
643 1538
            if (! $defaultPrevented) {
644 1538
                $column = $this->_getPortableTableColumnDefinition($tableColumn);
645
            }
646
647 1538
            if ($column === null) {
648
                continue;
649
            }
650
651 1538
            $name        = strtolower($column->getQuotedName($this->_platform));
652 1538
            $list[$name] = $column;
653
        }
654
655 1550
        return $list;
656
    }
657
658
    /**
659
     * Gets Table Column Definition.
660
     *
661
     * @param array<string, mixed> $tableColumn
662
     */
663
    abstract protected function _getPortableTableColumnDefinition(array $tableColumn) : Column;
664
665
    /**
666
     * Aggregates and groups the index results according to the required data result.
667
     *
668
     * @param array<int, array<string, mixed>> $tableIndexRows
669
     *
670
     * @return array<string, Index>
671
     */
672 1455
    protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array
673
    {
674 1455
        $result = [];
675 1455
        foreach ($tableIndexRows as $tableIndex) {
676 560
            $indexName = $keyName = $tableIndex['key_name'];
677 560
            if ($tableIndex['primary']) {
678 463
                $keyName = 'primary';
679
            }
680
681 560
            $keyName = strtolower($keyName);
682
683 560
            if (! isset($result[$keyName])) {
684
                $options = [
685 560
                    'lengths' => [],
686
                ];
687
688 560
                if (isset($tableIndex['where'])) {
689 15
                    $options['where'] = $tableIndex['where'];
690
                }
691
692 560
                $result[$keyName] = [
693 560
                    'name' => $indexName,
694
                    'columns' => [],
695 560
                    'unique' => ! $tableIndex['non_unique'],
696 560
                    'primary' => $tableIndex['primary'],
697 560
                    'flags' => $tableIndex['flags'] ?? [],
698 560
                    'options' => $options,
699
                ];
700
            }
701
702 560
            $result[$keyName]['columns'][]            = $tableIndex['column_name'];
703 560
            $result[$keyName]['options']['lengths'][] = $tableIndex['length'] ?? null;
704
        }
705
706 1455
        $eventManager = $this->_platform->getEventManager();
707
708 1455
        $indexes = [];
709 1455
        foreach ($result as $indexKey => $data) {
710 560
            $index            = null;
711 560
            $defaultPrevented = false;
712
713 560
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) {
714 22
                $eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn);
715 22
                $eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs);
716
717 22
                $defaultPrevented = $eventArgs->isDefaultPrevented();
718 22
                $index            = $eventArgs->getIndex();
719
            }
720
721 560
            if (! $defaultPrevented) {
722 560
                $index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary'], $data['flags'], $data['options']);
723
            }
724
725 560
            if ($index === null) {
726
                continue;
727
            }
728
729 560
            $indexes[$indexKey] = $index;
730
        }
731
732 1455
        return $indexes;
733
    }
734
735
    /**
736
     * @param array<int, array<string, mixed>> $tables
737
     *
738
     * @return array<int, string>
739
     */
740 314
    protected function _getPortableTablesList(array $tables) : array
741
    {
742 314
        $list = [];
743 314
        foreach ($tables as $value) {
744 292
            $list[] = $this->_getPortableTableDefinition($value);
745
        }
746
747 314
        return $list;
748
    }
749
750
    /**
751
     * @param array<string, string> $table
752
     */
753 132
    protected function _getPortableTableDefinition(array $table) : string
754
    {
755 132
        assert(! empty($table));
756
757 132
        return array_shift($table);
758
    }
759
760
    /**
761
     * @param array<int, array<string, mixed>> $users
762
     *
763
     * @return array<int, array<string, mixed>>
764
     */
765
    protected function _getPortableUsersList(array $users) : array
766
    {
767
        $list = [];
768
        foreach ($users as $value) {
769
            $list[] = $this->_getPortableUserDefinition($value);
770
        }
771
772
        return $list;
773
    }
774
775
    /**
776
     * @param array<string, mixed> $user
777
     *
778
     * @return array<string, mixed>
779
     */
780
    protected function _getPortableUserDefinition(array $user) : array
781
    {
782
        return $user;
783
    }
784
785
    /**
786
     * @param array<int, array<string, mixed>> $views
787
     *
788
     * @return array<string, View>
789
     */
790 22
    protected function _getPortableViewsList(array $views) : array
791
    {
792 22
        $list = [];
793 22
        foreach ($views as $value) {
794 22
            $view        = $this->_getPortableViewDefinition($value);
795 22
            $name        = strtolower($view->getQuotedName($this->_platform));
796 22
            $list[$name] = $view;
797
        }
798
799 22
        return $list;
800
    }
801
802
    /**
803
     * @param array<string, mixed> $view
804
     */
805
    protected function _getPortableViewDefinition(array $view) : View
806
    {
807
        throw NotSupported::new('Views');
808
    }
809
810
    /**
811
     * @param array<int|string, array<string, mixed>> $tableForeignKeys
812
     *
813
     * @return array<int, ForeignKeyConstraint>
814
     */
815 491
    protected function _getPortableTableForeignKeysList(array $tableForeignKeys) : array
816
    {
817 491
        $list = [];
818
819 491
        foreach ($tableForeignKeys as $value) {
820 116
            $list[] = $this->_getPortableTableForeignKeyDefinition($value);
821
        }
822
823 491
        return $list;
824
    }
825
826
    /**
827
     * @param array<string, mixed> $tableForeignKey
828
     */
829
    protected function _getPortableTableForeignKeyDefinition(array $tableForeignKey) : ForeignKeyConstraint
830
    {
831
        throw NotSupported::new('ForeignKey');
832
    }
833
834
    /**
835
     * @param array<int, string>|string $sql
836
     */
837 3532
    protected function _execSql($sql) : void
838
    {
839 3532
        foreach ((array) $sql as $query) {
840 3532
            $this->_conn->executeUpdate($query);
841
        }
842 3179
    }
843
844
    /**
845
     * Creates a schema instance for the current database.
846
     */
847 100
    public function createSchema() : Schema
848
    {
849 100
        $namespaces = [];
850
851 100
        if ($this->_platform->supportsSchemas()) {
852 7
            $namespaces = $this->listNamespaceNames();
853
        }
854
855 100
        $sequences = [];
856
857 100
        if ($this->_platform->supportsSequences()) {
858 8
            $sequences = $this->listSequences();
859
        }
860
861 100
        $tables = $this->listTables();
862
863 100
        return new Schema($tables, $sequences, $this->createSchemaConfig(), $namespaces);
864
    }
865
866
    /**
867
     * Creates the configuration for this schema.
868
     */
869 399
    public function createSchemaConfig() : SchemaConfig
870
    {
871 399
        $schemaConfig = new SchemaConfig();
872 399
        $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength());
873
874 399
        $searchPaths = $this->getSchemaSearchPaths();
875 399
        if (isset($searchPaths[0])) {
876 377
            $schemaConfig->setName($searchPaths[0]);
877
        }
878
879 399
        $params = $this->_conn->getParams();
880 399
        if (! isset($params['defaultTableOptions'])) {
881 399
            $params['defaultTableOptions'] = [];
882
        }
883
884 399
        if (! isset($params['defaultTableOptions']['charset']) && isset($params['charset'])) {
885 22
            $params['defaultTableOptions']['charset'] = $params['charset'];
886
        }
887
888 399
        $schemaConfig->setDefaultTableOptions($params['defaultTableOptions']);
889
890 399
        return $schemaConfig;
891
    }
892
893
    /**
894
     * The search path for namespaces in the currently connected database.
895
     *
896
     * The first entry is usually the default namespace in the Schema. All
897
     * further namespaces contain tables/sequences which can also be addressed
898
     * with a short, not full-qualified name.
899
     *
900
     * For databases that don't support subschema/namespaces this method
901
     * returns the name of the currently connected database.
902
     *
903
     * @return array<int, string>
904
     */
905 324
    public function getSchemaSearchPaths() : array
906
    {
907 324
        $database = $this->_conn->getDatabase();
908
909 324
        if ($database !== null) {
910 302
            return [$database];
911
        }
912
913 22
        return [];
914
    }
915
916
    /**
917
     * Given a table comment this method tries to extract a type hint for Doctrine Type. If the type hint is found,
918
     * it's removed from the comment.
919
     *
920
     * @return string|null The extracted Doctrine type or NULL of the type hint was not found.
921
     */
922 1692
    final protected function extractDoctrineTypeFromComment(?string &$comment) : ?string
923
    {
924 1692
        if ($comment === null || preg_match('/(.*)\(DC2Type:(((?!\)).)+)\)(.*)/', $comment, $match) === 0) {
925 1561
            return null;
926
        }
927
928 377
        $comment = $match[1] . $match[4];
929
930 377
        return $match[2];
931
    }
932
933
    /**
934
     * @throws DatabaseRequired
935
     */
936 1623
    private function ensureDatabase(?string $database, string $methodName) : string
937
    {
938 1623
        if ($database === null) {
939 12
            throw DatabaseRequired::new($methodName);
940
        }
941
942 1611
        return $database;
943
    }
944
}
945