Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Doctrine\DBAL\Schema;
4
 
5
use Doctrine\DBAL\Exception;
6
use Doctrine\DBAL\Platforms\AbstractPlatform;
7
use Doctrine\DBAL\Schema\Visitor\NamespaceVisitor;
8
use Doctrine\DBAL\Schema\Visitor\Visitor;
9
use Doctrine\DBAL\SQL\Builder\CreateSchemaObjectsSQLBuilder;
10
use Doctrine\DBAL\SQL\Builder\DropSchemaObjectsSQLBuilder;
11
use Doctrine\Deprecations\Deprecation;
12
 
13
use function array_keys;
14
use function strpos;
15
use function strtolower;
16
 
17
/**
18
 * Object representation of a database schema.
19
 *
20
 * Different vendors have very inconsistent naming with regard to the concept
21
 * of a "schema". Doctrine understands a schema as the entity that conceptually
22
 * wraps a set of database objects such as tables, sequences, indexes and
23
 * foreign keys that belong to each other into a namespace. A Doctrine Schema
24
 * has nothing to do with the "SCHEMA" defined as in PostgreSQL, it is more
25
 * related to the concept of "DATABASE" that exists in MySQL and PostgreSQL.
26
 *
27
 * Every asset in the doctrine schema has a name. A name consists of either a
28
 * namespace.local name pair or just a local unqualified name.
29
 *
30
 * The abstraction layer that covers a PostgreSQL schema is the namespace of an
31
 * database object (asset). A schema can have a name, which will be used as
32
 * default namespace for the unqualified database objects that are created in
33
 * the schema.
34
 *
35
 * In the case of MySQL where cross-database queries are allowed this leads to
36
 * databases being "misinterpreted" as namespaces. This is intentional, however
37
 * the CREATE/DROP SQL visitors will just filter this queries and do not
38
 * execute them. Only the queries for the currently connected database are
39
 * executed.
40
 */
