Completed
Pull Request — develop (#3565)
by Jonathan
13:02
created

AbstractSchemaManager::tableExists()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
cc 1
nc 1
nop 1
crap 1
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 call_user_func_array;
24
use function count;
25
use function func_get_args;
26
use function is_array;
27
use function is_callable;
28
use function preg_match;
29
use function strtolower;
30
31
/**
32
 * Base class for schema managers. Schema managers are used to inspect and/or
33
 * modify the database schema/structure.
34
 */
35
abstract class AbstractSchemaManager
36
{
37
    /**
38
     * Holds instance of the Doctrine connection for this schema manager.
39
     *
40
     * @var Connection
41
     */
42
    protected $_conn;
43
44
    /**
45
     * Holds instance of the database platform used for this schema manager.
46
     *
47
     * @var AbstractPlatform
48
     */
49
    protected $_platform;
50
51
    /**
52
     * Constructor. Accepts the Connection instance to manage the schema for.
53
     */
54 5450
    public function __construct(Connection $conn, ?AbstractPlatform $platform = null)
55
    {
56 5450
        $this->_conn     = $conn;
57 5450
        $this->_platform = $platform ?: $this->_conn->getDatabasePlatform();
58 5450
    }
59
60
    /**
61
     * Returns the associated platform.
62
     */
63 3607
    public function getDatabasePlatform() : AbstractPlatform
64
    {
65 3607
        return $this->_platform;
66
    }
67
68
    /**
69
     * Tries any method on the schema manager. Normally a method throws an
70
     * exception when your DBMS doesn't support it or if an error occurs.
71
     * This method allows you to try and method on your SchemaManager
72
     * instance and will return false if it does not work or is not supported.
73
     *
74
     * <code>
75
     * $result = $sm->tryMethod('dropView', 'view_name');
76
     * </code>
77
     *
78
     * @return mixed
79
     */
80 5330
    public function tryMethod()
81
    {
82 5330
        $args   = func_get_args();
83 5330
        $method = $args[0];
84 5330
        unset($args[0]);
85 5330
        $args = array_values($args);
86
87 5330
        $callback = [$this, $method];
88 5330
        assert(is_callable($callback));
89
90
        try {
91 5330
            return call_user_func_array($callback, $args);
92 5316
        } catch (Throwable $e) {
93 5316
            return false;
94
        }
95
    }
96
97
    /**
98
     * Lists the available databases for this connection.
99
     *
100
     * @return array<int, string>
101
     */
102 3062
    public function listDatabases() : array
103
    {
104 3062
        $sql = $this->_platform->getListDatabasesSQL();
105
106 2923
        $databases = $this->_conn->fetchAll($sql);
107
108 2923
        return $this->_getPortableDatabasesList($databases);
109
    }
110
111
    /**
112
     * Returns a list of all namespaces in the current database.
113
     *
114
     * @return array<int, string>
115
     */
116 1065
    public function listNamespaceNames() : array
117
    {
118 1065
        $sql = $this->_platform->getListNamespacesSQL();
119
120 1065
        $namespaces = $this->_conn->fetchAll($sql);
121
122 1065
        return $this->getPortableNamespacesList($namespaces);
123
    }
124
125
    /**
126
     * Lists the available sequences for this connection.
127
     *
128
     * @return array<int, Sequence>
129
     */
130 1094
    public function listSequences(?string $database = null) : array
131
    {
132 1094
        $database = $this->ensureDatabase(
133 1094
            $database ?? $this->_conn->getDatabase(),
134 1094
            __METHOD__
135
        );
136
137 1094
        $sql = $this->_platform->getListSequencesSQL($database);
138
139 1094
        $sequences = $this->_conn->fetchAll($sql);
140
141 1094
        return $this->filterAssetNames($this->_getPortableSequencesList($sequences));
142
    }
143
144
    /**
145
     * Lists the columns for a given table.
146
     *
147
     * In contrast to other libraries and to the old version of Doctrine,
148
     * this column definition does try to contain the 'primary' field for
149
     * the reason that it is not portable across different RDBMS. Use
150
     * {@see listTableIndexes($tableName)} to retrieve the primary key
151
     * of a table. We're a RDBMS specifies more details these are held
152
     * in the platformDetails array.
153
     *
154
     * @return array<string, Column>
155
     */
156 4315
    public function listTableColumns(string $table, ?string $database = null) : array
157
    {
158 4315
        $database = $this->ensureDatabase(
159 4315
            $database ?? $this->_conn->getDatabase(),
160 4315
            __METHOD__
161
        );
162
163 4315
        $sql = $this->_platform->getListTableColumnsSQL($table, $database);
164
165 4315
        $tableColumns = $this->_conn->fetchAll($sql);
166
167 4315
        return $this->_getPortableTableColumnList($table, $database, $tableColumns);
168
    }
169
170
    /**
171
     * Lists the indexes for a given table returning an array of Index instances.
172
     *
173
     * Keys of the portable indexes list are all lower-cased.
174
     *
175
     * @return array<string, Index>
176
     */
177 4014
    public function listTableIndexes(string $table) : array
178
    {
179 4014
        $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
180
181 4014
        $tableIndexes = $this->_conn->fetchAll($sql);
182
183 4014
        return $this->_getPortableTableIndexesList($tableIndexes, $table);
184
    }
185
186
    /**
187
     * Returns true if all the given tables exist.
188
     *
189
     * @param array<int, string> $tableNames
190
     */
191 4734
    public function tablesExist(array $tableNames) : bool
192
    {
193 4734
        $tableNames = array_map('strtolower', $tableNames);
194
195 4734
        return count($tableNames) === count(array_intersect($tableNames, array_map('strtolower', $this->listTableNames())));
196
    }
197
198 4734
    public function tableExists(string $tableName) : bool
199
    {
200 4734
        return $this->tablesExist([$tableName]);
201
    }
202
203
    /**
204
     * Returns a list of all tables in the current database.
205
     *
206
     * @return array<int, string>
207
     */
208 4410
    public function listTableNames() : array
209
    {
210 4410
        $sql = $this->_platform->getListTablesSQL();
211
212 4410
        $tables     = $this->_conn->fetchAll($sql);
213 4410
        $tableNames = $this->_getPortableTablesList($tables);
214
215 4410
        return $this->filterAssetNames($tableNames);
216
    }
217
218
    /**
219
     * Filters asset names if they are configured to return only a subset of all
220
     * the found elements.
221
     *
222
     * @param array<int, mixed> $assetNames
223
     *
224
     * @return array<int, mixed>
225
     */
226 4760
    protected function filterAssetNames(array $assetNames)
227
    {
228 4760
        $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter();
229 4760
        if (! $filter) {
230 4760
            return $assetNames;
231
        }
232
233 1564
        return array_values(array_filter($assetNames, $filter));
234
    }
235
236
    /**
237
     * Lists the tables for this connection.
238
     *
239
     * @return array<int, Table>
240
     */
241 4155
    public function listTables() : array
242
    {
243 4155
        $tableNames = $this->listTableNames();
244
245 4155
        $tables = [];
246 4155
        foreach ($tableNames as $tableName) {
247 4076
            $tables[] = $this->listTableDetails($tableName);
248
        }
249
250 4155
        return $tables;
251
    }
252
253 4303
    public function listTableDetails(string $tableName) : Table
254
    {
255 4303
        $columns     = $this->listTableColumns($tableName);
256 4303
        $foreignKeys = [];
257
258 4303
        if ($this->_platform->supportsForeignKeyConstraints()) {
259 4158
            $foreignKeys = $this->listTableForeignKeys($tableName);
260
        }
261
262 4303
        $indexes = $this->listTableIndexes($tableName);
263
264 4303
        return new Table($tableName, $columns, $indexes, [], $foreignKeys, []);
265
    }
266
267
    /**
268
     * Lists the views this connection has.
269
     *
270
     * @return array<string, View>
271
     */
272 2951
    public function listViews() : array
273
    {
274 2951
        $database = $this->ensureDatabase(
275 2951
            $this->_conn->getDatabase(),
276 2951
            __METHOD__
277
        );
278
279 2951
        $sql   = $this->_platform->getListViewsSQL($database);
280 2951
        $views = $this->_conn->fetchAll($sql);
281
282 2951
        return $this->_getPortableViewsList($views);
283
    }
284
285
    /**
286
     * Lists the foreign keys for the given table.
287
     *
288
     * @return array<int|string, ForeignKeyConstraint>
289
     */
290 4194
    public function listTableForeignKeys(string $table, ?string $database = null) : array
291
    {
292 4194
        if ($database === null) {
293 4194
            $database = $this->_conn->getDatabase();
294
        }
295 4194
        $sql              = $this->_platform->getListTableForeignKeysSQL($table, $database);
296 4194
        $tableForeignKeys = $this->_conn->fetchAll($sql);
297
298 4194
        return $this->_getPortableTableForeignKeysList($tableForeignKeys);
299
    }
300
301
    /* drop*() Methods */
302
303
    /**
304
     * Drops a database.
305
     *
306
     * NOTE: You can not drop the database this SchemaManager is currently connected to.
307
     */
308 4681
    public function dropDatabase(string $database) : void
309
    {
310 4681
        $this->_execSql($this->_platform->getDropDatabaseSQL($database));
311 4123
    }
312
313
    /**
314
     * Drops the given table.
315
     */
316 5310
    public function dropTable(string $tableName) : void
317
    {
318 5310
        $this->_execSql($this->_platform->getDropTableSQL($tableName));
319 5236
    }
320
321
    /**
322
     * Drops the index from the given table.
323
     *
324
     * @param Index|string $index The name of the index.
325
     * @param Table|string $table The name of the table.
326
     */
327 3076
    public function dropIndex($index, $table) : void
328
    {
329 3076
        if ($index instanceof Index) {
330
            $index = $index->getQuotedName($this->_platform);
331
        }
332
333 3076
        $this->_execSql($this->_platform->getDropIndexSQL($index, $table));
334 3076
    }
335
336
    /**
337
     * Drops the constraint from the given table.
338
     *
339
     * @param Table|string $table The name of the table.
340
     */
341
    public function dropConstraint(Constraint $constraint, $table) : void
342
    {
343
        $this->_execSql($this->_platform->getDropConstraintSQL($constraint, $table));
344
    }
345
346
    /**
347
     * Drops a foreign key from a table.
348
     *
349
     * @param ForeignKeyConstraint|string $foreignKey The name of the foreign key.
350
     * @param Table|string                $table      The name of the table with the foreign key.
351
     */
352
    public function dropForeignKey($foreignKey, $table) : void
353
    {
354
        $this->_execSql($this->_platform->getDropForeignKeySQL($foreignKey, $table));
355
    }
356
357
    /**
358
     * Drops a sequence with a given name.
359
     */
360 1091
    public function dropSequence(string $name) : void
361
    {
362 1091
        $this->_execSql($this->_platform->getDropSequenceSQL($name));
363
    }
364
365
    /**
366
     * Drops a view.
367
     */
368 3112
    public function dropView(string $name) : void
369
    {
370 3112
        $this->_execSql($this->_platform->getDropViewSQL($name));
371
    }
372
373
    /* create*() Methods */
374
375
    /**
376
     * Creates a new database.
377
     */
378 4679
    public function createDatabase(string $database) : void
379
    {
380 4679
        $this->_execSql($this->_platform->getCreateDatabaseSQL($database));
381 4679
    }
382
383
    /**
384
     * Creates a new table.
385
     */
386 5328
    public function createTable(Table $table) : void
387
    {
388 5328
        $createFlags = AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS;
389 5328
        $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags));
390 5307
    }
