Passed
Pull Request — master (#2412)
by Benoît
13:20
created

AbstractSchemaManager   F

Complexity

Total Complexity 118

Size/Duplication

Total Lines 1086
Duplicated Lines 0 %

Test Coverage

Coverage 83.49%

Importance

Changes 0
Metric Value
wmc 118
eloc 236
dl 0
loc 1086
ccs 268
cts 321
cp 0.8349
rs 2
c 0
b 0
f 0

65 Methods

Rating   Name   Duplication   Size   Complexity  
A _getPortableSequenceDefinition() 0 3 1
A dropAndCreateConstraint() 0 4 1
A _getPortableTriggerDefinition() 0 3 1
A __construct() 0 4 2
A _getPortableFunctionDefinition() 0 3 1
A getDatabasePlatform() 0 3 1
A dropAndCreateTable() 0 4 1
A dropTable() 0 3 1
A dropConstraint() 0 3 1
A dropView() 0 3 1
A getFilterSchemaAssetsExpression() 0 3 1
A dropAndCreateDatabase() 0 4 1
A createTable() 0 4 1
A createIndex() 0 3 1
A dropAndCreateForeignKey() 0 4 1
A dropAndCreateIndex() 0 4 1
A _getPortableDatabaseDefinition() 0 3 1
A getPortableNamespaceDefinition() 0 3 1
A dropForeignKey() 0 3 1
A dropAndCreateView() 0 4 1
A createView() 0 3 1
A createDatabase() 0 3 1
A dropAndCreateSequence() 0 4 1
A createSequence() 0 3 1
A dropDatabase() 0 3 1
A createForeignKey() 0 3 1
A dropSequence() 0 3 1
A createConstraint() 0 3 1
A filterAssetNames() 0 12 3
A dropIndex() 0 7 2
A _getPortableDatabasesList() 0 10 3
A _getPortableSequencesList() 0 10 3
A listTableDetails() 0 10 2
A listNamespaceNames() 0 7 1
A _getPortableTableColumnList() 0 28 6
A alterTable() 0 6 4
A listSequences() 0 10 2
A listDatabases() 0 7 1
A _getPortableTriggersList() 0 10 3
A tryMethod() 0 11 2
A listTableColumns() 0 11 2
A getPortableNamespacesList() 0 9 2
A tablesExist() 0 5 1
A renameTable() 0 5 1
A listTableForeignKeys() 0 9 2
A listViews() 0 7 1
A listTableIndexes() 0 7 1
A listTables() 0 10 2
A listTableNames() 0 8 1
A _getPortableFunctionsList() 0 10 3
A createSchema() 0 17 3
A _getPortableUserDefinition() 0 3 1
A removeDoctrineTypeFromComment() 0 3 1
A _getPortableTableDefinition() 0 3 1
A _getPortableTableForeignKeyDefinition() 0 3 1
A _getPortableTableForeignKeysList() 0 10 3
A _getPortableTablesList() 0 10 3
A _getPortableViewDefinition() 0 3 1
A _execSql() 0 4 2
A createSchemaConfig() 0 20 5
A getSchemaSearchPaths() 0 3 1
A _getPortableViewsList() 0 11 3
A extractDoctrineTypeFromComment() 0 7 2
A _getPortableUsersList() 0 10 3
B _getPortableTableIndexesList() 0 58 11

How to fix   Complexity   

Complex Class

Complex classes like AbstractSchemaManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AbstractSchemaManager, and based on these observations, apply Extract Interface, too.

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