Failed Conditions
Push — develop ( c067f0...c4478a )
by Sergei
10:16
created

AbstractSchemaManager::getPortableNamespacesList()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 9
ccs 5
cts 5
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
namespace Doctrine\DBAL\Schema;
4
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\ConnectionException;
7
use Doctrine\DBAL\DBALException;
8
use Doctrine\DBAL\Event\SchemaColumnDefinitionEventArgs;
9
use Doctrine\DBAL\Event\SchemaIndexDefinitionEventArgs;
10
use Doctrine\DBAL\Events;
11
use Doctrine\DBAL\Platforms\AbstractPlatform;
12
use Throwable;
13
use function array_filter;
14
use function array_intersect;
15
use function array_map;
16
use function array_values;
17
use function call_user_func_array;
18
use function count;
19
use function func_get_args;
20
use function is_array;
21
use function preg_match;
22
use function str_replace;
23
use function strtolower;
24
25
/**
26
 * Base class for schema managers. Schema managers are used to inspect and/or
27
 * modify the database schema/structure.
28
 */
29
abstract class AbstractSchemaManager
30
{
31
    /**
32
     * Holds instance of the Doctrine connection for this schema manager.
33
     *
34
     * @var Connection
35
     */
36
    protected $_conn;
37
38
    /**
39
     * Holds instance of the database platform used for this schema manager.
40
     *
41
     * @var AbstractPlatform
42
     */
43
    protected $_platform;
44
45
    /**
46
     * Constructor. Accepts the Connection instance to manage the schema for.
47
     */
48 1314
    public function __construct(Connection $conn, ?AbstractPlatform $platform = null)
49
    {
50 1314
        $this->_conn     = $conn;
51 1314
        $this->_platform = $platform ?: $this->_conn->getDatabasePlatform();
52 1314
    }
53
54
    /**
55
     * Returns the associated platform.
56
     *
57
     * @return AbstractPlatform
58
     */
59 366
    public function getDatabasePlatform()
60
    {
61 366
        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
     * @return mixed
75
     */
76 1853
    public function tryMethod()
77
    {
78 1853
        $args   = func_get_args();
79 1853
        $method = $args[0];
80 1853
        unset($args[0]);
81 1853
        $args = array_values($args);
82
83
        try {
84 1853
            return call_user_func_array([$this, $method], $args);
85 1403
        } catch (Throwable $e) {
86 1403
            return false;
87
        }
88
    }
89
90
    /**
91
     * Lists the available databases for this connection.
92
     *
93
     * @return string[]
94
     */
95 36
    public function listDatabases()
96
    {
97 36
        $sql = $this->_platform->getListDatabasesSQL();
98
99 34
        $databases = $this->_conn->fetchAll($sql);
100
101 34
        return $this->_getPortableDatabasesList($databases);
102
    }
103
104
    /**
105
     * Returns a list of all namespaces in the current database.
106
     *
107
     * @return string[]
108
     */
109 14
    public function listNamespaceNames()
110
    {
111 14
        $sql = $this->_platform->getListNamespacesSQL();
112
113 14
        $namespaces = $this->_conn->fetchAll($sql);
114
115 14
        return $this->getPortableNamespacesList($namespaces);
116
    }
117
118
    /**
119
     * Lists the available sequences for this connection.
120
     *
121
     * @param string|null $database
122
     *
123
     * @return Sequence[]
124
     */
125 52
    public function listSequences($database = null)
126
    {
127 52
        if ($database === null) {
128 52
            $database = $this->_conn->getDatabase();
129
        }
130 52
        $sql = $this->_platform->getListSequencesSQL($database);
131
132 52
        $sequences = $this->_conn->fetchAll($sql);
133
134 52
        return $this->filterAssetNames($this->_getPortableSequencesList($sequences));
135
    }
136
137
    /**
138
     * Lists the columns for a given table.
139
     *
140
     * In contrast to other libraries and to the old version of Doctrine,
141
     * this column definition does try to contain the 'primary' field for
142
     * the reason that it is not portable across different RDBMS. Use
143
     * {@see listTableIndexes($tableName)} to retrieve the primary key
144
     * of a table. We're a RDBMS specifies more details these are held
145
     * in the platformDetails array.
146
     *
147
     * @param string      $table    The name of the table.
148
     * @param string|null $database
149
     *
150
     * @return Column[]
151
     */
152 893
    public function listTableColumns($table, $database = null)
153
    {
154 893
        if (! $database) {
155 891
            $database = $this->_conn->getDatabase();
156
        }
157
158 893
        $sql = $this->_platform->getListTableColumnsSQL($table, $database);
159
160 893
        $tableColumns = $this->_conn->fetchAll($sql);
161
162 893
        return $this->_getPortableTableColumnList($table, $database, $tableColumns);
163
    }
164
165
    /**
166
     * Lists the indexes for a given table returning an array of Index instances.
167
     *
168
     * Keys of the portable indexes list are all lower-cased.
169
     *
170
     * @param string $table The name of the table.
171
     *
172
     * @return Index[]
173
     */
174 671
    public function listTableIndexes($table)
175
    {
176 671
        $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
177
178 671
        $tableIndexes = $this->_conn->fetchAll($sql);
179
180 671
        return $this->_getPortableTableIndexesList($tableIndexes, $table);
181
    }
182
183
    /**
184
     * Returns true if all the given tables exist.
185
     *
186
     * @param string[] $tableNames
187
     *
188
     * @return bool
189
     */
190 1406
    public function tablesExist($tableNames)
191
    {
192 1406
        $tableNames = array_map('strtolower', (array) $tableNames);
193
194 1406
        return count($tableNames) === count(array_intersect($tableNames, array_map('strtolower', $this->listTableNames())));
195
    }
196
197
    /**
198
     * Returns a list of all tables in the current database.
199
     *
200
     * @return string[]
201
     */
202 1463
    public function listTableNames()
203
    {
204 1463
        $sql = $this->_platform->getListTablesSQL();
205
206 1463
        $tables     = $this->_conn->fetchAll($sql);
207 1463
        $tableNames = $this->_getPortableTablesList($tables);
208
209 1463
        return $this->filterAssetNames($tableNames);
210
    }
211
212
    /**
213
     * Filters asset names if they are configured to return only a subset of all
214
     * the found elements.
215
     *
216
     * @param mixed[] $assetNames
217
     *
218
     * @return mixed[]
219
     */
220 1472
    protected function filterAssetNames($assetNames)
221
    {
222 1472
        $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter();
223 1472
        if (! $filter) {
224 1472
            return $assetNames;
225
        }
226
227 5
        return array_values(array_filter($assetNames, $filter));
228
    }
229
230
    /**
231
     * @deprecated Use Configuration::getSchemaAssetsFilter() instead
232
     *
233
     * @return string|null
234
     */
235
    protected function getFilterSchemaAssetsExpression()
236
    {
237
        return $this->_conn->getConfiguration()->getFilterSchemaAssetsExpression();
1 ignored issue
show
Deprecated Code introduced by
The function Doctrine\DBAL\Configurat...chemaAssetsExpression() has been deprecated: Use Configuration::getSchemaAssetsFilter() instead ( Ignorable by Annotation )

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

237
        return /** @scrutinizer ignore-deprecated */ $this->_conn->getConfiguration()->getFilterSchemaAssetsExpression();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
238
    }
239
240
    /**
241
     * Lists the tables for this connection.
242
     *
243
     * @return Table[]
244
     */
245 102
    public function listTables()
246
    {
247 102
        $tableNames = $this->listTableNames();
248
249 102
        $tables = [];
250 102
        foreach ($tableNames as $tableName) {
251 83
            $tables[] = $this->listTableDetails($tableName);
252
        }
253
254 102
        return $tables;
255
    }
256
257
    /**
258
     * @param string $tableName
259
     *
260
     * @return Table
261
     */
262 624
    public function listTableDetails($tableName)
263
    {
264 624
        $columns     = $this->listTableColumns($tableName);
265 624
        $foreignKeys = [];
266
267 624
        if ($this->_platform->supportsForeignKeyConstraints()) {
268 532
            $foreignKeys = $this->listTableForeignKeys($tableName);
269
        }
270
271 624
        $indexes = $this->listTableIndexes($tableName);
272
273 624
        return new Table($tableName, $columns, $indexes, [], $foreignKeys, []);
274
    }
275
276
    /**
277
     * Lists the views this connection has.
278
     *
279
     * @return View[]
280
     */
281 19
    public function listViews()
282
    {
283 19
        $database = $this->_conn->getDatabase();
284 19
        $sql      = $this->_platform->getListViewsSQL($database);
285 19
        $views    = $this->_conn->fetchAll($sql);
286
287 19
        return $this->_getPortableViewsList($views);
288
    }
289
290
    /**
291
     * Lists the foreign keys for the given table.
292
     *
293
     * @param string      $table    The name of the table.
294
     * @param string|null $database
295
     *
296
     * @return ForeignKeyConstraint[]
297
     */
298 592
    public function listTableForeignKeys($table, $database = null)
299
    {
300 592
        if ($database === null) {
301 592
            $database = $this->_conn->getDatabase();
302
        }
303 592
        $sql              = $this->_platform->getListTableForeignKeysSQL($table, $database);
0 ignored issues
show
Unused Code introduced by
The call to Doctrine\DBAL\Platforms\...stTableForeignKeysSQL() has too many arguments starting with $database. ( Ignorable by Annotation )

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

303
        /** @scrutinizer ignore-call */ 
304
        $sql              = $this->_platform->getListTableForeignKeysSQL($table, $database);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
304 592
        $tableForeignKeys = $this->_conn->fetchAll($sql);
305
306 592
        return $this->_getPortableTableForeignKeysList($tableForeignKeys);
307
    }
308
309
    /* drop*() Methods */
310
311
    /**
312
     * Drops a database.
313
     *
314
     * NOTE: You can not drop the database this SchemaManager is currently connected to.
315
     *
316
     * @param string $database The name of the database to drop.
317
     *
318
     * @return void
319
     */
320 34
    public function dropDatabase($database)
321
    {
322 34
        $this->_execSql($this->_platform->getDropDatabaseSQL($database));
323 23
    }
324
325
    /**
326
     * Drops the given table.
327
     *
328
     * @param string $tableName The name of the table to drop.
329
     *
330
     * @return void
331
     */
332 2092
    public function dropTable($tableName)
333
    {
334 2092
        $this->_execSql($this->_platform->getDropTableSQL($tableName));
335 1037
    }
336
337
    /**
338
     * Drops the index from the given table.
339
     *
340
     * @param Index|string $index The name of the index.
341
     * @param Table|string $table The name of the table.
342
     *
343
     * @return void
344
     */
345 19
    public function dropIndex($index, $table)
346
    {
347 19
        if ($index instanceof Index) {
348
            $index = $index->getQuotedName($this->_platform);
349
        }
350
351 19
        $this->_execSql($this->_platform->getDropIndexSQL($index, $table));
352 19
    }
353
354
    /**
355
     * Drops the constraint from the given table.
356
     *
357
     * @param Table|string $table The name of the table.
358
     *
359
     * @return void
360
     */
361
    public function dropConstraint(Constraint $constraint, $table)
362
    {
363
        $this->_execSql($this->_platform->getDropConstraintSQL($constraint, $table));
364
    }
365
366
    /**
367
     * Drops a foreign key from a table.
368
     *
369
     * @param ForeignKeyConstraint|string $foreignKey The name of the foreign key.
370
     * @param Table|string                $table      The name of the table with the foreign key.
371
     *
372
     * @return void
373
     */
374
    public function dropForeignKey($foreignKey, $table)
375
    {
376
        $this->_execSql($this->_platform->getDropForeignKeySQL($foreignKey, $table));
377
    }
378
379
    /**
380
     * Drops a sequence with a given name.
381
     *
382
     * @param string $name The name of the sequence to drop.
383
     *
384
     * @return void
385
     */
386 18
    public function dropSequence($name)
387
    {
388 18
        $this->_execSql($this->_platform->getDropSequenceSQL($name));
389
    }
390
391
    /**
392
     * Drops a view.
393
     *
394
     * @param string $name The name of the view.
395
     *
396
     * @return void
397
     */
398 24
    public function dropView($name)
399
    {
400 24
        $this->_execSql($this->_platform->getDropViewSQL($name));
401
    }
402
403
    /* create*() Methods */
404
405
    /**
406
     * Creates a new database.
407
     *
408
     * @param string $database The name of the database to create.
409
     *
410
     * @return void
411
     */
412 30
    public function createDatabase($database)
413
    {
414 30
        $this->_execSql($this->_platform->getCreateDatabaseSQL($database));
415 30
    }
416
417
    /**
418
     * Creates a new table.
419
     *
420
     * @return void
421
     */
422 2725
    public function createTable(Table $table)
423
    {
424 2725
        $createFlags = AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS;
425 2725
        $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags));
426 2035
    }