391
392
    /**
393
     * Creates a new sequence.
394
     *
395
     * @throws ConnectionException If something fails at database level.
396
     */
397 1093
    public function createSequence(Sequence $sequence) : void
398
    {
399 1093
        $this->_execSql($this->_platform->getCreateSequenceSQL($sequence));
400 1093
    }
401
402
    /**
403
     * Creates a constraint on a table.
404
     *
405
     * @param Table|string $table
406
     */
407 1
    public function createConstraint(Constraint $constraint, $table) : void
408
    {
409 1
        $this->_execSql($this->_platform->getCreateConstraintSQL($constraint, $table));
410 1
    }
411
412
    /**
413
     * Creates a new index on a table.
414
     *
415
     * @param Table|string $table The name of the table on which the index is to be created.
416
     */
417 3076
    public function createIndex(Index $index, $table) : void
418
    {
419 3076
        $this->_execSql($this->_platform->getCreateIndexSQL($index, $table));
420 3076
    }
421
422
    /**
423
     * Creates a new foreign key.
424
     *
425
     * @param ForeignKeyConstraint $foreignKey The ForeignKey instance.
426
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
427
     */
428 3086
    public function createForeignKey(ForeignKeyConstraint $foreignKey, $table) : void
429
    {
430 3086
        $this->_execSql($this->_platform->getCreateForeignKeySQL($foreignKey, $table));
431 3086
    }
