Completed
Pull Request — develop (#3501)
by Sergei
83:51 queued 18:47
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 5537
     */
51
    public function __construct(Connection $conn, ?AbstractPlatform $platform = null)
52 5537
    {
53 5537
        $this->_conn     = $conn;
54 5537
        $this->_platform = $platform ?: $this->_conn->getDatabasePlatform();
55
    }
56
57
    /**
58
     * Returns the associated platform.
59
     *
60
     * @return AbstractPlatform
61 3718
     */
62
    public function getDatabasePlatform()
63 3718
    {
64
        return $this->_platform;
65
    }
66
67
    /**
68
     * Tries any method on the schema manager. Normally a method throws an
69
     * exception when your DBMS doesn't support it or if an error occurs.
70
     * This method allows you to try and method on your SchemaManager
71
     * instance and will return false if it does not work or is not supported.
72
     *
73
     * <code>
74
     * $result = $sm->tryMethod('dropView', 'view_name');
75
     * </code>
76
     *
77
     * @return mixed
78 5349
     */
79
    public function tryMethod()
80 5349
    {
81 5349
        $args   = func_get_args();
82 5349
        $method = $args[0];
83 5349
        unset($args[0]);
84
        $args = array_values($args);
85 5349
86 5349
        $callback = [$this, $method];
87
        assert(is_callable($callback));
88
89 5349
        try {
90 5223
            return call_user_func_array($callback, $args);
91 5223
        } catch (Throwable $e) {
92
            return false;
93
        }
94
    }
95
96
    /**
97
     * Lists the available databases for this connection.
98
     *
99
     * @return string[]
100 3301
     */
101
    public function listDatabases()
102 3301
    {
103
        $sql = $this->_platform->getListDatabasesSQL();
104 3156
105
        $databases = $this->_conn->fetchAll($sql);
106 3156
107
        return $this->_getPortableDatabasesList($databases);
108
    }
109
110
    /**
111
     * Returns a list of all namespaces in the current database.
112
     *
113
     * @return string[]
114 1139
     */
115
    public function listNamespaceNames()
116 1139
    {
117
        $sql = $this->_platform->getListNamespacesSQL();
118 1139
119
        $namespaces = $this->_conn->fetchAll($sql);
120 1139
121
        return $this->getPortableNamespacesList($namespaces);
122
    }
123
124
    /**
125
     * Lists the available sequences for this connection.
126
     *
127
     * @param string|null $database
128
     *
129
     * @return Sequence[]
130 1168
     */
131
    public function listSequences($database = null)
132 1168
    {
133 1168
        if ($database === null) {
134
            $database = $this->_conn->getDatabase();
135 1168
        }
136
        $sql = $this->_platform->getListSequencesSQL($database);
137 1168
138
        $sequences = $this->_conn->fetchAll($sql);
139 1168
140
        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. We're 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 4230
     */
158
    public function listTableColumns($table, $database = null)
159 4230
    {
160 4229
        if (! $database) {
161
            $database = $this->_conn->getDatabase();
162
        }
163 4230
164
        $sql = $this->_platform->getListTableColumnsSQL($table, $database);
165 4230
166
        $tableColumns = $this->_conn->fetchAll($sql);
167 4230
168
        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 3920
     */
180
    public function listTableIndexes($table)
181 3920
    {
182
        $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
183 3920
184
        $tableIndexes = $this->_conn->fetchAll($sql);
185 3920
186
        return $this->_getPortableTableIndexesList($tableIndexes, $table);
187
    }
188
189
    /**
190
     * Returns true if all the given tables exist.
191
     *
192
     * @param string|string[] $tableNames
193
     *
194
     * @return bool
195 4646
     */
196
    public function tablesExist($tableNames)
197 4646
    {
198
        $tableNames = array_map('strtolower', (array) $tableNames);
199 4646
200
        return count($tableNames) === count(array_intersect($tableNames, array_map('strtolower', $this->listTableNames())));
201
    }
202
203
    /**
204
     * Returns a list of all tables in the current database.
205
     *
206
     * @return string[]
207 4490
     */
208
    public function listTableNames()
209 4490
    {
210
        $sql = $this->_platform->getListTablesSQL();
211 4490
212 4490
        $tables     = $this->_conn->fetchAll($sql);
213
        $tableNames = $this->_getPortableTablesList($tables);
214 4490
215
        return $this->filterAssetNames($tableNames);
216
    }
217
218
    /**
219
     * Filters asset names if they are configured to return only a subset of all
220
     * the found elements.
221
     *
222
     * @param mixed[] $assetNames
223
     *
224
     * @return mixed[]
225 4665
     */
226
    protected function filterAssetNames($assetNames)
227 4665
    {
228 4665
        $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter();
229 4665
        if (! $filter) {
230
            return $assetNames;
231
        }
232 1662
233
        return array_values(array_filter($assetNames, $filter));
234
    }
235
236
    /**
237
     * @deprecated Use Configuration::getSchemaAssetsFilter() instead
238
     *
239
     * @return string|null
240
     */
241
    protected function getFilterSchemaAssetsExpression()
242
    {
243
        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

243
        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...
244
    }
245
246
    /**
247
     * Lists the tables for this connection.
248
     *
249
     * @return Table[]
250 4101
     */
251
    public function listTables()
252 4101
    {
253
        $tableNames = $this->listTableNames();
254 4101
255 4101
        $tables = [];
256 4057
        foreach ($tableNames as $tableName) {
257
            $tables[] = $this->listTableDetails($tableName);
258
        }
259 4101
260
        return $tables;
261
    }
262
263
    /**
264
     * @param string $tableName
265
     *
266
     * @return Table
267 4218
     */
268
    public function listTableDetails($tableName)
269 4218
    {
270 4218
        $columns     = $this->listTableColumns($tableName);
271
        $foreignKeys = [];
272 4218
273 4069
        if ($this->_platform->supportsForeignKeyConstraints()) {
274
            $foreignKeys = $this->listTableForeignKeys($tableName);
275
        }
276 4218
277
        $indexes = $this->listTableIndexes($tableName);
278 4218
279
        return new Table($tableName, $columns, $indexes, [], $foreignKeys, []);
280
    }
281
282
    /**
283
     * Lists the views this connection has.
284
     *
285
     * @return View[]
286 3062
     */
287
    public function listViews()
288 3062
    {
289 3062
        $database = $this->_conn->getDatabase();
290 3062
        $sql      = $this->_platform->getListViewsSQL($database);
291
        $views    = $this->_conn->fetchAll($sql);
292 3062
293
        return $this->_getPortableViewsList($views);
294
    }
295
296
    /**
297
     * Lists the foreign keys for the given table.
298
     *
299
     * @param string      $table    The name of the table.
300
     * @param string|null $database
301
     *
302
     * @return ForeignKeyConstraint[]
303 4109
     */
304
    public function listTableForeignKeys($table, $database = null)
305 4109
    {
306 4109
        if ($database === null) {
307
            $database = $this->_conn->getDatabase();
308 4109
        }
309 4109
        $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

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