Completed
Push — 2.11.x ( 0a2e2f...a8544c )
by Grégoire
23s queued 16s
created

_getPortableTableIndexesList()   B

Complexity

Conditions 10
Paths 63

Size

Total Lines 61
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 34
CRAP Score 10.0023

Importance

Changes 0
Metric Value
eloc 36
dl 0
loc 61
ccs 34
cts 35
cp 0.9714
rs 7.6666
c 0
b 0
f 0
cc 10
nc 63
nop 2
crap 10.0023

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 assert;
18
use function call_user_func_array;
19
use function count;
20
use function func_get_args;
21
use function is_array;
22
use function is_callable;
23
use function preg_match;
24
use function str_replace;
25
use function strtolower;
26
27
/**
28
 * Base class for schema managers. Schema managers are used to inspect and/or
29
 * modify the database schema/structure.
30
 */
31
abstract class AbstractSchemaManager
32
{
33
    /**
34
     * Holds instance of the Doctrine connection for this schema manager.
35
     *
36
     * @var Connection
37
     */
38
    protected $_conn;
39
40
    /**
41
     * Holds instance of the database platform used for this schema manager.
42
     *
43
     * @var AbstractPlatform
44
     */
45
    protected $_platform;
46
47
    /**
48
     * Constructor. Accepts the Connection instance to manage the schema for.
49
     */
50 5462
    public function __construct(Connection $conn, ?AbstractPlatform $platform = null)
51
    {
52 5462
        $this->_conn     = $conn;
53 5462
        $this->_platform = $platform ?: $this->_conn->getDatabasePlatform();
54 5462
    }
55
56
    /**
57
     * Returns the associated platform.
58
     *
59
     * @return AbstractPlatform
60
     */
61 3473
    public function getDatabasePlatform()
62
    {
63 3473
        return $this->_platform;
64
    }
65
66
    /**
67
     * Tries any method on the schema manager. Normally a method throws an
68
     * exception when your DBMS doesn't support it or if an error occurs.
69
     * This method allows you to try and method on your SchemaManager
70
     * instance and will return false if it does not work or is not supported.
71
     *
72
     * <code>
73
     * $result = $sm->tryMethod('dropView', 'view_name');
74
     * </code>
75
     *
76
     * @return mixed
77
     */
78 5260
    public function tryMethod()
79
    {
80 5260
        $args   = func_get_args();
81 5260
        $method = $args[0];
82 5260
        unset($args[0]);
83 5260
        $args = array_values($args);
84
85 5260
        $callback = [$this, $method];
86 5260
        assert(is_callable($callback));
87
88
        try {
89 5260
            return call_user_func_array($callback, $args);
90 5140
        } catch (Throwable $e) {
91 5140
            return false;
92
        }
93
    }
94
95
    /**
96
     * Lists the available databases for this connection.
97
     *
98
     * @return string[]
99
     */
100 3093
    public function listDatabases()
101
    {
102 3093
        $sql = $this->_platform->getListDatabasesSQL();
103
104 2943
        $databases = $this->_conn->fetchAll($sql);
105
106 2943
        return $this->_getPortableDatabasesList($databases);
107
    }
108
109
    /**
110
     * Returns a list of all namespaces in the current database.
111
     *
112
     * @return string[]
113
     */
114 1250
    public function listNamespaceNames()
115
    {
116 1250
        $sql = $this->_platform->getListNamespacesSQL();
117
118 1250
        $namespaces = $this->_conn->fetchAll($sql);
119
120 1250
        return $this->getPortableNamespacesList($namespaces);
121
    }
122
123
    /**
124
     * Lists the available sequences for this connection.
125
     *
126
     * @param string|null $database
127
     *
128
     * @return Sequence[]
129
     */
130 1282
    public function listSequences($database = null)
131
    {
132 1282
        if ($database === null) {
133 1282
            $database = $this->_conn->getDatabase();
134
        }
135
136 1282
        $sql = $this->_platform->getListSequencesSQL($database);
137
138 1282
        $sequences = $this->_conn->fetchAll($sql);
139
140 1282
        return $this->filterAssetNames($this->_getPortableSequencesList($sequences));
141
    }
142
143
    /**
144
     * Lists the columns for a given table.
145
     *
146
     * In contrast to other libraries and to the old version of Doctrine,
147
     * this column definition does try to contain the 'primary' field for
148
     * the reason that it is not portable across different RDBMS. Use
149
     * {@see listTableIndexes($tableName)} to retrieve the primary key
150
     * of a table. Where a RDBMS specifies more details, these are held
151
     * in the platformDetails array.
152
     *
153
     * @param string      $table    The name of the table.
154
     * @param string|null $database
155
     *
156
     * @return Column[]
157
     */
158 4110
    public function listTableColumns($table, $database = null)
159
    {
160 4110
        if (! $database) {
161 4109
            $database = $this->_conn->getDatabase();
162
        }
163
164 4110
        $sql = $this->_platform->getListTableColumnsSQL($table, $database);
165
166 4110
        $tableColumns = $this->_conn->fetchAll($sql);
167
168 4110
        return $this->_getPortableTableColumnList($table, $database, $tableColumns);
169
    }
170
171
    /**
172
     * Lists the indexes for a given table returning an array of Index instances.
173
     *
174
     * Keys of the portable indexes list are all lower-cased.
175
     *
176
     * @param string $table The name of the table.
177
     *
178
     * @return Index[]
179
     */
180 3799
    public function listTableIndexes($table)
181
    {
182 3799
        $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
183
184 3799
        $tableIndexes = $this->_conn->fetchAll($sql);
185
186 3799
        return $this->_getPortableTableIndexesList($tableIndexes, $table);
187
    }
188
189
    /**
190
     * Returns true if all the given tables exist.
191
     *
192
     * The usage of a string $tableNames is deprecated. Pass a one-element array instead.
193
     *
194
     * @param string|string[] $tableNames
195
     *
196
     * @return bool
197
     */
198 4571
    public function tablesExist($tableNames)
199
    {
200 4571
        $tableNames = array_map('strtolower', (array) $tableNames);
201
202 4571
        return count($tableNames) === count(array_intersect($tableNames, array_map('strtolower', $this->listTableNames())));
203
    }
204
205
    /**
206
     * Returns a list of all tables in the current database.
207
     *
208
     * @return string[]
209
     */
210 4405
    public function listTableNames()
211
    {
212 4405
        $sql = $this->_platform->getListTablesSQL();
213
214 4405
        $tables     = $this->_conn->fetchAll($sql);
215 4405
        $tableNames = $this->_getPortableTablesList($tables);
216
217 4405
        return $this->filterAssetNames($tableNames);
218
    }
219
220
    /**
221
     * Filters asset names if they are configured to return only a subset of all
222
     * the found elements.
223
     *
224
     * @param mixed[] $assetNames
225
     *
226
     * @return mixed[]
227
     */
228 4592
    protected function filterAssetNames($assetNames)
229
    {
230 4592
        $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter();
231 4592
        if (! $filter) {
232 4592
            return $assetNames;
233
        }
234
235 1667
        return array_values(array_filter($assetNames, $filter));
236
    }
237
238
    /**
239
     * @deprecated Use Configuration::getSchemaAssetsFilter() instead
240
     *
241
     * @return string|null
242
     */
243
    protected function getFilterSchemaAssetsExpression()
244
    {
245
        return $this->_conn->getConfiguration()->getFilterSchemaAssetsExpression();
246
    }
247
248
    /**
249
     * Lists the tables for this connection.
250
     *
251
     * @return Table[]
252
     */
253 3889
    public function listTables()
254
    {
255 3889
        $tableNames = $this->listTableNames();
256
257 3889
        $tables = [];
258 3889
        foreach ($tableNames as $tableName) {
259 3839
            $tables[] = $this->listTableDetails($tableName);
260
        }
261
262 3889
        return $tables;
263
    }
264
265
    /**
266
     * @param string $tableName
267
     *
268
     * @return Table
269
     */
270 4098
    public function listTableDetails($tableName)
271
    {
272 4098
        $columns     = $this->listTableColumns($tableName);
273 4098
        $foreignKeys = [];
274 4098
        if ($this->_platform->supportsForeignKeyConstraints()) {
275 4098
            $foreignKeys = $this->listTableForeignKeys($tableName);
276
        }
277
278 4098
        $indexes = $this->listTableIndexes($tableName);
279
280 4098
        return new Table($tableName, $columns, $indexes, $foreignKeys);
281
    }
282
283
    /**
284
     * Lists the views this connection has.
285
     *
286
     * @return View[]
287
     */
288 2868
    public function listViews()
289
    {
290 2868
        $database = $this->_conn->getDatabase();
291 2868
        $sql      = $this->_platform->getListViewsSQL($database);
292 2868
        $views    = $this->_conn->fetchAll($sql);
293
294 2868
        return $this->_getPortableViewsList($views);
295
    }
296
297
    /**
298
     * Lists the foreign keys for the given table.
299
     *
300
     * @param string      $table    The name of the table.
301
     * @param string|null $database
302
     *
303
     * @return ForeignKeyConstraint[]
304
     */
305 3972
    public function listTableForeignKeys($table, $database = null)
306
    {
307 3972
        if ($database === null) {
308 3972
            $database = $this->_conn->getDatabase();
309
        }
310
311 3972
        $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

311
        /** @scrutinizer ignore-call */ 
312
        $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...
312 3972
        $tableForeignKeys = $this->_conn->fetchAll($sql);
313
314 3972
        return $this->_getPortableTableForeignKeysList($tableForeignKeys);
315
    }
316
317
    /* drop*() Methods */
318
319
    /**
320
     * Drops a database.
321
     *
322
     * NOTE: You can not drop the database this SchemaManager is currently connected to.
323
     *
324
     * @param string $database The name of the database to drop.
325
     *
326
     * @return void
327
     */
328 4756
    public function dropDatabase($database)
329
    {
330 4756
        $this->_execSql($this->_platform->getDropDatabaseSQL($database));
331 4033
    }
332
333
    /**
334
     * Drops the given table.
335
     *
336
     * @param string $tableName The name of the table to drop.
337
     *
338
     * @return void
339
     */
340 5059
    public function dropTable($tableName)
341
    {
342 5059
        $this->_execSql($this->_platform->getDropTableSQL($tableName));
343 4985
    }
344
345
    /**
346
     * Drops the index from the given table.
347
     *
348
     * @param Index|string $index The name of the index.
349
     * @param Table|string $table The name of the table.
350
     *
351
     * @return void
352
     */
353 2985
    public function dropIndex($index, $table)
354
    {
355 2985
        if ($index instanceof Index) {
356
            $index = $index->getQuotedName($this->_platform);
357
        }
358
359 2985
        $this->_execSql($this->_platform->getDropIndexSQL($index, $table));
360 2985
    }
361
362
    /**
363
     * Drops the constraint from the given table.
364
     *
365
     * @param Table|string $table The name of the table.
366
     *
367
     * @return void
368
     */
369
    public function dropConstraint(Constraint $constraint, $table)
370
    {
371
        $this->_execSql($this->_platform->getDropConstraintSQL($constraint, $table));
372
    }
373
374
    /**
375
     * Drops a foreign key from a table.
376
     *
377
     * @param ForeignKeyConstraint|string $foreignKey The name of the foreign key.
378
     * @param Table|string                $table      The name of the table with the foreign key.
379
     *
380
     * @return void
381
     */
382
    public function dropForeignKey($foreignKey, $table)
383
    {
384
        $this->_execSql($this->_platform->getDropForeignKeySQL($foreignKey, $table));
385
    }
386
387
    /**
388
     * Drops a sequence with a given name.
389
     *
390
     * @param string $name The name of the sequence to drop.
391
     *
392
     * @return void
393
     */
394 1279
    public function dropSequence($name)
395
    {
396 1279
        $this->_execSql($this->_platform->getDropSequenceSQL($name));
397
    }
398
399
    /**
400
     * Drops a view.
401
     *
402
     * @param string $name The name of the view.
403
     *
404
     * @return void
405
     */
406 3060
    public function dropView($name)
407
    {
408 3060
        $this->_execSql($this->_platform->getDropViewSQL($name));
409
    }
410
411
    /* create*() Methods */
412
413
    /**
414
     * Creates a new database.
415
     *
416
     * @param string $database The name of the database to create.
417
     *
418
     * @return void
419
     */
420 4754
    public function createDatabase($database)
421
    {
422 4754
        $this->_execSql($this->_platform->getCreateDatabaseSQL($database));
423 4754
    }
424
425
    /**
426
     * Creates a new table.
427
     *
428
     * @return void
429
     */
430 5076
    public function createTable(Table $table)
431
    {
432 5076
        $createFlags = AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS;
433 5076
        $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags));