427
428
    /**
429
     * Creates a new sequence.
430
     *
431
     * @param Sequence $sequence
432
     *
433
     * @return void
434
     *
435
     * @throws ConnectionException If something fails at database level.
436
     */
437 43
    public function createSequence($sequence)
438
    {
439 43
        $this->_execSql($this->_platform->getCreateSequenceSQL($sequence));
440 38
    }
441
442
    /**
443
     * Creates a constraint on a table.
444
     *
445
     * @param Table|string $table
446
     *
447
     * @return void
448
     */
449 2
    public function createConstraint(Constraint $constraint, $table)
450
    {
451 2
        $this->_execSql($this->_platform->getCreateConstraintSQL($constraint, $table));
452 2
    }
453
454
    /**
455
     * Creates a new index on a table.
456
     *
457
     * @param Table|string $table The name of the table on which the index is to be created.
458
     *
459
     * @return void
460
     */
461 19
    public function createIndex(Index $index, $table)
462
    {
463 19
        $this->_execSql($this->_platform->getCreateIndexSQL($index, $table));
464 19
    }
465
466
    /**
467
     * Creates a new foreign key.
468
     *
469
     * @param ForeignKeyConstraint $foreignKey The ForeignKey instance.
470
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
471
     *
472
     * @return void
473
     */
