Failed Conditions
Pull Request — develop (#3348)
by Sergei
22: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
     */
51 5504
    public function __construct(Connection $conn, ?AbstractPlatform $platform = null)
52
    {
53 5504
        $this->_conn     = $conn;
54 5504
        $this->_platform = $platform ?: $this->_conn->getDatabasePlatform();
55 5504
    }
56
57
    /**
58
     * Returns the associated platform.
59
     */
60 3689
    public function getDatabasePlatform() : AbstractPlatform
61
    {
62 3689
        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 5316
    public function tryMethod()
78
    {
79 5316
        $args   = func_get_args();
80 5316
        $method = $args[0];
81 5316
        unset($args[0]);
82 5316
        $args = array_values($args);
83
84 5316
        $callback = [$this, $method];
85 5316
        assert(is_callable($callback));
86
87
        try {
88 5316
            return call_user_func_array($callback, $args);
89 5190
        } catch (Throwable $e) {
90 5190
            return false;
91
        }
92
    }
93
94
    /**
95
     * Lists the available databases for this connection.
96
     *
97
     * @return string[]
98
     */
99 3271
    public function listDatabases() : array
100
    {
101 3271
        $sql = $this->_platform->getListDatabasesSQL();
102
103 3125
        $databases = $this->_conn->fetchAll($sql);
104
105 3125
        return $this->_getPortableDatabasesList($databases);
106
    }
107
108
    /**
109
     * Returns a list of all namespaces in the current database.
110
     *
111
     * @return string[]
112
     */
113 1138
    public function listNamespaceNames() : array
114
    {
115 1138
        $sql = $this->_platform->getListNamespacesSQL();
116
117 1138
        $namespaces = $this->_conn->fetchAll($sql);
118
119 1138
        return $this->getPortableNamespacesList($namespaces);
120
    }
121
122
    /**
123
     * Lists the available sequences for this connection.
124
     *
125
     * @return Sequence[]
126
     */
127 1167
    public function listSequences(?string $database = null) : array
128
    {
129 1167
        if ($database === null) {
130 1167
            $database = $this->_conn->getDatabase();
131
        }
132 1167
        $sql = $this->_platform->getListSequencesSQL($database);
133
134 1167
        $sequences = $this->_conn->fetchAll($sql);
135
136 1167
        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 4196
    public function listTableColumns(string $table, ?string $database = null) : array
154
    {
155 4196
        if (! $database) {
156 4195
            $database = $this->_conn->getDatabase();
157
        }
158
159 4196
        $sql = $this->_platform->getListTableColumnsSQL($table, $database);
160
161 4196
        $tableColumns = $this->_conn->fetchAll($sql);
162
163 4196
        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 3885
    public function listTableIndexes(string $table) : array
176
    {
177 3885
        $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
178
179 3885
        $tableIndexes = $this->_conn->fetchAll($sql);
180
181 3885
        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 4612
    public function tablesExist($tableNames) : bool
190
    {
191 4612
        $tableNames = array_map('strtolower', (array) $tableNames);
192
193 4612
        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 4455
    public function listTableNames() : array
202
    {
203 4455
        $sql = $this->_platform->getListTablesSQL();
204
205 4455
        $tables     = $this->_conn->fetchAll($sql);
206 4455
        $tableNames = $this->_getPortableTablesList($tables);
207
208 4455
        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 4632
    protected function filterAssetNames(array $assetNames) : array
220
    {
221 4632
        $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter();
222 4632
        if (! $filter) {
223 4632
            return $assetNames;
224
        }
225
226 1660
        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 4068
    public function listTables() : array
243
    {
244 4068
        $tableNames = $this->listTableNames();
245
246 4068
        $tables = [];
247 4068
        foreach ($tableNames as $tableName) {
248 4023
            $tables[] = $this->listTableDetails($tableName);
249
        }
250
251 4068
        return $tables;
252
    }
253
254 4184
    public function listTableDetails(string $tableName) : Table
255
    {
256 4184
        $columns     = $this->listTableColumns($tableName);
257 4184
        $foreignKeys = [];
258
259 4184
        if ($this->_platform->supportsForeignKeyConstraints()) {
260 4034
            $foreignKeys = $this->listTableForeignKeys($tableName);
261
        }
262
263 4184
        $indexes = $this->listTableIndexes($tableName);
264
265 4184
        return new Table($tableName, $columns, $indexes, [], $foreignKeys, []);
266
    }
267
268
    /**
269
     * Lists the views this connection has.
270
     *
271
     * @return View[]
272
     */
273 3033
    public function listViews() : array
274
    {
275 3033
        $database = $this->_conn->getDatabase();
276 3033
        $sql      = $this->_platform->getListViewsSQL($database);
277 3033
        $views    = $this->_conn->fetchAll($sql);
278
279 3033
        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 4074
    public function listTableForeignKeys(string $table, ?string $database = null) : array
290
    {
291 4074
        if ($database === null) {
292 4074
            $database = $this->_conn->getDatabase();
293
        }
294 4074
        $sql              = $this->_platform->getListTableForeignKeysSQL($table, $database);
295 4074
        $tableForeignKeys = $this->_conn->fetchAll($sql);
296
297 4074
        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 4847
    public function dropDatabase(string $database) : void
310
    {
311 4847
        $this->_execSql($this->_platform->getDropDatabaseSQL($database));
312 4295
    }
313
314
    /**
315
     * Drops the given table.
316
     *
317
     * @param string $tableName The name of the table to drop.
318
     */
319 5126
    public function dropTable(string $tableName) : void
320
    {
321 5126
        $this->_execSql($this->_platform->getDropTableSQL($tableName));
322 5054
    }
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 3153
    public function dropIndex($index, $table) : void
331
    {
332 3153
        if ($index instanceof Index) {
333
            $index = $index->getQuotedName($this->_platform);
334
        }
335
336 3153
        $this->_execSql($this->_platform->getDropIndexSQL($index, $table));
337 3153
    }
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 1164
    public function dropSequence(string $name) : void
366
    {
367 1164
        $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 3199
    public function dropView(string $name) : void
376
    {
377 3199
        $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 4845
    public function createDatabase(string $database) : void
388
    {
389 4845
        $this->_execSql($this->_platform->getCreateDatabaseSQL($database));
390 4845
    }
391
392
    /**
393
     * Creates a new table.
394
     */
395 5143
    public function createTable(Table $table) : void
396
    {
397 5143
        $createFlags = AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS;
398 5143
        $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags));
399 5123
    }
400
401
    /**
402
     * Creates a new sequence.
403
     *
404
     * @throws ConnectionException If something fails at database level.
405
     */
406 1166
    public function createSequence(Sequence $sequence) : void
407
    {
408 1166
        $this->_execSql($this->_platform->getCreateSequenceSQL($sequence));
409 1166
    }
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 3153
    public function createIndex(Index $index, $table) : void
427
    {
428 3153
        $this->_execSql($this->_platform->getCreateIndexSQL($index, $table));
429 3153
    }
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 3163
    public function createForeignKey(ForeignKeyConstraint $foreignKey, $table) : void
438
    {
439 3163
        $this->_execSql($this->_platform->getCreateForeignKeySQL($foreignKey, $table));
440 3163
    }
441
442
    /**
443
     * Creates a new view.
444
     */
445 3199
    public function createView(View $view) : void
446
    {
447 3199
        $this->_execSql($this->_platform->getCreateViewSQL($view->getQuotedName($this->_platform), $view->getSql()));
448 3199
    }
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 3153
    public function dropAndCreateIndex(Index $index, $table) : void
472
    {
473 3153
        $this->tryMethod('dropIndex', $index->getQuotedName($this->_platform), $table);
474 3153
        $this->createIndex($index, $table);
475 3153
    }
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 1164
    public function dropAndCreateSequence(Sequence $sequence) : void
495
    {
496 1164
        $this->tryMethod('dropSequence', $sequence->getQuotedName($this->_platform));
497 1164
        $this->createSequence($sequence);
498 1164
    }
499
500
    /**
501
     * Drops and creates a new table.
502
     */
503 5087
    public function dropAndCreateTable(Table $table) : void
504
    {
505 5087
        $this->tryMethod('dropTable', $table->getQuotedName($this->_platform));
506 5087
        $this->createTable($table);
507 5087
    }
508
509
    /**
510
     * Drops and creates a new database.
511
     *
512
     * @param string $database The name of the database to create.
513
     */
514 4991
    public function dropAndCreateDatabase(string $database) : void
515
    {
516 4991
        $this->tryMethod('dropDatabase', $database);
517 4991
        $this->createDatabase($database);
518 4991
    }
519
520
    /**
521
     * Drops and creates a new view.
522
     */
523 3199
    public function dropAndCreateView(View $view) : void
524
    {
525 3199
        $this->tryMethod('dropView', $view->getQuotedName($this->_platform));
526 3199
        $this->createView($view);
527 3199
    }
528
529
    /* alterTable() Methods */
530
531
    /**
532
     * Alters an existing tables schema.
533
     */
534 3856
    public function alterTable(TableDiff $tableDiff) : void
535
    {
536 3856
        $queries = $this->_platform->getAlterTableSQL($tableDiff);
537
538 3856
        if (! is_array($queries) || ! count($queries)) {
539 1559
            return;
540
        }
541
542 3856
        foreach ($queries as $ddlQuery) {
543 3856
            $this->_execSql($ddlQuery);
544
        }
545 3856
    }
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 3125
    protected function _getPortableDatabasesList(array $databases) : array
571
    {
572 3125
        $list = [];
573 3125
        foreach ($databases as $value) {
574 3125
            $value = $this->_getPortableDatabaseDefinition($value);
575
576 3125
            if (! $value) {
577
                continue;
578
            }
579
580 3125
            $list[] = $value;
581
        }
582
583 3125
        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 1138
    protected function getPortableNamespacesList(array $namespaces) : array
594
    {
595 1138
        $namespacesList = [];
596
597 1138
        foreach ($namespaces as $namespace) {
598 1138
            $namespacesList[] = $this->getPortableNamespaceDefinition($namespace);
599
        }
600
601 1138
        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 297
    protected function _getPortableSequencesList(array $sequences) : array
694
    {
695 297
        $list = [];
696
697 297
        foreach ($sequences as $value) {
698 297
            $list[] = $this->_getPortableSequenceDefinition($value);
699
        }
700
701 297
        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 4196
    protected function _getPortableTableColumnList(string $table, ?string $database, array $tableColumns) : array
725
    {
726 4196
        $eventManager = $this->_platform->getEventManager();
727
728 4196
        $list = [];
729 4196
        foreach ($tableColumns as $tableColumn) {
730 4196
            $column           = null;
731 4196
            $defaultPrevented = false;
732
733 4196
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaColumnDefinition)) {
734 3249
                $eventArgs = new SchemaColumnDefinitionEventArgs($tableColumn, $table, $database, $this->_conn);
735 3249
                $eventManager->dispatchEvent(Events::onSchemaColumnDefinition, $eventArgs);
736
737 3249
                $defaultPrevented = $eventArgs->isDefaultPrevented();
738 3249
                $column           = $eventArgs->getColumn();
739
            }
740
741 4196
            if (! $defaultPrevented) {
742 4196
                $column = $this->_getPortableTableColumnDefinition($tableColumn);
743
            }
744
745 4196
            if (! $column) {
746
                continue;
747
            }
748
749 4196
            $name        = strtolower($column->getQuotedName($this->_platform));
750 4196
            $list[$name] = $column;
751
        }
752
753 4196
        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 4189
    protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array
771
    {
772 4189
        $result = [];
773 4189
        foreach ($tableIndexRows as $tableIndex) {
774 4132
            $indexName = $keyName = $tableIndex['key_name'];
775 4132
            if ($tableIndex['primary']) {
776 4130
                $keyName = 'primary';
777
            }
778 4132
            $keyName = strtolower($keyName);
779
780 4132
            if (! isset($result[$keyName])) {
781
                $options = [
782 4132
                    'lengths' => [],
783
                ];
784
785 4132
                if (isset($tableIndex['where'])) {
786 934
                    $options['where'] = $tableIndex['where'];
787
                }
788
789 4132
                $result[$keyName] = [
790 4132
                    'name' => $indexName,
791
                    'columns' => [],
792 4132
                    'unique' => ! $tableIndex['non_unique'],
793 4132
                    'primary' => $tableIndex['primary'],
794 4132
                    'flags' => $tableIndex['flags'] ?? [],
795 4132
                    'options' => $options,
796
                ];
797
            }
798
799 4132
            $result[$keyName]['columns'][]            = $tableIndex['column_name'];
800 4132
            $result[$keyName]['options']['lengths'][] = $tableIndex['length'] ?? null;
801
        }
802
803 4189
        $eventManager = $this->_platform->getEventManager();
804
805 4189
        $indexes = [];
806 4189
        foreach ($result as $indexKey => $data) {
807 4132
            $index            = null;
808 4132
            $defaultPrevented = false;
809
810 4132
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) {
811 3225
                $eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn);
812 3225
                $eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs);
813
814 3225
                $defaultPrevented = $eventArgs->isDefaultPrevented();
815 3225
                $index            = $eventArgs->getIndex();
816
            }
817
818 4132
            if (! $defaultPrevented) {
819 4132
                $index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary'], $data['flags'], $data['options']);
820
            }
821
822 4132
            if (! $index) {
823
                continue;
824
            }
825
826 4132
            $indexes[$indexKey] = $index;
827
        }
828
829 4189
        return $indexes;
830
    }
831
832
    /**
833
     * @param mixed[][] $tables
834
     *
835
     * @return string[]
836
     */
837 4455
    protected function _getPortableTablesList(array $tables) : array
838
    {
839 4455
        $list = [];
840 4455
        foreach ($tables as $value) {
841 4453
            $value = $this->_getPortableTableDefinition($value);
842
843 4453
            if (! $value) {
844
                continue;
845
            }
846
847 4453
            $list[] = $value;
848
        }
849
850 4455
        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 3033
    protected function _getPortableViewsList(array $views) : array
898
    {
899 3033
        $list = [];
900 3033
        foreach ($views as $value) {
901 3033
            $view        = $this->_getPortableViewDefinition($value);
902 3033
            $name        = strtolower($view->getQuotedName($this->_platform));
903 3033
            $list[$name] = $view;
904
        }
905
906 3033
        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 1482
    protected function _getPortableTableForeignKeysList(array $tableForeignKeys) : array
923
    {
924 1482
        $list = [];
925
926 1482
        foreach ($tableForeignKeys as $value) {
927 1383
            $list[] = $this->_getPortableTableForeignKeyDefinition($value);
928
        }
929
930 1482
        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 5344
    protected function _execSql($sql) : void
945
    {
946 5344
        foreach ((array) $sql as $query) {
947 5344
            $this->_conn->executeUpdate($query);
948
        }
949 5318
    }
950
951
    /**
952
     * Creates a schema instance for the current database.
953
     */
954 3890
    public function createSchema() : Schema
955
    {
956 3890
        $namespaces = [];
957
958 3890
        if ($this->_platform->supportsSchemas()) {
959 1056
            $namespaces = $this->listNamespaceNames();
960
        }
961
962 3890
        $sequences = [];
963
964 3890
        if ($this->_platform->supportsSequences()) {
965 1057
            $sequences = $this->listSequences();
966
        }
967
968 3890
        $tables = $this->listTables();
969
970 3890
        return new Schema($tables, $sequences, $this->createSchemaConfig(), $namespaces);
971
    }
972
973
    /**
974
     * Creates the configuration for this schema.
975
     */
976 4122
    public function createSchemaConfig() : SchemaConfig
977
    {
978 4122
        $schemaConfig = new SchemaConfig();
979 4122
        $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength());
980
981 4122
        $searchPaths = $this->getSchemaSearchPaths();
982 4122
        if (isset($searchPaths[0])) {
983 3975
            $schemaConfig->setName($searchPaths[0]);
984
        }
985
986 4122
        $params = $this->_conn->getParams();
987 4122
        if (! isset($params['defaultTableOptions'])) {
988 4122
            $params['defaultTableOptions'] = [];
989
        }
990 4122
        if (! isset($params['defaultTableOptions']['charset']) && isset($params['charset'])) {
991 913
            $params['defaultTableOptions']['charset'] = $params['charset'];
992
        }
993 4122
        $schemaConfig->setDefaultTableOptions($params['defaultTableOptions']);
994
995 4122
        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 3380
    public function getSchemaSearchPaths() : array
1011
    {
1012 3380
        $database = $this->_conn->getDatabase();
1013
1014 3380
        if ($database !== null) {
1015 3005
            return [$database];
1016
        }
1017
1018 1021
        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 4203
    protected function extractDoctrineTypeFromComment(?string &$comment) : ?string
1028
    {
1029 4203
        if ($comment === null || ! preg_match('/(.*)\(DC2Type:(((?!\)).)+)\)(.*)/', $comment, $match)) {
1030 4196
            return null;
1031
        }
1032
1033 3550
        $comment = $match[1] . $match[4];
1034
1035 3550
        return $match[2];
1036
    }
1037
}
1038