434 5055
    }
435
436
    /**
437
     * Creates a new sequence.
438
     *
439
     * @param Sequence $sequence
440
     *
441
     * @return void
442
     *
443
     * @throws ConnectionException If something fails at database level.
444
     */
445 1281
    public function createSequence($sequence)
446
    {
447 1281
        $this->_execSql($this->_platform->getCreateSequenceSQL($sequence));
448 1281
    }
449
450
    /**
451
     * Creates a constraint on a table.
452
     *
453
     * @param Table|string $table
454
     *
455
     * @return void
456
     */
457 1
    public function createConstraint(Constraint $constraint, $table)
458
    {
459 1
        $this->_execSql($this->_platform->getCreateConstraintSQL($constraint, $table));
460 1
    }
461
462
    /**
463
     * Creates a new index on a table.
464
     *
465
     * @param Table|string $table The name of the table on which the index is to be created.
466
     *
467
     * @return void
468
     */
469 2985
    public function createIndex(Index $index, $table)
470
    {
471 2985
        $this->_execSql($this->_platform->getCreateIndexSQL($index, $table));
472 2985
    }
473
474
    /**
475
     * Creates a new foreign key.
476
     *
477
     * @param ForeignKeyConstraint $foreignKey The ForeignKey instance.
478
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
479
     *
480
     * @return void
481
     */