474 34
    public function createForeignKey(ForeignKeyConstraint $foreignKey, $table)
475
    {
476 34
        $this->_execSql($this->_platform->getCreateForeignKeySQL($foreignKey, $table));
477 34
    }
478
479
    /**
480
     * Creates a new view.
481
     *
482
     * @return void
483
     */
484 24
    public function createView(View $view)
485
    {
486 24
        $this->_execSql($this->_platform->getCreateViewSQL($view->getQuotedName($this->_platform), $view->getSql()));
487 24
    }
488
489
    /* dropAndCreate*() Methods */
490
491
    /**
492
     * Drops and creates a constraint.
493
     *
494
     * @see dropConstraint()
495
     * @see createConstraint()
496
     *
497
     * @param Table|string $table
498
     *
499
     * @return void
500
     */
501
    public function dropAndCreateConstraint(Constraint $constraint, $table)
502
    {
503
        $this->tryMethod('dropConstraint', $constraint, $table);
504
        $this->createConstraint($constraint, $table);
505
    }
506
507
    /**
508
     * Drops and creates a new index on a table.
509
     *
510
     * @param Table|string $table The name of the table on which the index is to be created.
511
     *
512
     * @return void
513
     */
514 19
    public function dropAndCreateIndex(Index $index, $table)
