Completed
Push — master ( 09e072...c7757e )
by Luís
15s
created

Schema::__construct()   B

Complexity

Conditions 6
Paths 16

Size

Total Lines 22
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 6.027

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 10
cts 11
cp 0.9091
rs 8.6737
c 0
b 0
f 0
cc 6
eloc 10
nc 16
nop 4
crap 6.027
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\Schema\Visitor\CreateSchemaSqlCollector;
23
use Doctrine\DBAL\Schema\Visitor\DropSchemaSqlCollector;
24
use Doctrine\DBAL\Schema\Visitor\NamespaceVisitor;
25
use Doctrine\DBAL\Schema\Visitor\Visitor;
26
use Doctrine\DBAL\Platforms\AbstractPlatform;
27
28
/**
29
 * Object representation of a database schema.
30
 *
31
 * Different vendors have very inconsistent naming with regard to the concept
32
 * of a "schema". Doctrine understands a schema as the entity that conceptually
33
 * wraps a set of database objects such as tables, sequences, indexes and
34
 * foreign keys that belong to each other into a namespace. A Doctrine Schema
35
 * has nothing to do with the "SCHEMA" defined as in PostgreSQL, it is more
36
 * related to the concept of "DATABASE" that exists in MySQL and PostgreSQL.
37
 *
38
 * Every asset in the doctrine schema has a name. A name consists of either a
39
 * namespace.local name pair or just a local unqualified name.
40
 *
41
 * The abstraction layer that covers a PostgreSQL schema is the namespace of an
42
 * database object (asset). A schema can have a name, which will be used as
43
 * default namespace for the unqualified database objects that are created in
44
 * the schema.
45
 *
46
 * In the case of MySQL where cross-database queries are allowed this leads to
47
 * databases being "misinterpreted" as namespaces. This is intentional, however
48
 * the CREATE/DROP SQL visitors will just filter this queries and do not
49
 * execute them. Only the queries for the currently connected database are
50
 * executed.
51
 *
52
 * @link   www.doctrine-project.org
53
 * @since  2.0
54
 * @author Benjamin Eberlei <[email protected]>
55
 */