432
433
    /**
434
     * Creates a new view.
435
     */
436 3112
    public function createView(View $view) : void
437
    {
438 3112
        $this->_execSql($this->_platform->getCreateViewSQL($view->getQuotedName($this->_platform), $view->getSql()));
439 3112
    }
440
441
    /* dropAndCreate*() Methods */
442
443
    /**
444
     * Drops and creates a constraint.
445
     *
446
     * @see dropConstraint()
447
     * @see createConstraint()
448
     *
449
     * @param Table|string $table
450
     */
451
    public function dropAndCreateConstraint(Constraint $constraint, $table) : void
452
    {
453
        $this->tryMethod('dropConstraint', $constraint, $table);
454
        $this->createConstraint($constraint, $table);
455
    }
456
457
    /**
458
     * Drops and creates a new index on a table.
459
     *
460
     * @param Table|string $table The name of the table on which the index is to be created.
461
     */
462 3076
    public function dropAndCreateIndex(Index $index, $table) : void
463
    {
464 3076
        $this->tryMethod('dropIndex', $index->getQuotedName($this->_platform), $table);
465 3076
        $this->createIndex($index, $table);
466 3076
    }
467
468
    /**
469
     * Drops and creates a new foreign key.
470
     *
471
     * @param ForeignKeyConstraint $foreignKey An associative array that defines properties of the foreign key to be created.
472
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
473
     */