515
    {
516 19
        $this->tryMethod('dropIndex', $index->getQuotedName($this->_platform), $table);
517 19
        $this->createIndex($index, $table);
518 19
    }
519
520
    /**
521
     * Drops and creates a new foreign key.
522
     *
523
     * @param ForeignKeyConstraint $foreignKey An associative array that defines properties of the foreign key to be created.
524
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
525
     *
526
     * @return void
527
     */
528
    public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table)
529
    {
530
        $this->tryMethod('dropForeignKey', $foreignKey, $table);
531
        $this->createForeignKey($foreignKey, $table);
532
    }
533
534
    /**
535
     * Drops and create a new sequence.
536
     *
537
     * @return void
538
     *
539
     * @throws ConnectionException If something fails at database level.
540
     */
541 18
    public function dropAndCreateSequence(Sequence $sequence)
542
    {
543 18
        $this->tryMethod('dropSequence', $sequence->getQuotedName($this->_platform));
544 18
        $this->createSequence($sequence);
545 18
    }
546
547
    /**
548
     * Drops and creates a new table.
549
     *
550
     * @return void
551
     */
552 1255
    public function dropAndCreateTable(Table $table)
553
    {
554 1255
        $this->tryMethod('dropTable', $table->getQuotedName($this->_platform));
555 1255
        $this->createTable($table);
556 1255
    }
