Completed
Pull Request — develop (#3348)
by Sergei
114:01 queued 50:53
created

AbstractSchemaManager::ensureDatabase()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

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