Completed
Pull Request — master (#3610)
by Sergei
06:29
created

_getPortableTableColumnList()   B

Complexity

Conditions 6
Paths 9

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 6.0061

Importance

Changes 0
Metric Value
dl 0
loc 31
ccs 17
cts 18
cp 0.9444
rs 8.8017
c 0
b 0
f 0
cc 6
nc 9
nop 3
crap 6.0061
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 5907
    public function __construct(Connection $conn, ?AbstractPlatform $platform = null)
51
    {
52 5907
        $this->_conn     = $conn;
53 5907
        $this->_platform = $platform ?: $this->_conn->getDatabasePlatform();
54 5907
    }
55
56
    /**
57
     * Returns the associated platform.
58
     *
59
     * @return AbstractPlatform
60
     */
61 3718
    public function getDatabasePlatform()
62
    {
63 3718
        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 5718
    public function tryMethod()
79
    {
80 5718
        $args   = func_get_args();
81 5718
        $method = $args[0];
82 5718
        unset($args[0]);
83 5718
        $args = array_values($args);
84
85 5718
        $callback = [$this, $method];
86 5718
        assert(is_callable($callback));
87
88
        try {
89 5718
            return call_user_func_array($callback, $args);
90 5578
        } catch (Throwable $e) {
91 5578
            return false;
92
        }
93
    }
94
95
    /**
96
     * Lists the available databases for this connection.
97
     *
98
     * @return string[]
99
     */
100 3300
    public function listDatabases()
101
    {
102 3300
        $sql = $this->_platform->getListDatabasesSQL();
103
104 3161
        $databases = $this->_conn->fetchAll($sql);
105
106 3161
        return $this->_getPortableDatabasesList($databases);
107
    }
108
109
    /**
110
     * Returns a list of all namespaces in the current database.
111
     *
112
     * @return string[]
113
     */
114 1225
    public function listNamespaceNames()
115
    {
116 1225
        $sql = $this->_platform->getListNamespacesSQL();
117
118 1225
        $namespaces = $this->_conn->fetchAll($sql);
119
120 1225
        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 1261
    public function listSequences($database = null)
131
    {
132 1261
        if ($database === null) {
133 1261
            $database = $this->_conn->getDatabase();
134
        }
135 1261
        $sql = $this->_platform->getListSequencesSQL($database);
136
137 1261
        $sequences = $this->_conn->fetchAll($sql);
138
139 1261
        return $this->filterAssetNames($this->_getPortableSequencesList($sequences));
140
    }
141
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
     * @param string|null $database
154
     *
155
     * @return Column[]
156
     */
157 4442
    public function listTableColumns($table, $database = null)
158
    {
159 4442
        if (! $database) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $database of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
160 4440
            $database = $this->_conn->getDatabase();
161
        }
162
163 4442
        $sql = $this->_platform->getListTableColumnsSQL($table, $database);
164
165 4442
        $tableColumns = $this->_conn->fetchAll($sql);
166
167 4442
        return $this->_getPortableTableColumnList($table, $database, $tableColumns);
168
    }
169
170
    /**
171
     * Lists the indexes for a given table returning an array of Index instances.
172
     *
173
     * Keys of the portable indexes list are all lower-cased.
174
     *
175
     * @param string $table The name of the table.
176
     *
177
     * @return Index[]
178
     */
179 4129
    public function listTableIndexes($table)
180
    {
181 4129
        $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
182
183 4129
        $tableIndexes = $this->_conn->fetchAll($sql);
184
185 4129
        return $this->_getPortableTableIndexesList($tableIndexes, $table);
186
    }
187
188
    /**
189
     * Returns true if all the given tables exist.
190
     *
191
     * @param string|string[] $tableNames
192
     *
193
     * @return bool
194
     */
195 4922
    public function tablesExist($tableNames)
196
    {
197 4922
        $tableNames = array_map('strtolower', (array) $tableNames);
198
199 4922
        return count($tableNames) === count(array_intersect($tableNames, array_map('strtolower', $this->listTableNames())));
200
    }
201
202
    /**
203
     * Returns a list of all tables in the current database.
204
     *
205
     * @return string[]
206
     */
207 4762
    public function listTableNames()
208
    {
209 4762
        $sql = $this->_platform->getListTablesSQL();
210
211 4762
        $tables     = $this->_conn->fetchAll($sql);
212 4762
        $tableNames = $this->_getPortableTablesList($tables);
213
214 4762
        return $this->filterAssetNames($tableNames);
215
    }
216
217
    /**
218
     * Filters asset names if they are configured to return only a subset of all
219
     * the found elements.
220
     *
221
     * @param mixed[] $assetNames
222
     *
223
     * @return mixed[]
224
     */
225 4946
    protected function filterAssetNames($assetNames)
226
    {
227 4946
        $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter();
228 4946
        if (! $filter) {
229 4946
            return $assetNames;
230
        }
231
232 1707
        return array_values(array_filter($assetNames, $filter));
233
    }
234
235
    /**
236
     * @deprecated Use Configuration::getSchemaAssetsFilter() instead
237
     *
238
     * @return string|null
239
     */
240
    protected function getFilterSchemaAssetsExpression()
241
    {
242
        return $this->_conn->getConfiguration()->getFilterSchemaAssetsExpression();
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\DBAL\Configurat...chemaAssetsExpression() has been deprecated with message: Use Configuration::getSchemaAssetsFilter() instead

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

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

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

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

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