474
    public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table) : void
475
    {
476
        $this->tryMethod('dropForeignKey', $foreignKey, $table);
477
        $this->createForeignKey($foreignKey, $table);
478
    }
479
480
    /**
481
     * Drops and create a new sequence.
482
     *
483
     * @throws ConnectionException If something fails at database level.
484
     */
485 1091
    public function dropAndCreateSequence(Sequence $sequence) : void
486
    {
487 1091
        $this->tryMethod('dropSequence', $sequence->getQuotedName($this->_platform));
488 1091
        $this->createSequence($sequence);
489 1091
    }
490
491
    /**
492
     * Drops and creates a new table.
493
     */
494 5273
    public function dropAndCreateTable(Table $table) : void
495
    {
496 5273
        $this->tryMethod('dropTable', $table->getQuotedName($this->_platform));
497 5273
        $this->createTable($table);
498 5273
    }
499
500
    /**
501
     * Drops and creates a new database.
502
     */
503 4818
    public function dropAndCreateDatabase(string $database) : void
504
    {
505 4818
        $this->tryMethod('dropDatabase', $database);
506 4818
        $this->createDatabase($database);
507 4818
    }
508
509
    /**
510
     * Drops and creates a new view.
511
     */
512 3112
    public function dropAndCreateView(View $view) : void