482 3029
    public function createForeignKey(ForeignKeyConstraint $foreignKey, $table)
483
    {
484 3029
        $this->_execSql($this->_platform->getCreateForeignKeySQL($foreignKey, $table));
485 3029
    }
486
487
    /**
488
     * Creates a new view.
489
     *
490
     * @return void
491
     */
492 3060
    public function createView(View $view)
493
    {
494 3060
        $this->_execSql($this->_platform->getCreateViewSQL($view->getQuotedName($this->_platform), $view->getSql()));
495 3060
    }
496
497
    /* dropAndCreate*() Methods */
498
499
    /**
500
     * Drops and creates a constraint.
501
     *
502
     * @see dropConstraint()
503
     * @see createConstraint()
504
     *
505
     * @param Table|string $table
506
     *
507
     * @return void
508
     */
509
    public function dropAndCreateConstraint(Constraint $constraint, $table)
510
    {
511
        $this->tryMethod('dropConstraint', $constraint, $table);
512
        $this->createConstraint($constraint, $table);
513
    }
514
515
    /**
516
     * Drops and creates a new index on a table.
517
     *
518
     * @param Table|string $table The name of the table on which the index is to be created.
519
     *
520
     * @return void
521
     */
522 2985
    public function dropAndCreateIndex(Index $index, $table)
