Completed
Push — master ( ed25dc...18a804 )
by Sergei
35:26 queued 32:37
created

AbstractSchemaManager::dropAndCreateConstraint()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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

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