557
558
    /**
559
     * Drops and creates a new database.
560
     *
561
     * @param string $database The name of the database to create.
562
     *
563
     * @return void
564
     */
565 36
    public function dropAndCreateDatabase($database)
566
    {
567 36
        $this->tryMethod('dropDatabase', $database);
568 36
        $this->createDatabase($database);
569 36
    }
570
571
    /**
572
     * Drops and creates a new view.
573
     *
574
     * @return void
575
     */
576 24
    public function dropAndCreateView(View $view)
577
    {
578 24
        $this->tryMethod('dropView', $view->getQuotedName($this->_platform));
579 24
        $this->createView($view);
580 24
    }
581
582
    /* alterTable() Methods */
583
584
    /**
585
     * Alters an existing tables schema.
586
     *
587
     * @return void
588
     */
589 343
    public function alterTable(TableDiff $tableDiff)
590
    {
591 343
        $queries = $this->_platform->getAlterTableSQL($tableDiff);
592
593 343
        if (! is_array($queries) || ! count($queries)) {
594 6
            return;
595
        }
596
597 337
        foreach ($queries as $ddlQuery) {
598 337
            $this->_execSql($ddlQuery);
599
        }
600 337
    }
601
602
    /**
603
     * Renames a given table to another name.
604
     *
605
     * @param string $name    The current name of the table.
606
     * @param string $newName The new name of the table.
607
     *
608
     * @return void
609
     */
610 2
    public function renameTable($name, $newName)
611
    {
612 2
        $tableDiff          = new TableDiff($name);
613 2
        $tableDiff->newName = $newName;
614 2
        $this->alterTable($tableDiff);
615 2
    }
616
617
    /**
618
     * Methods for filtering return values of list*() methods to convert
619
     * the native DBMS data definition to a portable Doctrine definition
620
     */
621
622
    /**
623
     * @param mixed[] $databases
624
     *
625
     * @return string[]
626
     */
627 34
    protected function _getPortableDatabasesList($databases)
628
    {
629 34
        $list = [];
630 34
        foreach ($databases as $value) {
631 34
            $value = $this->_getPortableDatabaseDefinition($value);
632
633 34
            if (! $value) {
634
                continue;
635
            }
636
637 34
            $list[] = $value;
638
        }
639
640 34
        return $list;
641
    }
642
643
    /**
644
     * Converts a list of namespace names from the native DBMS data definition to a portable Doctrine definition.
645
     *
646
     * @param mixed[][] $namespaces The list of namespace names in the native DBMS data definition.
647
     *
648
     * @return string[]
649
     */
650 14
    protected function getPortableNamespacesList(array $namespaces)
651
    {
652 14
        $namespacesList = [];
653
654 14
        foreach ($namespaces as $namespace) {
655 14
            $namespacesList[] = $this->getPortableNamespaceDefinition($namespace);
656
        }
657
658 14
        return $namespacesList;
659
    }
660
661
    /**
662
     * @param mixed $database
663
     *
664
     * @return mixed
665
     */
666
    protected function _getPortableDatabaseDefinition($database)
667
    {
668
        return $database;
669
    }
670
671
    /**
672
     * Converts a namespace definition from the native DBMS data definition to a portable Doctrine definition.
673
     *
674
     * @param mixed[] $namespace The native DBMS namespace definition.
675
     *
676
     * @return mixed
677
     */
678
    protected function getPortableNamespaceDefinition(array $namespace)
679
    {
680
        return $namespace;
681
    }
682
683
    /**
684
     * @param mixed[][] $functions
685
     *
686
     * @return mixed[][]
687
     */