523
    {
524 2985
        $this->tryMethod('dropIndex', $index->getQuotedName($this->_platform), $table);
525 2985
        $this->createIndex($index, $table);
526 2985
    }
527
528
    /**
529
     * Drops and creates a new foreign key.
530
     *
531
     * @param ForeignKeyConstraint $foreignKey An associative array that defines properties of the foreign key to be created.
532
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
533
     *
534
     * @return void
535
     */
536
    public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table)
537
    {
538
        $this->tryMethod('dropForeignKey', $foreignKey, $table);
539
        $this->createForeignKey($foreignKey, $table);
540
    }
541
542
    /**
543
     * Drops and create a new sequence.
544
     *
545
     * @return void
546
     *
547
     * @throws ConnectionException If something fails at database level.
548
     */
549 1279
    public function dropAndCreateSequence(Sequence $sequence)
550
    {
551 1279
        $this->tryMethod('dropSequence', $sequence->getQuotedName($this->_platform));
552 1279
        $this->createSequence($sequence);
553 1279
    }
554
555
    /**
556
     * Drops and creates a new table.
557
     *
558
     * @return void
559
     */
560 5018
    public function dropAndCreateTable(Table $table)
561
    {
562 5018
        $this->tryMethod('dropTable', $table->getQuotedName($this->_platform));
563 5018
        $this->createTable($table);
564 5018
    }
