Failed Conditions
Pull Request — develop (#3348)
by Sergei
10:40
created

AbstractSchemaManager::removeDoctrineTypeFromComment()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

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

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