688
    protected function _getPortableFunctionsList($functions)
689
    {
690
        $list = [];
691
        foreach ($functions as $value) {
692
            $value = $this->_getPortableFunctionDefinition($value);
693
694
            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...
695
                continue;
696
            }
697
698
            $list[] = $value;
699
        }
700
701
        return $list;
702
    }
703
704
    /**
705
     * @param mixed[] $function
706
     *
707
     * @return mixed
708
     */
709
    protected function _getPortableFunctionDefinition($function)
710
    {
711
        return $function;
712
    }
713
714
    /**
715
     * @param mixed[][] $triggers
716
     *
717
     * @return mixed[][]
718
     */
719
    protected function _getPortableTriggersList($triggers)
720
    {
721
        $list = [];
722
        foreach ($triggers as $value) {
723
            $value = $this->_getPortableTriggerDefinition($value);
724
725
            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...
726
                continue;
727
            }
728
729
            $list[] = $value;
730
        }
731
732
        return $list;
733
    }
734
735
    /**
736
     * @param mixed[] $trigger
737
     *
738
     * @return mixed
739
     */
740
    protected function _getPortableTriggerDefinition($trigger)
741
    {
742
        return $trigger;
743
    }
744
745
    /**
746
     * @param mixed[][] $sequences
747
     *
748
     * @return Sequence[]
749
     */
750 22
    protected function _getPortableSequencesList($sequences)
751
    {
752 22
        $list = [];
753 22
        foreach ($sequences as $value) {
754 22
            $value = $this->_getPortableSequenceDefinition($value);
755
756 22
            if (! $value) {
757
                continue;
758
            }
759
760 22
            $list[] = $value;
761
        }
762
763 22
        return $list;
764
    }
765
766
    /**
767
     * @param mixed[] $sequence
768
     *
769
     * @return Sequence
770
     *
771
     * @throws DBALException
772
     */
773
    protected function _getPortableSequenceDefinition($sequence)
774
    {
775
        throw DBALException::notSupported('Sequences');
776
    }
777
778
    /**
779
     * Independent of the database the keys of the column list result are lowercased.
780
     *
781
     * The name of the created column instance however is kept in its case.
782
     *
783
     * @param string    $table        The name of the table.
784
     * @param string    $database
785
     * @param mixed[][] $tableColumns
786
     *
787
     * @return Column[]
788
     */
789 893
    protected function _getPortableTableColumnList($table, $database, $tableColumns)
790
    {
791 893
        $eventManager = $this->_platform->getEventManager();
792
793 893
        $list = [];
794 893
        foreach ($tableColumns as $tableColumn) {
795 893
            $column           = null;
796 893
            $defaultPrevented = false;
797
798 893
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaColumnDefinition)) {
799 19
                $eventArgs = new SchemaColumnDefinitionEventArgs($tableColumn, $table, $database, $this->_conn);
800 19
                $eventManager->dispatchEvent(Events::onSchemaColumnDefinition, $eventArgs);
801
802 19
                $defaultPrevented = $eventArgs->isDefaultPrevented();
803 19
                $column           = $eventArgs->getColumn();
804
            }
805
806 893
            if (! $defaultPrevented) {
807 893
                $column = $this->_getPortableTableColumnDefinition($tableColumn);
808
            }
809
810 893
            if (! $column) {
811
                continue;
812
            }
813
814 893
            $name        = strtolower($column->getQuotedName($this->_platform));
815 893
            $list[$name] = $column;
816
        }
817
818 893
        return $list;
819
    }
820
821
    /**
822
     * Gets Table Column Definition.
823
     *
824
     * @param mixed[] $tableColumn
825
     *
826
     * @return Column
827
     */
828
    abstract protected function _getPortableTableColumnDefinition($tableColumn);
829
830
    /**
831
     * Aggregates and groups the index results according to the required data result.
832
     *
833
     * @param mixed[][]   $tableIndexRows
834
     * @param string|null $tableName
835
     *
836
     * @return Index[]
837
     */
838 727
    protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null)