565
566
    /**
567
     * Drops and creates a new database.
568
     *
569
     * @param string $database The name of the database to create.
570
     *
571
     * @return void
572
     */
573 4904
    public function dropAndCreateDatabase($database)
574
    {
575 4904
        $this->tryMethod('dropDatabase', $database);
576 4904
        $this->createDatabase($database);
577 4904
    }
578
579
    /**
580
     * Drops and creates a new view.
581
     *
582
     * @return void
583
     */
584 3060
    public function dropAndCreateView(View $view)
585
    {
586 3060
        $this->tryMethod('dropView', $view->getQuotedName($this->_platform));
587 3060
        $this->createView($view);
588 3060
    }
589
590
    /* alterTable() Methods */
591
592
    /**
593
     * Alters an existing tables schema.
594
     *
595
     * @return void
596
     */
597 3658
    public function alterTable(TableDiff $tableDiff)
598
    {
599 3658
        $queries = $this->_platform->getAlterTableSQL($tableDiff);
600 3658
        if (! is_array($queries) || ! count($queries)) {
601 1227
            return;
602
        }
603
604 3658
        foreach ($queries as $ddlQuery) {
605 3658
            $this->_execSql($ddlQuery);
606
        }
607 3658
    }
608
609
    /**
610
     * Renames a given table to another name.
611
     *
612
     * @param string $name    The current name of the table.
613
     * @param string $newName The new name of the table.
614
     *
615
     * @return void
616
     */
617 1
    public function renameTable($name, $newName)
618
    {
619 1
        $tableDiff          = new TableDiff($name);
620 1
        $tableDiff->newName = $newName;
621 1
        $this->alterTable($tableDiff);
622 1
    }
623
624
    /**
625
     * Methods for filtering return values of list*() methods to convert
626
     * the native DBMS data definition to a portable Doctrine definition
627
     */
628
629
    /**
630
     * @param mixed[] $databases
631
     *
632
     * @return string[]
633
     */
634 2943
    protected function _getPortableDatabasesList($databases)
635
    {
636 2943
        $list = [];
637 2943
        foreach ($databases as $value) {
638 2943
            $value = $this->_getPortableDatabaseDefinition($value);
639
640 2943
            if (! $value) {
641
                continue;
642
            }
643
644 2943
            $list[] = $value;
645
        }
646
647 2943
        return $list;
648
    }
649
650
    /**
651
     * Converts a list of namespace names from the native DBMS data definition to a portable Doctrine definition.
652
     *
653
     * @param mixed[][] $namespaces The list of namespace names in the native DBMS data definition.
654
     *
655
     * @return string[]
656
     */
657 1250
    protected function getPortableNamespacesList(array $namespaces)
658
    {
659 1250
        $namespacesList = [];
660
661 1250
        foreach ($namespaces as $namespace) {
662 1250
            $namespacesList[] = $this->getPortableNamespaceDefinition($namespace);
663
        }
664
665 1250
        return $namespacesList;
666
    }
667
668
    /**
669
     * @param mixed $database
670
     *
671
     * @return mixed
672
     */
673
    protected function _getPortableDatabaseDefinition($database)
674
    {
675
        return $database;
676
    }
677
678
    /**
679
     * Converts a namespace definition from the native DBMS data definition to a portable Doctrine definition.
680
     *
681
     * @param mixed[] $namespace The native DBMS namespace definition.
682
     *
683
     * @return mixed
684
     */
685
    protected function getPortableNamespaceDefinition(array $namespace)
686
    {
687
        return $namespace;
688
    }
689
690
    /**
691
     * @deprecated
692
     *
693
     * @param mixed[][] $functions
694
     *
695
     * @return mixed[][]
696
     */
697
    protected function _getPortableFunctionsList($functions)
698
    {
699
        $list = [];
700
        foreach ($functions as $value) {
701
            $value = $this->_getPortableFunctionDefinition($value);
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\DBAL\Schema\Abs...bleFunctionDefinition() has been deprecated. ( Ignorable by Annotation )

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

701
            $value = /** @scrutinizer ignore-deprecated */ $this->_getPortableFunctionDefinition($value);
Loading history...
702
703
            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...
704
                continue;
705
            }
706
707
            $list[] = $value;
708
        }
