Completed
Pull Request — 2.9 (#3692)
by
unknown
64:38 queued 13s
created

AbstractSchemaManager::listAllTableNames()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 3
c 2
b 0
f 0
dl 0
loc 7
ccs 1
cts 1
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
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 1934
    public function __construct(Connection $conn, ?AbstractPlatform $platform = null)
49
    {
50 1934
        $this->_conn     = $conn;
51 1934
        $this->_platform = $platform ?: $this->_conn->getDatabasePlatform();
52 1934
    }
53
54
    /**
55
     * Returns the associated platform.
56
     *
57
     * @return AbstractPlatform
58
     */
59 543
    public function getDatabasePlatform()
60
    {
61 543
        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 2808
    public function tryMethod()
77
    {
78 2808
        $args   = func_get_args();
79 2808
        $method = $args[0];
80 2808
        unset($args[0]);
81 2808
        $args = array_values($args);
82
83
        try {
84 2808
            return call_user_func_array([$this, $method], $args);
85 2095
        } catch (Throwable $e) {
86 2095
            return false;
87
        }
88
    }
89
90
    /**
91
     * Lists the available databases for this connection.
92
     *
93
     * @return string[]
94
     */
95 51
    public function listDatabases()
96
    {
97 51
        $sql = $this->_platform->getListDatabasesSQL();
98
99 50
        $databases = $this->_conn->fetchAll($sql);
100
101 50
        return $this->_getPortableDatabasesList($databases);
102
    }
103
104
    /**
105
     * Returns a list of all namespaces in the current database.
106
     *
107
     * @return string[]
108
     */
109 18
    public function listNamespaceNames()
110
    {
111 18
        $sql = $this->_platform->getListNamespacesSQL();
112
113 18
        $namespaces = $this->_conn->fetchAll($sql);
114
115 18
        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 63
    public function listSequences($database = null)
126
    {
127 63
        if ($database === null) {
128 63
            $database = $this->_conn->getDatabase();
129
        }
130 63
        $sql = $this->_platform->getListSequencesSQL($database);
131
132 63
        $sequences = $this->_conn->fetchAll($sql);
133
134 63
        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 1394
    public function listTableColumns($table, $database = null)
153
    {
154 1394
        if (! $database) {
155 1392
            $database = $this->_conn->getDatabase();
156
        }
157
158 1394
        $sql = $this->_platform->getListTableColumnsSQL($table, $database);
159
160 1394
        $tableColumns = $this->_conn->fetchAll($sql);
161
162 1394
        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 1113
    public function listTableIndexes($table)
175
    {
176 1113
        $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
177
178 1113
        $tableIndexes = $this->_conn->fetchAll($sql);
179
180 1113
        return $this->_getPortableTableIndexesList($tableIndexes, $table);
181
    }
182
183
    /**
184
     * Returns true if all the given tables exist.
185
     *
186
     * @param string|string[] $tableNames
187
     *
188
     * @return bool
189
     */
190 2078
    public function tablesExist($tableNames)
191
    {
192 2078
        $tableNames = array_map('strtolower', (array) $tableNames);
193
194 2078
        return count($tableNames) === count(array_intersect($tableNames, array_map('strtolower', $this->listTableNames())));
195
    }
196
197
    /**
198
     * Returns true if all the given tables exist. This method ignores filters.
199
     *
200
     * @param string[] $tableNames
201
     *
202 2106
     * @return bool
203
     */
204 2106
    public function allTablesExistInSchema(array $tableNames) : bool
205
    {
206 2106
        $tableNames = array_map('strtolower', $tableNames);
207 2106
208
        return count($tableNames) === count(array_intersect($tableNames, array_map('strtolower', $this->listAllTableNames())));
209 2106
    }
210
211
    /**
212
     * Returns a filtered list of all tables in the current database.
213
     *
214
     * @return string[]
215
     */
216
    public function listTableNames()
217
    {
218
        return $this->filterAssetNames($this->listAllTableNames());
219
    }
220 2169
221
    /**
222 2169
     * Returns a list of all tables in the current database.
223 2169
     *
224 2169
     * @return string[]
225
     */
226
    final public function listAllTableNames(): iterable
227 7
    {
228
        $sql = $this->_platform->getListTablesSQL();
229
230
        $tables = $this->_conn->fetchAll($sql);
231
232
        return $this->_getPortableTablesList($tables);
233
    }
234
235
    /**
236
     * Filters asset names if they are configured to return only a subset of all
237
     * the found elements.
238
     *
239
     * @param mixed[] $assetNames
240
     *
241
     * @return mixed[]
242
     */
243
    protected function filterAssetNames($assetNames)
244
    {
245 144
        $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter();
246
        if (! $filter) {
247 144
            return $assetNames;
248
        }
249 144
250 144
        return array_values(array_filter($assetNames, $filter));
251 117
    }
252
253
    /**
254 144
     * @deprecated Use Configuration::getSchemaAssetsFilter() instead
255
     *
256
     * @return string|null
257
     */
258
    protected function getFilterSchemaAssetsExpression()
259
    {
260
        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

260
        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...
261
    }
262 1010
263
    /**
264 1010
     * Lists the tables for this connection.
265 1010
     *
266 1010
     * @return Table[]
267 927
     */
268
    public function listTables()
269 1010
    {
270
        $tableNames = $this->listTableNames();
271 1010
272
        $tables = [];
273
        foreach ($tableNames as $tableName) {
274
            $tables[] = $this->listTableDetails($tableName);
275
        }
276
277
        return $tables;
278
    }
279 27
280
    /**
281 27
     * @param string $tableName
282 27
     *
283 27
     * @return Table
284
     */
285 27
    public function listTableDetails($tableName)
286
    {
287
        $columns     = $this->listTableColumns($tableName);
288
        $foreignKeys = [];
289
        if ($this->_platform->supportsForeignKeyConstraints()) {
290
            $foreignKeys = $this->listTableForeignKeys($tableName);
291
        }
292
        $indexes = $this->listTableIndexes($tableName);
293
294
        return new Table($tableName, $columns, $indexes, $foreignKeys, false, []);
295
    }
296 1015
297
    /**
298 1015
     * Lists the views this connection has.
299 1015
     *
300
     * @return View[]
301 1015
     */
302 1015
    public function listViews()
303
    {
304 1015
        $database = $this->_conn->getDatabase();
305
        $sql      = $this->_platform->getListViewsSQL($database);
306
        $views    = $this->_conn->fetchAll($sql);
307
308
        return $this->_getPortableViewsList($views);
309
    }
310
311
    /**
312
     * Lists the foreign keys for the given table.
313
     *
314
     * @param string      $table    The name of the table.
315
     * @param string|null $database
316
     *
317
     * @return ForeignKeyConstraint[]
318 50
     */
319
    public function listTableForeignKeys($table, $database = null)
320 50
    {
321 35
        if ($database === null) {
322
            $database = $this->_conn->getDatabase();
323
        }
324
        $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

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