513
    {
514 3112
        $this->tryMethod('dropView', $view->getQuotedName($this->_platform));
515 3112
        $this->createView($view);
516 3112
    }
517
518
    /* alterTable() Methods */
519
520
    /**
521
     * Alters an existing tables schema.
522
     */
523 3777
    public function alterTable(TableDiff $tableDiff) : void
524
    {
525 3777
        $queries = $this->_platform->getAlterTableSQL($tableDiff);
526
527 3777
        if (! is_array($queries) || ! count($queries)) {
528 1466
            return;
529
        }
530
531 3777
        foreach ($queries as $ddlQuery) {
532 3777
            $this->_execSql($ddlQuery);
533
        }
534 3777
    }
535
536
    /**
537
     * Renames a given table to another name.
538
     */
539 1
    public function renameTable(string $name, string $newName) : void
540
    {
541 1
        $tableDiff          = new TableDiff($name);
542 1
        $tableDiff->newName = $newName;
543 1
        $this->alterTable($tableDiff);
544 1
    }
545
546
    /**
547
     * Methods for filtering return values of list*() methods to convert
548
     * the native DBMS data definition to a portable Doctrine definition
549
     */
550
551
    /**
552
     * @param array<int, mixed> $databases
553
     *
554
     * @return array<int, string>
555
     */
556 2923
    protected function _getPortableDatabasesList(array $databases) : array
557
    {
558 2923
        $list = [];
559 2923
        foreach ($databases as $value) {
560 2923
            $value = $this->_getPortableDatabaseDefinition($value);
561
562 2923
            if (! $value) {
563
                continue;
564
            }
565
566 2923
            $list[] = $value;
567
        }
568
569 2923
        return $list;
570
    }
571
572
    /**
573
     * Converts a list of namespace names from the native DBMS data definition to a portable Doctrine definition.
574
     *
575
     * @param array<int, array<int, mixed>> $namespaces The list of namespace names in the native DBMS data definition.
576
     *
577
     * @return array<int, string>
578
     */
579 1065
    protected function getPortableNamespacesList(array $namespaces) : array
580
    {
581 1065
        $namespacesList = [];
582
583 1065
        foreach ($namespaces as $namespace) {
584 1065
            $namespacesList[] = $this->getPortableNamespaceDefinition($namespace);
585
        }
586
587 1065
        return $namespacesList;
588
    }
589
590
    /**
591
     * @param array<string, string> $database
592
     */
593
    protected function _getPortableDatabaseDefinition(array $database) : string
594
    {
595
        return array_shift($database);
596
    }
597
598
    /**
599
     * Converts a namespace definition from the native DBMS data definition to a portable Doctrine definition.
600
     *
601
     * @param array<string|int, mixed> $namespace The native DBMS namespace definition.
602
     */
603
    protected function getPortableNamespaceDefinition(array $namespace) : string
604
    {
605
        return array_shift($namespace);
606
    }
607
608
    /**
609
     * @param array<int, array<int, mixed>> $triggers
610
     *
611
     * @return array<int, string>
612
     */
613
    protected function _getPortableTriggersList(array $triggers)
614
    {
615
        $list = [];
616
        foreach ($triggers as $value) {
617
            $value = $this->_getPortableTriggerDefinition($value);
618
619
            if (! $value) {
620
                continue;
621
            }
622
623
            $list[] = $value;
624
        }
625
626
        return $list;
627
    }
628
629
    /**
630
     * @param array<string|int, mixed> $trigger
631
     */