709
710
        return $list;
711
    }
712
713
    /**
714
     * @deprecated
715
     *
716
     * @param mixed[] $function
717
     *
718
     * @return mixed
719
     */
720
    protected function _getPortableFunctionDefinition($function)
721
    {
722
        return $function;
723
    }
724
725
    /**
726
     * @param mixed[][] $triggers
727
     *
728
     * @return mixed[][]
729
     */
730
    protected function _getPortableTriggersList($triggers)
731
    {
732
        $list = [];
733
        foreach ($triggers as $value) {
734
            $value = $this->_getPortableTriggerDefinition($value);
735
736
            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...
737
                continue;
738
            }
739
740
            $list[] = $value;
741
        }
742
743
        return $list;
744
    }
745
746
    /**
747
     * @param mixed[] $trigger
748
     *
749
     * @return mixed
750
     */
751
    protected function _getPortableTriggerDefinition($trigger)
752
    {
753
        return $trigger;
754
    }
755
756
    /**
757
     * @param mixed[][] $sequences
758
     *
759
     * @return Sequence[]
760
     */
761 288
    protected function _getPortableSequencesList($sequences)
762
    {
763 288
        $list = [];
764
765 288
        foreach ($sequences as $value) {
766 288
            $list[] = $this->_getPortableSequenceDefinition($value);
767
        }
768
769 288
        return $list;
770
    }
771
772
    /**
773
     * @param mixed[] $sequence
774
     *
775
     * @return Sequence
776
     *
777
     * @throws DBALException
778
     */
779
    protected function _getPortableSequenceDefinition($sequence)
780
    {
781
        throw DBALException::notSupported('Sequences');
782
    }
783
784
    /**
785
     * Independent of the database the keys of the column list result are lowercased.
786
     *
787
     * The name of the created column instance however is kept in its case.
788
     *
789
     * @param string    $table        The name of the table.
790
     * @param string    $database
791
     * @param mixed[][] $tableColumns
792
     *
793
     * @return Column[]
794
     */
795 4110
    protected function _getPortableTableColumnList($table, $database, $tableColumns)
796
    {
797 4110
        $eventManager = $this->_platform->getEventManager();
798
799 4110
        $list = [];
800 4110
        foreach ($tableColumns as $tableColumn) {
801 4110
            $column           = null;
802 4110
            $defaultPrevented = false;
803
804 4110
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaColumnDefinition)) {
805 3077
                $eventArgs = new SchemaColumnDefinitionEventArgs($tableColumn, $table, $database, $this->_conn);
806 3077
                $eventManager->dispatchEvent(Events::onSchemaColumnDefinition, $eventArgs);
807
808 3077
                $defaultPrevented = $eventArgs->isDefaultPrevented();
809 3077
                $column           = $eventArgs->getColumn();
810
            }
811
812 4110
            if (! $defaultPrevented) {
813 4110
                $column = $this->_getPortableTableColumnDefinition($tableColumn);
814
            }
815
816 4110
            if (! $column) {
817
                continue;
818
            }
819
820 4110
            $name        = strtolower($column->getQuotedName($this->_platform));
821 4110
            $list[$name] = $column;
822
        }
823
824 4110
        return $list;
825
    }
826
827
    /**
828
     * Gets Table Column Definition.
829
     *
830
     * @param mixed[] $tableColumn
831
     *
832
     * @return Column
833
     */
834
    abstract protected function _getPortableTableColumnDefinition($tableColumn);
835
836
    /**
837
     * Aggregates and groups the index results according to the required data result.
838
     *
839
     * @param mixed[][]   $tableIndexRows
840
     * @param string|null $tableName
841
     *
842
     * @return Index[]
843
     */
844 4103
    protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null)