41
class Schema extends AbstractAsset
42
{
43
    /**
44
     * The namespaces in this schema.
45
     *
46
     * @var string[]
47
     */
48
    private array $namespaces = [];
49
 
50
    /** @var Table[] */
51
    protected $_tables = [];
52
 
53
    /** @var Sequence[] */
54
    protected $_sequences = [];
55
 
56
    /** @var SchemaConfig */
57
    protected $_schemaConfig;
58
 
59
    /**
60
     * @param Table[]    $tables
61
     * @param Sequence[] $sequences
62
     * @param string[]   $namespaces
63
     *
64
     * @throws SchemaException
65
     */
66
    public function __construct(
67
        array $tables = [],
68
        array $sequences = [],
69
        ?SchemaConfig $schemaConfig = null,
70
        array $namespaces = []
71
    ) {
72
        $schemaConfig ??= new SchemaConfig();
73
 
74
        $this->_schemaConfig = $schemaConfig;
75
        $this->_setName($schemaConfig->getName() ?? 'public');
76
 
77
        foreach ($namespaces as $namespace) {
78
            $this->createNamespace($namespace);
79
        }
80
 
81
        foreach ($tables as $table) {
82
            $this->_addTable($table);
83
        }
84
 
85
        foreach ($sequences as $sequence) {
86
            $this->_addSequence($sequence);
87
        }
88
    }
89
 
90
    /**
91
     * @deprecated
92
     *
93
     * @return bool
94
     */
95
    public function hasExplicitForeignKeyIndexes()
96
    {
97
        Deprecation::trigger(
98
            'doctrine/dbal',
99
            'https://github.com/doctrine/dbal/pull/4822',
100
            'Schema::hasExplicitForeignKeyIndexes() is deprecated.',
101
        );
102
 
103
        return $this->_schemaConfig->hasExplicitForeignKeyIndexes();
104
    }
105
 
106
    /**
107
     * @return void
108
     *
109
     * @throws SchemaException
110
     */
111
    protected function _addTable(Table $table)
112
    {
113
        $namespaceName = $table->getNamespaceName();
114
        $tableName     = $this->normalizeName($table);
115
 
116
        if (isset($this->_tables[$tableName])) {
117
            throw SchemaException::tableAlreadyExists($tableName);
118
        }
119
 
120
        if (
121
            $namespaceName !== null
122
            && ! $table->isInDefaultNamespace($this->getName())
123
            && ! $this->hasNamespace($namespaceName)
124
        ) {
125
            $this->createNamespace($namespaceName);
126
        }
127
 
128
        $this->_tables[$tableName] = $table;
129
        $table->setSchemaConfig($this->_schemaConfig);
130
    }
131
 
132
    /**
133
     * @return void
134
     *
135
     * @throws SchemaException
136
     */
137
    protected function _addSequence(Sequence $sequence)
138
    {
139
        $namespaceName = $sequence->getNamespaceName();
140
        $seqName       = $this->normalizeName($sequence);
141
 
142
        if (isset($this->_sequences[$seqName])) {
143
            throw SchemaException::sequenceAlreadyExists($seqName);
144
        }
145
 
146
        if (
147
            $namespaceName !== null
148
            && ! $sequence->isInDefaultNamespace($this->getName())
149
            && ! $this->hasNamespace($namespaceName)
150
        ) {
151
            $this->createNamespace($namespaceName);
152
        }
153
 
154
        $this->_sequences[$seqName] = $sequence;
155
    }
156
 
157
    /**
158
     * Returns the namespaces of this schema.
159
     *
160
     * @return string[] A list of namespace names.
161
     */
162
    public function getNamespaces()
163
    {
164
        return $this->namespaces;
165
    }
166
 
167
    /**
168
     * Gets all tables of this schema.
169
     *
170
     * @return Table[]
171
     */
172
    public function getTables()
173
    {
174
        return $this->_tables;
175
    }
176
 
177
    /**
178
     * @param string $name
179
     *
180
     * @return Table
181
     *
182
     * @throws SchemaException
183
     */
184
    public function getTable($name)
185
    {
186
        $name = $this->getFullQualifiedAssetName($name);
187
        if (! isset($this->_tables[$name])) {
188
            throw SchemaException::tableDoesNotExist($name);
189
        }
190
 
191
        return $this->_tables[$name];
192
    }
193
 
194
    /** @param string $name */
195
    private function getFullQualifiedAssetName($name): string
196
    {
197
        $name = $this->getUnquotedAssetName($name);
198
 
199
        if (strpos($name, '.') === false) {
200
            $name = $this->getName() . '.' . $name;
201
        }
202
 
203
        return strtolower($name);
204
    }
205
 
206
    private function normalizeName(AbstractAsset $asset): string
207
    {
208
        return $asset->getFullQualifiedName($this->getName());
209
    }
210
 
211
    /**
212
     * Returns the unquoted representation of a given asset name.
213
     *
214
     * @param string $assetName Quoted or unquoted representation of an asset name.
215
     */
216
    private function getUnquotedAssetName($assetName): string
217
    {
218
        if ($this->isIdentifierQuoted($assetName)) {
219
            return $this->trimQuotes($assetName);
220
        }
221
 
222
        return $assetName;
223
    }
224
 
225
    /**
226
     * Does this schema have a namespace with the given name?
227
     *
228
     * @param string $name
229
     *
230
     * @return bool
231
     */
232
    public function hasNamespace($name)
233
    {
234
        $name = strtolower($this->getUnquotedAssetName($name));
235
 
236
        return isset($this->namespaces[$name]);
237
    }
238
 
239
    /**
240
     * Does this schema have a table with the given name?
241
     *
242
     * @param string $name
243
     *
244
     * @return bool
245
     */
246
    public function hasTable($name)
247
    {
248
        $name = $this->getFullQualifiedAssetName($name);
249
 
250
        return isset($this->_tables[$name]);
251
    }
252
 
253
    /**
254
     * Gets all table names, prefixed with a schema name, even the default one if present.
255
     *
256
     * @deprecated Use {@see getTables()} and {@see Table::getName()} instead.
257
     *
258
     * @return string[]
259
     */
260
    public function getTableNames()
261
    {
262
        Deprecation::trigger(
263
            'doctrine/dbal',
264
            'https://github.com/doctrine/dbal/pull/4800',
265
            'Schema::getTableNames() is deprecated.'
266
            . ' Use Schema::getTables() and Table::getName() instead.',
267
            __METHOD__,
268
        );
269
 
270
        return array_keys($this->_tables);
271
    }
272
 
273
    /**
274
     * @param string $name
275
     *
276
     * @return bool
277
     */
278
    public function hasSequence($name)
279
    {
280
        $name = $this->getFullQualifiedAssetName($name);
281
 
282
        return isset($this->_sequences[$name]);
283
    }
284
 
285
    /**
286
     * @param string $name
287
     *
288
     * @return Sequence
289
     *
290
     * @throws SchemaException
291
     */
292
    public function getSequence($name)
293
    {
294
        $name = $this->getFullQualifiedAssetName($name);
295
        if (! $this->hasSequence($name)) {
296
            throw SchemaException::sequenceDoesNotExist($name);
297
        }
298
 
299
        return $this->_sequences[$name];
300
    }
301
 
302
    /** @return Sequence[] */
303
    public function getSequences()
304
    {
305
        return $this->_sequences;
306
    }
307
 
308
    /**
309
     * Creates a new namespace.
310
     *
311
     * @param string $name The name of the namespace to create.
312
     *
313
     * @return Schema This schema instance.
314
     *
315
     * @throws SchemaException
316
     */
317
    public function createNamespace($name)
318
    {
319
        $unquotedName = strtolower($this->getUnquotedAssetName($name));
320
 
321
        if (isset($this->namespaces[$unquotedName])) {
322
            throw SchemaException::namespaceAlreadyExists($unquotedName);
323
        }
324
 
325
        $this->namespaces[$unquotedName] = $name;
326
 
327
        return $this;
328
    }
329
 
330
    /**
331
     * Creates a new table.
332
     *
333
     * @param string $name
334
     *
335
     * @return Table
336
     *
337
     * @throws SchemaException
338
     */
339
    public function createTable($name)
340
    {
341
        $table = new Table($name);
342
        $this->_addTable($table);
343
 
344
        foreach ($this->_schemaConfig->getDefaultTableOptions() as $option => $value) {
345
            $table->addOption($option, $value);
346
        }
347
 
348
        return $table;
349
    }
350
 
351
    /**
352
     * Renames a table.
353
     *
354
     * @param string $oldName
355
     * @param string $newName
356
     *
357
     * @return Schema
358
     *
359
     * @throws SchemaException
360
     */
361
    public function renameTable($oldName, $newName)
362
    {
363
        $table = $this->getTable($oldName);
364
        $table->_setName($newName);
365
 
366
        $this->dropTable($oldName);
367
        $this->_addTable($table);
368
 
369
        return $this;
370
    }
371
 
372
    /**
373
     * Drops a table from the schema.
374
     *
375
     * @param string $name
376
     *
377
     * @return Schema
378
     *
379
     * @throws SchemaException
380
     */
381
    public function dropTable($name)
382
    {
383
        $name = $this->getFullQualifiedAssetName($name);
384
        $this->getTable($name);
385
        unset($this->_tables[$name]);
386
 
387
        return $this;
388
    }
389
 
390
    /**
391
     * Creates a new sequence.
392
     *
393
     * @param string $name
394
     * @param int    $allocationSize
395
     * @param int    $initialValue
396
     *
397
     * @return Sequence
398
     *
399
     * @throws SchemaException
400
     */
401
    public function createSequence($name, $allocationSize = 1, $initialValue = 1)
402
    {
403
        $seq = new Sequence($name, $allocationSize, $initialValue);
404
        $this->_addSequence($seq);
405
 
406
        return $seq;
407
    }
408
 
409
    /**
410
     * @param string $name
411
     *
412
     * @return Schema
413
     */
414
    public function dropSequence($name)
415
    {
416
        $name = $this->getFullQualifiedAssetName($name);
417
        unset($this->_sequences[$name]);
418
 
419
        return $this;
420
    }
421
 
422
    /**
423
     * Returns an array of necessary SQL queries to create the schema on the given platform.
424
     *
425
     * @return list<string>
426
     *
427
     * @throws Exception
428
     */
429
    public function toSql(AbstractPlatform $platform)
430
    {
431
        $builder = new CreateSchemaObjectsSQLBuilder($platform);
432
 
433
        return $builder->buildSQL($this);
434
    }
435
 
436
    /**
437
     * Return an array of necessary SQL queries to drop the schema on the given platform.
438
     *
439
     * @return list<string>
440
     *
441
     * @throws Exception
442
     */
443
    public function toDropSql(AbstractPlatform $platform)
444
    {
445
        $builder = new DropSchemaObjectsSQLBuilder($platform);
446
 
447
        return $builder->buildSQL($this);
448
    }
449
 
450
    /**
451
     * @deprecated
452
     *
453
     * @return string[]
454
     *
455
     * @throws SchemaException
456
     */
457
    public function getMigrateToSql(Schema $toSchema, AbstractPlatform $platform)
458
    {
459
        $schemaDiff = (new Comparator())->compareSchemas($this, $toSchema);
460
 
461
        return $schemaDiff->toSql($platform);
462
    }
463
 
464
    /**
465
     * @deprecated
466
     *
467
     * @return string[]
468
     *
469
     * @throws SchemaException
470
     */
471
    public function getMigrateFromSql(Schema $fromSchema, AbstractPlatform $platform)
472
    {
473
        $schemaDiff = (new Comparator())->compareSchemas($fromSchema, $this);
474
 
475
        return $schemaDiff->toSql($platform);
476
    }
477
 
478
    /**
479
     * @deprecated
480
     *
481
     * @return void
482
     */
483
    public function visit(Visitor $visitor)
484
    {
485
        Deprecation::triggerIfCalledFromOutside(
486
            'doctrine/dbal',
487
            'https://github.com/doctrine/dbal/pull/5435',
488
            'Schema::visit() is deprecated.',
489
        );
490
 
491
        $visitor->acceptSchema($this);
492
 
493
        if ($visitor instanceof NamespaceVisitor) {
494
            foreach ($this->namespaces as $namespace) {
495
                $visitor->acceptNamespace($namespace);
496
            }
497
        }
498
 
499
        foreach ($this->_tables as $table) {
500
            $table->visit($visitor);
501
        }
502
 
503
        foreach ($this->_sequences as $sequence) {
504
            $sequence->visit($visitor);
505
        }
506
    }
507
 
508
    /**
509
     * Cloning a Schema triggers a deep clone of all related assets.
510
     *
511
     * @return void
512
     */
513
    public function __clone()
514
    {
515
        foreach ($this->_tables as $k => $table) {
516
            $this->_tables[$k] = clone $table;
517
        }
518
 
519
        foreach ($this->_sequences as $k => $sequence) {
520
            $this->_sequences[$k] = clone $sequence;
521
        }
522
    }
523
}