839
    {
840 727
        $result = [];
841 727
        foreach ($tableIndexRows as $tableIndex) {
842 425
            $indexName = $keyName = $tableIndex['key_name'];
843 425
            if ($tableIndex['primary']) {
844 370
                $keyName = 'primary';
845
            }
846 425
            $keyName = strtolower($keyName);
847
848 425
            if (! isset($result[$keyName])) {
849 425
                $result[$keyName] = [
850 425
                    'name' => $indexName,
851 425
                    'columns' => [$tableIndex['column_name']],
852 425
                    'unique' => $tableIndex['non_unique'] ? false : true,
853 425
                    'primary' => $tableIndex['primary'],
854 425
                    'flags' => $tableIndex['flags'] ?? [],
855 425
                    'options' => isset($tableIndex['where']) ? ['where' => $tableIndex['where']] : [],
856
                ];
857
            } else {
858 425
                $result[$keyName]['columns'][] = $tableIndex['column_name'];
859
            }
860
        }
861
862 727
        $eventManager = $this->_platform->getEventManager();
863
864 727
        $indexes = [];
865 727
        foreach ($result as $indexKey => $data) {
866 425
            $index            = null;
867 425
            $defaultPrevented = false;
868
869 425
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) {
870 19
                $eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn);
871 19
                $eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs);
872
873 19
                $defaultPrevented = $eventArgs->isDefaultPrevented();
874 19
                $index            = $eventArgs->getIndex();
875
            }
876
877 425
            if (! $defaultPrevented) {
878 425
                $index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary'], $data['flags'], $data['options']);
879
            }
880
881 425
            if (! $index) {
882
                continue;
883
            }
884
885 425
            $indexes[$indexKey] = $index;
886
        }
887
888 727
        return $indexes;
889
    }
890
891
    /**
892
     * @param mixed[][] $tables
893
     *
894
     * @return string[]
895
     */
896 1463
    protected function _getPortableTablesList($tables)
897
    {
898 1463
        $list = [];
899 1463
        foreach ($tables as $value) {
900 1444
            $value = $this->_getPortableTableDefinition($value);
901
902 1444
            if (! $value) {
903
                continue;
904
            }
905
906 1444
            $list[] = $value;
907
        }
908
909 1463
        return $list;
910
    }
911
912
    /**
913
     * @param mixed $table
914
     *
915
     * @return string
916
     */
917
    protected function _getPortableTableDefinition($table)
918
    {
919
        return $table;
920
    }
921
922
    /**
923
     * @param mixed[][] $users
924
     *
925
     * @return string[][]
926
     */
927
    protected function _getPortableUsersList($users)
928
    {
929
        $list = [];
930
        foreach ($users as $value) {
931
            $value = $this->_getPortableUserDefinition($value);
932
933
            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...
934
                continue;
935
            }
936
937
            $list[] = $value;
938
        }
939
940
        return $list;
941
    }
942
943
    /**
944
     * @param mixed[] $user
945
     *
946
     * @return mixed[]
947
     */
948
    protected function _getPortableUserDefinition($user)
949
    {
950
        return $user;
951
    }
952
953
    /**
954
     * @param mixed[][] $views
955
     *
956
     * @return View[]
957
     */
958 19
    protected function _getPortableViewsList($views)
959
    {
960 19
        $list = [];
961 19
        foreach ($views as $value) {
962 19
            $view = $this->_getPortableViewDefinition($value);
963
964 19
            if (! $view) {
965
                continue;
966
            }
967
968 19
            $viewName        = strtolower($view->getQuotedName($this->_platform));
969 19
            $list[$viewName] = $view;
970
        }
971
972 19
        return $list;
973
    }
974
975
    /**
976
     * @param mixed[] $view
977
     *
978
     * @return View|false
979
     */
980
    protected function _getPortableViewDefinition($view)
981
    {
982
        return false;
983
    }
984
985
    /**
986
     * @param mixed[][] $tableForeignKeys
987
     *
988
     * @return ForeignKeyConstraint[]
989
     */
990 265
    protected function _getPortableTableForeignKeysList($tableForeignKeys)