632
    protected function _getPortableTriggerDefinition(array $trigger) : string
633
    {
634
        return array_shift($trigger);
635
    }
636
637
    /**
638
     * @param array<int, array<string, mixed>> $sequences
639
     *
640
     * @return array<int, Sequence>
641
     */
642 277
    protected function _getPortableSequencesList(array $sequences) : array
643
    {
644 277
        $list = [];
645
646 277
        foreach ($sequences as $value) {
647 277
            $list[] = $this->_getPortableSequenceDefinition($value);
648
        }
649
650 277
        return $list;
651
    }
652
653
    /**
654
     * @param array<string, mixed> $sequence
655
     *
656
     * @throws DBALException
657
     */
658
    protected function _getPortableSequenceDefinition(array $sequence) : Sequence
659
    {
660
        throw NotSupported::new('Sequences');
661
    }
662
663
    /**
664
     * Independent of the database the keys of the column list result are lowercased.
665
     *
666
     * The name of the created column instance however is kept in its case.
667
     *
668
     * @param array<int, array<string, mixed>> $tableColumns
669
     *
670
     * @return array<string, Column>
671
     */
672 4315
    protected function _getPortableTableColumnList(string $table, string $database, array $tableColumns) : array
673
    {
674 4315
        $eventManager = $this->_platform->getEventManager();
675
676 4315
        $list = [];
677 4315
        foreach ($tableColumns as $tableColumn) {
678 4315
            $column           = null;
679 4315
            $defaultPrevented = false;
680
681 4315
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaColumnDefinition)) {
682 3176
                $eventArgs = new SchemaColumnDefinitionEventArgs($tableColumn, $table, $database, $this->_conn);
683 3176
                $eventManager->dispatchEvent(Events::onSchemaColumnDefinition, $eventArgs);
684
685 3176
                $defaultPrevented = $eventArgs->isDefaultPrevented();
686 3176
                $column           = $eventArgs->getColumn();
687
            }
688
689 4315
            if (! $defaultPrevented) {
690 4315
                $column = $this->_getPortableTableColumnDefinition($tableColumn);
691
            }
692
693 4315
            if (! $column) {
694
                continue;
695
            }
696
697 4315
            $name        = strtolower($column->getQuotedName($this->_platform));
698 4315
            $list[$name] = $column;
699
        }
700
701 4315
        return $list;
702
    }
703
704
    /**
705
     * Gets Table Column Definition.
706
     *
707
     * @param array<string, mixed> $tableColumn
708
     */
709
    abstract protected function _getPortableTableColumnDefinition(array $tableColumn) : Column;
710
711
    /**
712
     * Aggregates and groups the index results according to the required data result.
713
     *
714
     * @param array<int, array<string, mixed>> $tableIndexRows
715
     *
716
     * @return array<string, Index>
717
     */
718 4308
    protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array
719
    {
720 4308
        $result = [];
721 4308
        foreach ($tableIndexRows as $tableIndex) {
722 4185
            $indexName = $keyName = $tableIndex['key_name'];
723 4185
            if ($tableIndex['primary']) {
724 4183
                $keyName = 'primary';
725
            }
726 4185
            $keyName = strtolower($keyName);
727
728 4185
            if (! isset($result[$keyName])) {
729
                $options = [
730 4185
                    'lengths' => [],
731
                ];
732
733 4185
                if (isset($tableIndex['where'])) {
734 876
                    $options['where'] = $tableIndex['where'];
735
                }
736
737 4185
                $result[$keyName] = [
738 4185
                    'name' => $indexName,
739
                    'columns' => [],
740 4185
                    'unique' => ! $tableIndex['non_unique'],
741 4185
                    'primary' => $tableIndex['primary'],
742 4185
                    'flags' => $tableIndex['flags'] ?? [],
743 4185
                    'options' => $options,
744
                ];
745
            }
746
747 4185
            $result[$keyName]['columns'][]            = $tableIndex['column_name'];
748 4185
            $result[$keyName]['options']['lengths'][] = $tableIndex['length'] ?? null;
749
        }
750
751 4308
        $eventManager = $this->_platform->getEventManager();
752
753 4308
        $indexes = [];
754 4308
        foreach ($result as $indexKey => $data) {
755 4185
            $index            = null;
756 4185
            $defaultPrevented = false;
757
758 4185
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) {
759 3151
                $eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn);
760 3151
                $eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs);