56
class Schema extends AbstractAsset
57
{
58
    /**
59
     * The namespaces in this schema.
60
     *
61
     * @var array
62
     */
63
    private $namespaces = [];
64
65
    /**
66
     * @var \Doctrine\DBAL\Schema\Table[]
67
     */
68
    protected $_tables = [];
69
70
    /**
71
     * @var \Doctrine\DBAL\Schema\Sequence[]
72
     */
73
    protected $_sequences = [];
74
75
    /**
76
     * @var \Doctrine\DBAL\Schema\SchemaConfig
77
     */
78
    protected $_schemaConfig = false;
79
80
    /**
81
     * @param \Doctrine\DBAL\Schema\Table[]      $tables
82
     * @param \Doctrine\DBAL\Schema\Sequence[]   $sequences
83
     * @param \Doctrine\DBAL\Schema\SchemaConfig $schemaConfig
84
     * @param array                              $namespaces
85
     */
86 67
    public function __construct(
87
        array $tables = [],
88
        array $sequences = [],
89
        SchemaConfig $schemaConfig = null,
90
        array $namespaces = []
91
    ) {
92 67
        if ($schemaConfig == null) {
93 58
            $schemaConfig = new SchemaConfig();
94
        }
95 67
        $this->_schemaConfig = $schemaConfig;
96 67
        $this->_setName($schemaConfig->getName() ?: 'public');
97
98 67
        foreach ($namespaces as $namespace) {
99
            $this->createNamespace($namespace);
100
        }
101
102 67
        foreach ($tables as $table) {
103 19
            $this->_addTable($table);
104
        }
105
106 66
        foreach ($sequences as $sequence) {
107 4
            $this->_addSequence($sequence);
108
        }
109 65
    }
110
111
    /**
112
     * @return boolean
113
     */
114
    public function hasExplicitForeignKeyIndexes()
115
    {
116
        return $this->_schemaConfig->hasExplicitForeignKeyIndexes();
117
    }
118
119
    /**
120
     * @param \Doctrine\DBAL\Schema\Table $table
121
     *
122
     * @return void
123
     *
124
     * @throws \Doctrine\DBAL\Schema\SchemaException
125
     */
126 52 View Code Duplication
    protected function _addTable(Table $table)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
127
    {
128 52
        $namespaceName = $table->getNamespaceName();
129 52
        $tableName = $table->getFullQualifiedName($this->getName());
130
131 52
        if (isset($this->_tables[$tableName])) {
132 1
            throw SchemaException::tableAlreadyExists($tableName);
133
        }
134
135 52
        if ( ! $table->isInDefaultNamespace($this->getName()) && ! $this->hasNamespace($namespaceName)) {
136 8
            $this->createNamespace($namespaceName);
137
        }
138
139 52
        $this->_tables[$tableName] = $table;
140 52
        $table->setSchemaConfig($this->_schemaConfig);
141 52
    }
142
143
    /**
144
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
145
     *
146
     * @return void
147
     *
148
     * @throws \Doctrine\DBAL\Schema\SchemaException
149
     */
150 17 View Code Duplication
    protected function _addSequence(Sequence $sequence)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
151
    {
152 17
        $namespaceName = $sequence->getNamespaceName();
153 17
        $seqName = $sequence->getFullQualifiedName($this->getName());
154
155 17
        if (isset($this->_sequences[$seqName])) {
156 1
            throw SchemaException::sequenceAlreadyExists($seqName);
157
        }
158
159 17
        if ( ! $sequence->isInDefaultNamespace($this->getName()) && ! $this->hasNamespace($namespaceName)) {
160 1
            $this->createNamespace($namespaceName);
161
        }
162
163 17
        $this->_sequences[$seqName] = $sequence;
164 17
    }
165
166
    /**
167
     * Returns the namespaces of this schema.
168
     *
169
     * @return array A list of namespace names.
170
     */
171 27
    public function getNamespaces()
172
    {
173 27
        return $this->namespaces;
174
    }
175
176
    /**
177
     * Gets all tables of this schema.
178
     *
179
     * @return \Doctrine\DBAL\Schema\Table[]
180
     */
181 30
    public function getTables()
182
    {
183 30
        return $this->_tables;
184
    }
185
186
    /**
187
     * @param string $tableName
188
     *
189
     * @return \Doctrine\DBAL\Schema\Table
190
     *
191
     * @throws \Doctrine\DBAL\Schema\SchemaException
192
     */
193 33
    public function getTable($tableName)
194
    {
195 33
        $tableName = $this->getFullQualifiedAssetName($tableName);
196 33
        if (!isset($this->_tables[$tableName])) {
197 1
            throw SchemaException::tableDoesNotExist($tableName);
198
        }
199
200 32
        return $this->_tables[$tableName];
201
    }
202
203
    /**
204
     * @param string $name
205
     *
206
     * @return string
207
     */
208 46
    private function getFullQualifiedAssetName($name)
209
    {
210 46
        $name = $this->getUnquotedAssetName($name);
211
212 46
        if (strpos($name, ".") === false) {
213 42
            $name = $this->getName() . "." . $name;
214
        }
215
216 46
        return strtolower($name);
217
    }
218
219
    /**
220
     * Returns the unquoted representation of a given asset name.
221
     *
222
     * @param string $assetName Quoted or unquoted representation of an asset name.
223
     *
224
     * @return string
225
     */
226 51
    private function getUnquotedAssetName($assetName)
227
    {
228 51
        if ($this->isIdentifierQuoted($assetName)) {
229 2
            return $this->trimQuotes($assetName);
230
        }
231
232 50
        return $assetName;
233
    }
234
235
    /**
236
     * Does this schema have a namespace with the given name?
237
     *
238
     * @param string $namespaceName
239
     *
240
     * @return boolean
241
     */
242 10
    public function hasNamespace($namespaceName)
243
    {
244 10
        $namespaceName = strtolower($this->getUnquotedAssetName($namespaceName));
245
246 10
        return isset($this->namespaces[$namespaceName]);
247
    }
248
249
    /**
250
     * Does this schema have a table with the given name?
251
     *
252
     * @param string $tableName
253
     *
254
     * @return boolean
255
     */
256 32
    public function hasTable($tableName)
257
    {
258 32
        $tableName = $this->getFullQualifiedAssetName($tableName);
259
260 32
        return isset($this->_tables[$tableName]);
261
    }
262
263
    /**
264
     * Gets all table names, prefixed with a schema name, even the default one if present.
265
     *
266
     * @return array
267
     */
268
    public function getTableNames()
269
    {
270
        return array_keys($this->_tables);
271
    }
272
273
    /**
274
     * @param string $sequenceName
275
     *
276
     * @return boolean
277
     */
278 13
    public function hasSequence($sequenceName)
279
    {
280 13
        $sequenceName = $this->getFullQualifiedAssetName($sequenceName);
281
282 13
        return isset($this->_sequences[$sequenceName]);
283
    }
284
285
    /**
286
     * @param string $sequenceName
287
     *
288
     * @return \Doctrine\DBAL\Schema\Sequence
289
     *
290
     * @throws \Doctrine\DBAL\Schema\SchemaException
291
     */
292 9
    public function getSequence($sequenceName)
293
    {
294 9
        $sequenceName = $this->getFullQualifiedAssetName($sequenceName);
295 9
        if (!$this->hasSequence($sequenceName)) {
296 1
            throw SchemaException::sequenceDoesNotExist($sequenceName);
297
        }
298
299 8
        return $this->_sequences[$sequenceName];
300
    }
301
302
    /**
303
     * @return \Doctrine\DBAL\Schema\Sequence[]
304
     */
305 29
    public function getSequences()
306
    {
307 29
        return $this->_sequences;
308
    }
309
310
    /**
311
     * Creates a new namespace.
312
     *
313
     * @param string $namespaceName The name of the namespace to create.
314
     *
315
     * @return \Doctrine\DBAL\Schema\Schema This schema instance.
316
     *
317
     * @throws SchemaException
318
     */
319 11
    public function createNamespace($namespaceName)
320
    {
321 11
        $unquotedNamespaceName = strtolower($this->getUnquotedAssetName($namespaceName));
322
323 11
        if (isset($this->namespaces[$unquotedNamespaceName])) {
324 1
            throw SchemaException::namespaceAlreadyExists($unquotedNamespaceName);
325
        }
326
327 11
        $this->namespaces[$unquotedNamespaceName] = $namespaceName;
328
329 11
        return $this;
330
    }
331
332
    /**
333
     * Creates a new table.
334
     *
335
     * @param string $tableName
336
     *
337
     * @return \Doctrine\DBAL\Schema\Table
338
     */
339 35
    public function createTable($tableName)
340
    {
341 35
        $table = new Table($tableName);
342 35
        $this->_addTable($table);
343
344 35
        foreach ($this->_schemaConfig->getDefaultTableOptions() as $name => $value) {
345
            $table->addOption($name, $value);
346
        }
347
348 35
        return $table;
349
    }
350
351
    /**
352
     * Renames a table.
353
     *
354
     * @param string $oldTableName
355
     * @param string $newTableName
356
     *
357
     * @return \Doctrine\DBAL\Schema\Schema
358
     */
359 1
    public function renameTable($oldTableName, $newTableName)
360
    {
361 1
        $table = $this->getTable($oldTableName);
362 1
        $table->_setName($newTableName);
363
364 1
        $this->dropTable($oldTableName);
365 1
        $this->_addTable($table);
366
367 1
        return $this;
368
    }
369
370
    /**
371
     * Drops a table from the schema.
372
     *
373
     * @param string $tableName
374
     *
375
     * @return \Doctrine\DBAL\Schema\Schema
376
     */
377 5
    public function dropTable($tableName)
378
    {
379 5
        $tableName = $this->getFullQualifiedAssetName($tableName);
380 5
        $this->getTable($tableName);
381 5
        unset($this->_tables[$tableName]);
382
383 5
        return $this;
384
    }
385
386
    /**
387
     * Creates a new sequence.
388
     *
389
     * @param string  $sequenceName
390
     * @param integer $allocationSize
391
     * @param integer $initialValue
392
     *
393
     * @return \Doctrine\DBAL\Schema\Sequence
394
     */
395 13
    public function createSequence($sequenceName, $allocationSize=1, $initialValue=1)
396
    {
397 13
        $seq = new Sequence($sequenceName, $allocationSize, $initialValue);
398 13
        $this->_addSequence($seq);
399
400 13
        return $seq;
401
    }
402
403
    /**
404
     * @param string $sequenceName
405
     *
406
     * @return \Doctrine\DBAL\Schema\Schema
407
     */
408 1
    public function dropSequence($sequenceName)
409
    {
410 1
        $sequenceName = $this->getFullQualifiedAssetName($sequenceName);
411 1
        unset($this->_sequences[$sequenceName]);
412
413 1
        return $this;
414
    }
415
416
    /**
417
     * Returns an array of necessary SQL queries to create the schema on the given platform.
418
     *
419
     * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
420
     *
421
     * @return array
422
     */
423 12
    public function toSql(AbstractPlatform $platform)
424
    {
425 12
        $sqlCollector = new CreateSchemaSqlCollector($platform);
426 12
        $this->visit($sqlCollector);
427
428 12
        return $sqlCollector->getQueries();
429
    }
430
431
    /**
432
     * Return an array of necessary SQL queries to drop the schema on the given platform.
433
     *
434
     * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
435
     *
436
     * @return array
437
     */
438 1
    public function toDropSql(AbstractPlatform $platform)
439
    {
440 1
        $dropSqlCollector = new DropSchemaSqlCollector($platform);
441 1
        $this->visit($dropSqlCollector);
442
443 1
        return $dropSqlCollector->getQueries();
444
    }
445
446
    /**
447
     * @param \Doctrine\DBAL\Schema\Schema              $toSchema
448
     * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
449
     *
450
     * @return array
451
     */
452 View Code Duplication
    public function getMigrateToSql(Schema $toSchema, AbstractPlatform $platform)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
453
    {
454
        $comparator = new Comparator();
455
        $schemaDiff = $comparator->compare($this, $toSchema);
456
457
        return $schemaDiff->toSql($platform);
458
    }
459
460
    /**
461
     * @param \Doctrine\DBAL\Schema\Schema              $fromSchema
462
     * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
463
     *
464
     * @return array
465
     */
466 View Code Duplication
    public function getMigrateFromSql(Schema $fromSchema, AbstractPlatform $platform)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
467
    {
468
        $comparator = new Comparator();
469
        $schemaDiff = $comparator->compare($fromSchema, $this);
470
471
        return $schemaDiff->toSql($platform);
472
    }
473
474
    /**
475
     * @param \Doctrine\DBAL\Schema\Visitor\Visitor $visitor
476
     *
477
     * @return void
478
     */
479 18
    public function visit(Visitor $visitor)
480
    {
481 18
        $visitor->acceptSchema($this);
482
483 18
        if ($visitor instanceof NamespaceVisitor) {
484 15
            foreach ($this->namespaces as $namespace) {
485 4
                $visitor->acceptNamespace($namespace);
486
            }
487
        }
488
489 18
        foreach ($this->_tables as $table) {
490 18
            $table->visit($visitor);
491
        }
492
493 18
        foreach ($this->_sequences as $sequence) {
494 4
            $sequence->visit($visitor);
495
        }
496 18
    }
497
498
    /**
499
     * Cloning a Schema triggers a deep clone of all related assets.
500
     *
501
     * @return void
502
     */
503 2
    public function __clone()
504
    {
505 2
        foreach ($this->_tables as $k => $table) {
506 1
            $this->_tables[$k] = clone $table;
507
        }
508 2
        foreach ($this->_sequences as $k => $sequence) {
509 2
            $this->_sequences[$k] = clone $sequence;
510
        }
511 2
    }
512
}
513