991
    {
992 265
        $list = [];
993 265
        foreach ($tableForeignKeys as $value) {
994 86
            $value = $this->_getPortableTableForeignKeyDefinition($value);
995
996 86
            if (! $value) {
997
                continue;
998
            }
999
1000 86
            $list[] = $value;
1001
        }
1002
1003 265
        return $list;
1004
    }
1005
1006
    /**
1007
     * @param mixed $tableForeignKey
1008
     *
1009
     * @return ForeignKeyConstraint
1010
     */
1011
    protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
1012
    {
1013
        return $tableForeignKey;
1014
    }
1015
1016
    /**
1017
     * @param string[]|string $sql
1018
     *
1019
     * @return void
1020
     */
1021 2992
    protected function _execSql($sql)
1022
    {
1023 2992
        foreach ((array) $sql as $query) {
1024 2992
            $this->_conn->executeUpdate($query);
1025
        }
1026 2126
    }
1027
1028
    /**
1029
     * Creates a schema instance for the current database.
1030
     *
1031
     * @return Schema
1032
     */
1033 76
    public function createSchema()
1034
    {
1035 76
        $namespaces = [];
1036
1037 76
        if ($this->_platform->supportsSchemas()) {
1038 7
            $namespaces = $this->listNamespaceNames();
1039
        }
1040
1041 76
        $sequences = [];
1042
1043 76
        if ($this->_platform->supportsSequences()) {
1044 9
            $sequences = $this->listSequences();
1045
        }
1046
1047 76
        $tables = $this->listTables();
1048
1049 76
        return new Schema($tables, $sequences, $this->createSchemaConfig(), $namespaces);
1050
    }
1051
1052
    /**
1053
     * Creates the configuration for this schema.
1054
     *
1055
     * @return SchemaConfig
1056
     */
1057 329
    public function createSchemaConfig()
1058
    {
1059 329
        $schemaConfig = new SchemaConfig();
1060 329
        $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength());
1061
1062 329
        $searchPaths = $this->getSchemaSearchPaths();
1063 329
        if (isset($searchPaths[0])) {
1064 233
            $schemaConfig->setName($searchPaths[0]);
1065
        }
1066
1067 329
        $params = $this->_conn->getParams();
1068 329
        if (! isset($params['defaultTableOptions'])) {
1069 329
            $params['defaultTableOptions'] = [];
1070
        }
1071 329
        if (! isset($params['defaultTableOptions']['charset']) && isset($params['charset'])) {
1072 19
            $params['defaultTableOptions']['charset'] = $params['charset'];
1073
        }
1074 329
        $schemaConfig->setDefaultTableOptions($params['defaultTableOptions']);
1075
1076 329
        return $schemaConfig;
1077
    }
1078
1079
    /**
1080
     * The search path for namespaces in the currently connected database.
1081
     *
1082
     * The first entry is usually the default namespace in the Schema. All
1083
     * further namespaces contain tables/sequences which can also be addressed
1084
     * with a short, not full-qualified name.
1085
     *
1086
     * For databases that don't support subschema/namespaces this method
1087
     * returns the name of the currently connected database.
1088
     *
1089
     * @return string[]
1090
     */
1091 254
    public function getSchemaSearchPaths()
1092
    {
1093 254
        return [$this->_conn->getDatabase()];
1094
    }
1095
1096
    /**
1097
     * Given a table comment this method tries to extract a typehint for Doctrine Type, or returns
1098
     * the type given as default.
1099
     *
1100
     * @param string $comment
1101
     * @param string $currentType
1102
     *
1103
     * @return string
1104
     */
1105 944
    public function extractDoctrineTypeFromComment($comment, $currentType)
1106
    {
1107 944
        if (preg_match('(\(DC2Type:(((?!\)).)+)\))', $comment, $match)) {
1108 212
            $currentType = $match[1];
1109
        }
1110
1111 944
        return $currentType;
1112
    }
1113
1114
    /**
1115
     * @param string $comment
1116
     * @param string $type
1117
     *
1118
     * @return string
1119
     */
1120 806
    public function removeDoctrineTypeFromComment($comment, $type)
1121
    {
1122 806
        return str_replace('(DC2Type:' . $type . ')', '', $comment);
1123
    }
1124
}
1125