845
    {
846 4103
        $result = [];
847 4103
        foreach ($tableIndexRows as $tableIndex) {
848 3969
            $indexName = $keyName = $tableIndex['key_name'];
849 3969
            if ($tableIndex['primary']) {
850 3967
                $keyName = 'primary';
851
            }
852
853 3969
            $keyName = strtolower($keyName);
854
855 3969
            if (! isset($result[$keyName])) {
856
                $options = [
857 3969
                    'lengths' => [],
858
                ];
859
860 3969
                if (isset($tableIndex['where'])) {
861 1067
                    $options['where'] = $tableIndex['where'];
862
                }
863
864 3969
                $result[$keyName] = [
865 3969
                    'name' => $indexName,
866
                    'columns' => [],
867 3969
                    'unique' => ! $tableIndex['non_unique'],
868 3969
                    'primary' => $tableIndex['primary'],
869 3969
                    'flags' => $tableIndex['flags'] ?? [],
870 3969
                    'options' => $options,
871
                ];
872
            }
873
874 3969
            $result[$keyName]['columns'][]            = $tableIndex['column_name'];
875 3969
            $result[$keyName]['options']['lengths'][] = $tableIndex['length'] ?? null;
876
        }
877
878 4103
        $eventManager = $this->_platform->getEventManager();
879
880 4103
        $indexes = [];
881 4103
        foreach ($result as $indexKey => $data) {
882 3969
            $index            = null;
883 3969
            $defaultPrevented = false;
884
885 3969
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) {
886 3054
                $eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn);
887 3054
                $eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs);
888
889 3054
                $defaultPrevented = $eventArgs->isDefaultPrevented();
890 3054
                $index            = $eventArgs->getIndex();
891
            }
892
893 3969
            if (! $defaultPrevented) {
894 3969
                $index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary'], $data['flags'], $data['options']);
895
            }
896
897 3969
            if (! $index) {
898
                continue;
899
            }
900
901 3969
            $indexes[$indexKey] = $index;
902
        }
903
904 4103
        return $indexes;
905
    }
906
907
    /**
908
     * @param mixed[][] $tables
909
     *
910
     * @return string[]
911
     */
912 4405
    protected function _getPortableTablesList($tables)
913
    {
914 4405
        $list = [];
915 4405
        foreach ($tables as $value) {
916 4403
            $value = $this->_getPortableTableDefinition($value);
917
918 4403
            if (! $value) {
919
                continue;
920
            }
921
922 4403
            $list[] = $value;
923
        }
924
925 4405
        return $list;
926
    }
927
928
    /**
929
     * @param mixed $table
930
     *
931
     * @return string
932
     */
933
    protected function _getPortableTableDefinition($table)
934
    {
935
        return $table;
936
    }
937
938
    /**
939
     * @param mixed[][] $users
940
     *
941
     * @return string[][]
942
     */
943
    protected function _getPortableUsersList($users)
944
    {
945
        $list = [];
946
        foreach ($users as $value) {
947
            $value = $this->_getPortableUserDefinition($value);
948
949
            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...
950
                continue;
951
            }
952
953
            $list[] = $value;
954
        }
955
956
        return $list;
957
    }
958
959
    /**
960
     * @param string[] $user
961
     *
962
     * @return string[]
963
     */
964
    protected function _getPortableUserDefinition($user)
965
    {
966
        return $user;
967
    }
968
969
    /**
970
     * @param mixed[][] $views
971
     *
972
     * @return View[]
973
     */
974 2868
    protected function _getPortableViewsList($views)
975
    {
976 2868
        $list = [];
977 2868
        foreach ($views as $value) {
978 2868
            $view = $this->_getPortableViewDefinition($value);
979
980 2868
            if (! $view) {
981
                continue;
982
            }
983
984 2868
            $viewName        = strtolower($view->getQuotedName($this->_platform));
985 2868
            $list[$viewName] = $view;
986
        }
987
988 2868
        return $list;
989
    }
990
991
    /**
992
     * @param mixed[] $view
993
     *
994
     * @return View|false
995
     */
996
    protected function _getPortableViewDefinition($view)
997
    {
998
        return false;
999
    }
1000
1001
    /**
1002
     * @param mixed[][] $tableForeignKeys
1003
     *
1004
     * @return ForeignKeyConstraint[]
1005
     */
1006 1681
    protected function _getPortableTableForeignKeysList($tableForeignKeys)
1007
    {
1008 1681
        $list = [];
1009
1010 1681
        foreach ($tableForeignKeys as $value) {
1011 1615
            $list[] = $this->_getPortableTableForeignKeyDefinition($value);
1012
        }
1013
1014 1681
        return $list;
1015
    }