761
762 3151
                $defaultPrevented = $eventArgs->isDefaultPrevented();
763 3151
                $index            = $eventArgs->getIndex();
764
            }
765
766 4185
            if (! $defaultPrevented) {
767 4185
                $index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary'], $data['flags'], $data['options']);
768
            }
769
770 4185
            if (! $index) {
771
                continue;
772
            }
773
774 4185
            $indexes[$indexKey] = $index;
775
        }
776
777 4308
        return $indexes;
778
    }
779
780
    /**
781
     * @param array<int, array<string, mixed>> $tables
782
     *
783
     * @return array<int, string>
784
     */
785 4410
    protected function _getPortableTablesList(array $tables) : array
786
    {
787 4410
        $list = [];
788 4410
        foreach ($tables as $value) {
789 4407
            $value = $this->_getPortableTableDefinition($value);
790
791 4407
            if (! $value) {
792
                continue;
793
            }
794
795 4407
            $list[] = $value;
796
        }
797
798 4410
        return $list;
799
    }
800
801
    /**
802
     * @param array<string, string> $table
803
     */
804
    protected function _getPortableTableDefinition(array $table) : string
805
    {
806
        return array_shift($table);
807
    }
808
809
    /**
810
     * @param array<int, array<string, mixed>> $users
811
     *
812
     * @return array<int, array<string, mixed>>
813
     */
814
    protected function _getPortableUsersList(array $users) : array
815
    {
816
        $list = [];
817
        foreach ($users as $value) {
818
            $value = $this->_getPortableUserDefinition($value);
819
820
            if (! $value) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $value of type array<string,mixed> is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
821
                continue;
822
            }
823
824
            $list[] = $value;
825
        }
826
827
        return $list;
828
    }
829
830
    /**
831
     * @param array<string, mixed> $user
832
     *
833
     * @return array<string, mixed>
834
     */
835
    protected function _getPortableUserDefinition(array $user) : array
836
    {
837
        return $user;
838
    }
839
840
    /**
841
     * @param array<int, array<string, mixed>> $views
842
     *
843
     * @return array<string, View>
844
     */
845 2951
    protected function _getPortableViewsList(array $views) : array
846
    {
847 2951
        $list = [];
848 2951
        foreach ($views as $value) {
849 2951
            $view        = $this->_getPortableViewDefinition($value);
850 2951
            $name        = strtolower($view->getQuotedName($this->_platform));
851 2951
            $list[$name] = $view;
852
        }
853
854 2951
        return $list;
855
    }
856
857
    /**
858
     * @param array<string, mixed> $view
859
     */
860
    protected function _getPortableViewDefinition(array $view) : View
861
    {
862
        throw NotSupported::new('Views');
863
    }
864
865
    /**
866
     * @param array<int|string, array<string, mixed>> $tableForeignKeys
867
     *
868
     * @return array<int, ForeignKeyConstraint>
869
     */
870 1592
    protected function _getPortableTableForeignKeysList(array $tableForeignKeys) : array
871
    {
872 1592
        $list = [];
873
874 1592
        foreach ($tableForeignKeys as $value) {
875 1436
            $list[] = $this->_getPortableTableForeignKeyDefinition($value);
876
        }
877
878 1592
        return $list;
879
    }
880
881
    /**
882
     * @param array<string, mixed> $tableForeignKey
883
     */
884
    protected function _getPortableTableForeignKeyDefinition(array $tableForeignKey) : ForeignKeyConstraint
