Total Complexity | 50 |
Total Lines | 454 |
Duplicated Lines | 9.91 % |
Coverage | 89.31% |
Changes | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Schema 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 Schema, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
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() |
|
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.