Passed
Pull Request — master (#3225)
by Šimon
12:57
created

AbstractSchemaManager::_getPortableTablesList()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 10
ccs 6
cts 6
cp 1
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 1
crap 3
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Schema;
21
22
use Doctrine\DBAL\Events;
23
use Doctrine\DBAL\Event\SchemaColumnDefinitionEventArgs;
24
use Doctrine\DBAL\Event\SchemaIndexDefinitionEventArgs;
25
use Doctrine\DBAL\DBALException;
26
use Doctrine\DBAL\Platforms\AbstractPlatform;
27
use function array_filter;
28
use function array_map;
29
use function array_values;
30
use function call_user_func_array;
31
use function count;
32
use function func_get_args;
33
use function is_array;
34
use function is_null;
35
use function preg_match;
36
use function str_replace;
37
use function strtolower;
38
39
/**
40
 * Base class for schema managers. Schema managers are used to inspect and/or
41
 * modify the database schema/structure.
42
 *
43
 * @author Konsta Vesterinen <[email protected]>
44
 * @author Lukas Smith <[email protected]> (PEAR MDB2 library)
45
 * @author Roman Borschel <[email protected]>
46
 * @author Jonathan H. Wage <[email protected]>
47
 * @author Benjamin Eberlei <[email protected]>
48
 * @since  2.0
49
 */
50
abstract class AbstractSchemaManager
51
{
52
    /**
53
     * Holds instance of the Doctrine connection for this schema manager.
54
     *
55
     * @var \Doctrine\DBAL\Connection
56
     */
57
    protected $_conn;
58
59
    /**
60
     * Holds instance of the database platform used for this schema manager.
61
     *
62
     * @var \Doctrine\DBAL\Platforms\AbstractPlatform
63
     */
64
    protected $_platform;
65
66
    /**
67
     * Constructor. Accepts the Connection instance to manage the schema for.
68
     *
69
     * @param \Doctrine\DBAL\Connection                      $conn
70
     * @param \Doctrine\DBAL\Platforms\AbstractPlatform|null $platform
71
     */
72 1350
    public function __construct(\Doctrine\DBAL\Connection $conn, AbstractPlatform $platform = null)
73
    {
74 1350
        $this->_conn     = $conn;
75 1350
        $this->_platform = $platform ?: $this->_conn->getDatabasePlatform();
76 1350
    }
77
78
    /**
79
     * Returns the associated platform.
80
     *
81
     * @return \Doctrine\DBAL\Platforms\AbstractPlatform
82
     */
83 375
    public function getDatabasePlatform()
84
    {
85 375
        return $this->_platform;
86
    }
87
88
    /**
89
     * Tries any method on the schema manager. Normally a method throws an
90
     * exception when your DBMS doesn't support it or if an error occurs.
91
     * This method allows you to try and method on your SchemaManager
92
     * instance and will return false if it does not work or is not supported.
93
     *
94
     * <code>
95
     * $result = $sm->tryMethod('dropView', 'view_name');
96
     * </code>
97
     *
98
     * @return mixed
99
     */
100 1804
    public function tryMethod()
101
    {
102 1804
        $args = func_get_args();
103 1804
        $method = $args[0];
104 1804
        unset($args[0]);
105 1804
        $args = array_values($args);
106
107
        try {
108 1804
            return call_user_func_array([$this, $method], $args);
109 1379
        } catch (\Exception $e) {
110 1379
            return false;
111
        }
112
    }
113
114
    /**
115
     * Lists the available databases for this connection.
116
     *
117
     * @return array
118
     */
119 35
    public function listDatabases()
120
    {
121 35
        $sql = $this->_platform->getListDatabasesSQL();
122
123 34
        $databases = $this->_conn->fetchAll($sql);
124
125 34
        return $this->_getPortableDatabasesList($databases);
126
    }
127
128
    /**
129
     * Returns a list of all namespaces in the current database.
130
     *
131
     * @return array
132
     */
133 16
    public function listNamespaceNames()
134
    {
135 16
        $sql = $this->_platform->getListNamespacesSQL();
136
137 16
        $namespaces = $this->_conn->fetchAll($sql);
138
139 16
        return $this->getPortableNamespacesList($namespaces);
140
    }
141
142
    /**
143
     * Lists the available sequences for this connection.
144
     *
145
     * @param string|null $database
146
     *
147
     * @return \Doctrine\DBAL\Schema\Sequence[]
148
     */
149 53
    public function listSequences($database = null)
150
    {
151 53
        if ($database === null) {
152 53
            $database = $this->_conn->getDatabase();
153
        }
154 53
        $sql = $this->_platform->getListSequencesSQL($database);
155
156 53
        $sequences = $this->_conn->fetchAll($sql);
157
158 53
        return $this->filterAssetNames($this->_getPortableSequencesList($sequences));
159
    }
160
161
    /**
162
     * Lists the columns for a given table.
163
     *
164
     * In contrast to other libraries and to the old version of Doctrine,
165
     * this column definition does try to contain the 'primary' field for
166
     * the reason that it is not portable across different RDBMS. Use
167
     * {@see listTableIndexes($tableName)} to retrieve the primary key
168
     * of a table. We're a RDBMS specifies more details these are held
169
     * in the platformDetails array.
170
     *
171
     * @param string      $table    The name of the table.
172
     * @param string|null $database
173
     *
174
     * @return \Doctrine\DBAL\Schema\Column[]
175
     */
176 908
    public function listTableColumns($table, $database = null)
177
    {
178 908
        if ( ! $database) {
179 907
            $database = $this->_conn->getDatabase();
180
        }
181
182 908
        $sql = $this->_platform->getListTableColumnsSQL($table, $database);
183
184 908
        $tableColumns = $this->_conn->fetchAll($sql);
185
186 908
        return $this->_getPortableTableColumnList($table, $database, $tableColumns);
187
    }
188
189
    /**
190
     * Lists the indexes for a given table returning an array of Index instances.
191
     *
192
     * Keys of the portable indexes list are all lower-cased.
193
     *
194
     * @param string $table The name of the table.
195
     *
196
     * @return \Doctrine\DBAL\Schema\Index[]
197
     */
198 684
    public function listTableIndexes($table)
199
    {
200 684
        $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
201
202 684
        $tableIndexes = $this->_conn->fetchAll($sql);
203
204 684
        return $this->_getPortableTableIndexesList($tableIndexes, $table);
205
    }
206
207
    /**
208
     * Returns true if all the given tables exist.
209
     *
210
     * @param array $tableNames
211
     *
212
     * @return bool
213
     */
214 1419
    public function tablesExist($tableNames)
215
    {
216 1419
        $tableNames = array_map('strtolower', (array) $tableNames);
217
218 1419
        return count($tableNames) == count(\array_intersect($tableNames, array_map('strtolower', $this->listTableNames())));
219
    }
220
221
    /**
222
     * Returns a list of all tables in the current database.
223
     *
224
     * @return array
225
     */
226 1423
    public function listTableNames()
227
    {
228 1423
        $sql = $this->_platform->getListTablesSQL();
229
230 1423
        $tables = $this->_conn->fetchAll($sql);
231 1423
        $tableNames = $this->_getPortableTablesList($tables);
232
233 1423
        return $this->filterAssetNames($tableNames);
234
    }
235
236
    /**
237
     * Filters asset names if they are configured to return only a subset of all
238
     * the found elements.
239
     *
240
     * @param array $assetNames
241
     *
242
     * @return array
243
     */
244 1485
    protected function filterAssetNames($assetNames)
245
    {
246 1485
        $filterExpr = $this->getFilterSchemaAssetsExpression();
247 1485
        if ( ! $filterExpr) {
248 1485
            return $assetNames;
249
        }
250
251 6
        return array_values(
252
            array_filter($assetNames, function ($assetName) use ($filterExpr) {
253 6
                $assetName = ($assetName instanceof AbstractAsset) ? $assetName->getName() : $assetName;
254
255 6
                return preg_match($filterExpr, $assetName);
256 6
            })
257
        );
258
    }
259
260
    /**
261
     * @return string|null
262
     */
263 1485
    protected function getFilterSchemaAssetsExpression()
264
    {
265 1485
        return $this->_conn->getConfiguration()->getFilterSchemaAssetsExpression();
266
    }
267
268
    /**
269
     * Lists the tables for this connection.
270
     *
271
     * @return \Doctrine\DBAL\Schema\Table[]
272
     */
273 102
    public function listTables()
274
    {
275 102
        $tableNames = $this->listTableNames();
276
277 102
        $tables = [];
278 102
        foreach ($tableNames as $tableName) {
279 83
            $tables[] = $this->listTableDetails($tableName);
280
        }
281
282 102
        return $tables;
283
    }
284
285
    /**
286
     * @param string $tableName
287
     *
288
     * @return \Doctrine\DBAL\Schema\Table
289
     */
290 637
    public function listTableDetails($tableName)
291
    {
292 637
        $columns = $this->listTableColumns($tableName);
293 637
        $foreignKeys = [];
294 637
        if ($this->_platform->supportsForeignKeyConstraints()) {
295 572
            $foreignKeys = $this->listTableForeignKeys($tableName);
296
        }
297 637
        $indexes = $this->listTableIndexes($tableName);
298
299 637
        return new Table($tableName, $columns, $indexes, $foreignKeys, false, []);
300
    }
301
302
    /**
303
     * Lists the views this connection has.
304
     *
305
     * @return \Doctrine\DBAL\Schema\View[]
306
     */
307 19
    public function listViews()
308
    {
309 19
        $database = $this->_conn->getDatabase();
310 19
        $sql = $this->_platform->getListViewsSQL($database);
311 19
        $views = $this->_conn->fetchAll($sql);
312
313 19
        return $this->_getPortableViewsList($views);
314
    }
315
316
    /**
317
     * Lists the foreign keys for the given table.
318
     *
319
     * @param string      $table    The name of the table.
320
     * @param string|null $database
321
     *
322
     * @return \Doctrine\DBAL\Schema\ForeignKeyConstraint[]
323
     */
324 635
    public function listTableForeignKeys($table, $database = null)
325
    {
326 635
        if ($database === null) {
327 635
            $database = $this->_conn->getDatabase();
328
        }
329 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

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