0 ignored issues
show
Unused Code introduced by
The parameter $tableForeignKey is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

884
    protected function _getPortableTableForeignKeyDefinition(/** @scrutinizer ignore-unused */ array $tableForeignKey) : ForeignKeyConstraint

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
885
    {
886
        throw NotSupported::new('ForeignKey');
887
    }
888
889
    /**
890
     * @param array<int, string>|string $sql
891
     */
892 5359
    protected function _execSql($sql) : void
893
    {
894 5359
        foreach ((array) $sql as $query) {
895 5359
            $this->_conn->executeUpdate($query);
896
        }
897 5332
    }
898
899
    /**
900
     * Creates a schema instance for the current database.
901
     */
902 3982
    public function createSchema() : Schema
903
    {
904 3982
        $namespaces = [];
905
906 3982
        if ($this->_platform->supportsSchemas()) {
907 983
            $namespaces = $this->listNamespaceNames();
908
        }
909
910 3982
        $sequences = [];
911
912 3982
        if ($this->_platform->supportsSequences()) {
913 984
            $sequences = $this->listSequences();
914
        }
915
916 3982
        $tables = $this->listTables();
917
918 3982
        return new Schema($tables, $sequences, $this->createSchemaConfig(), $namespaces);
919
    }
920
921
    /**
922
     * Creates the configuration for this schema.
923
     */
924 4209
    public function createSchemaConfig() : SchemaConfig
925
    {
926 4209
        $schemaConfig = new SchemaConfig();
927 4209
        $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength());
928
929 4209
        $searchPaths = $this->getSchemaSearchPaths();
930 4209
        if (isset($searchPaths[0])) {
931 4208
            $schemaConfig->setName($searchPaths[0]);
932
        }
933
934 4209
        $params = $this->_conn->getParams();
935 4209
        if (! isset($params['defaultTableOptions'])) {
936 4209
            $params['defaultTableOptions'] = [];
937
        }
938 4209
        if (! isset($params['defaultTableOptions']['charset']) && isset($params['charset'])) {
939 851
            $params['defaultTableOptions']['charset'] = $params['charset'];
940
        }
941 4209
        $schemaConfig->setDefaultTableOptions($params['defaultTableOptions']);
942
943 4209
        return $schemaConfig;
944
    }
945
946
    /**
947
     * The search path for namespaces in the currently connected database.
948
     *
949
     * The first entry is usually the default namespace in the Schema. All
950
     * further namespaces contain tables/sequences which can also be addressed
951
     * with a short, not full-qualified name.
952
     *
953
     * For databases that don't support subschema/namespaces this method
954
     * returns the name of the currently connected database.
955
     *
956
     * @return array<int, string>
957
     */
958 3501
    public function getSchemaSearchPaths() : array
959
    {
960 3501
        return [$this->_conn->getDatabase()];
961
    }
962
963
    /**
964
     * Given a table comment this method tries to extract a type hint for Doctrine Type. If the type hint is found,
965
     * it's removed from the comment.
966
     *
967
     * @return string|null The extracted Doctrine type or NULL of the type hint was not found.
968
     */
969 4322
    final protected function extractDoctrineTypeFromComment(?string &$comment) : ?string
970
    {
971 4322
        if ($comment === null || ! preg_match('/(.*)\(DC2Type:(((?!\)).)+)\)(.*)/', $comment, $match)) {
972 4317
            return null;
973
        }
974
975 3325
        $comment = $match[1] . $match[4];
976
977 3325
        return $match[2];
978
    }
979
980
    /**
981
     * @throws DatabaseRequired
982
     */
983 4320
    private function ensureDatabase(?string $database, string $methodName) : string
984
    {
985 4320
        if ($database === null) {
986 1838
            throw DatabaseRequired::new($methodName);
987
        }
988
989 4320
        return $database;
990
    }
991
}
992