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) |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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
|
|
|
|
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.