1016
1017
    /**
1018
     * @param mixed $tableForeignKey
1019
     *
1020
     * @return ForeignKeyConstraint
1021
     */
1022
    protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
1023
    {
1024
        return $tableForeignKey;
1025
    }
1026
1027
    /**
1028
     * @param string[]|string $sql
1029
     *
1030
     * @return void
1031
     */
1032 5289
    protected function _execSql($sql)
1033
    {
1034 5289
        foreach ((array) $sql as $query) {
1035 5289
            $this->_conn->executeUpdate($query);
1036
        }
1037 5261
    }
1038
1039
    /**
1040
     * Creates a schema instance for the current database.
1041
     *
1042
     * @return Schema
1043
     */
1044 3686
    public function createSchema()
1045
    {
1046 3686
        $namespaces = [];
1047
1048 3686
        if ($this->_platform->supportsSchemas()) {
1049 1158
            $namespaces = $this->listNamespaceNames();
1050
        }
1051
1052 3686
        $sequences = [];
1053
1054 3686
        if ($this->_platform->supportsSequences()) {
1055 1159
            $sequences = $this->listSequences();
1056
        }
1057
1058 3686
        $tables = $this->listTables();
1059
1060 3686
        return new Schema($tables, $sequences, $this->createSchemaConfig(), $namespaces);
1061
    }
1062
1063
    /**
1064
     * Creates the configuration for this schema.
1065
     *
1066
     * @return SchemaConfig
1067
     */
1068 3956
    public function createSchemaConfig()
1069
    {
1070 3956
        $schemaConfig = new SchemaConfig();
1071 3956
        $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength());
1072
1073 3956
        $searchPaths = $this->getSchemaSearchPaths();
1074 3956
        if (isset($searchPaths[0])) {
1075 3805
            $schemaConfig->setName($searchPaths[0]);
1076
        }
1077
1078 3956
        $params = $this->_conn->getParams();
1079 3956
        if (! isset($params['defaultTableOptions'])) {
1080 3956
            $params['defaultTableOptions'] = [];
1081
        }
1082
1083 3956
        if (! isset($params['defaultTableOptions']['charset']) && isset($params['charset'])) {
1084 783
            $params['defaultTableOptions']['charset'] = $params['charset'];
1085
        }
1086
1087 3956
        $schemaConfig->setDefaultTableOptions($params['defaultTableOptions']);
1088
1089 3956
        return $schemaConfig;
1090
    }
1091
1092
    /**
1093
     * The search path for namespaces in the currently connected database.
1094
     *
1095
     * The first entry is usually the default namespace in the Schema. All
1096
     * further namespaces contain tables/sequences which can also be addressed
1097
     * with a short, not full-qualified name.
1098
     *
1099
     * For databases that don't support subschema/namespaces this method
1100
     * returns the name of the currently connected database.
1101
     *
1102
     * @return string[]
1103
     */
1104 3078
    public function getSchemaSearchPaths()
1105
    {
1106 3078
        return [$this->_conn->getDatabase()];
1107
    }
1108
1109
    /**
1110
     * Given a table comment this method tries to extract a typehint for Doctrine Type, or returns
1111
     * the type given as default.
1112
     *
1113
     * @param string|null $comment
1114
     * @param string      $currentType
1115
     *
1116
     * @return string
1117
     */
1118 4112
    public function extractDoctrineTypeFromComment($comment, $currentType)
1119
    {
1120 4112
        if ($comment !== null && preg_match('(\(DC2Type:(((?!\)).)+)\))', $comment, $match)) {
1121 3317
            return $match[1];
1122
        }
1123
1124 4086
        return $currentType;
1125
    }
1126
1127
    /**
1128
     * @param string|null $comment
1129
     * @param string|null $type
1130
     *
1131
     * @return string|null
1132
     */
1133 4062
    public function removeDoctrineTypeFromComment($comment, $type)
1134
    {
1135 4062
        if ($comment === null) {
1136 2537
            return null;
1137
        }
1138
1139 3774
        return str_replace('(DC2Type:' . $type . ')', '', $comment);
1140
    }
1141
}
1142