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\Types\Type; |
||
23 | use Doctrine\DBAL\Schema\Visitor\Visitor; |
||
24 | use Doctrine\DBAL\DBALException; |
||
25 | |||
26 | /** |
||
27 | * Object Representation of a table. |
||
28 | * |
||
29 | * @link www.doctrine-project.org |
||
30 | * @since 2.0 |
||
31 | * @author Benjamin Eberlei <[email protected]> |
||
32 | */ |
||
33 | class Table extends AbstractAsset |
||
34 | { |
||
35 | /** |
||
36 | * @var string |
||
37 | */ |
||
38 | protected $_name = null; |
||
39 | |||
40 | /** |
||
41 | * @var Column[] |
||
42 | */ |
||
43 | protected $_columns = []; |
||
44 | |||
45 | /** |
||
46 | * @var Index[] |
||
47 | */ |
||
48 | private $implicitIndexes = []; |
||
49 | |||
50 | /** |
||
51 | * @var Index[] |
||
52 | */ |
||
53 | protected $_indexes = []; |
||
54 | |||
55 | /** |
||
56 | * @var string |
||
57 | */ |
||
58 | protected $_primaryKeyName = false; |
||
59 | |||
60 | /** |
||
61 | * @var ForeignKeyConstraint[] |
||
62 | */ |
||
63 | protected $_fkConstraints = []; |
||
64 | |||
65 | /** |
||
66 | * @var array |
||
67 | */ |
||
68 | protected $_options = []; |
||
69 | |||
70 | /** |
||
71 | * @var SchemaConfig |
||
72 | */ |
||
73 | protected $_schemaConfig = null; |
||
74 | |||
75 | /** |
||
76 | * @param string $tableName |
||
77 | * @param Column[] $columns |
||
78 | * @param Index[] $indexes |
||
79 | * @param ForeignKeyConstraint[] $fkConstraints |
||
80 | * @param integer $idGeneratorType |
||
81 | * @param array $options |
||
82 | * |
||
83 | * @throws DBALException |
||
84 | */ |
||
85 | 755 | public function __construct($tableName, array $columns=[], array $indexes=[], array $fkConstraints=[], $idGeneratorType = 0, array $options=[]) |
|
0 ignored issues
–
show
|
|||
86 | { |
||
87 | 755 | if (strlen($tableName) == 0) { |
|
88 | 1 | throw DBALException::invalidTableName($tableName); |
|
89 | } |
||
90 | |||
91 | 754 | $this->_setName($tableName); |
|
92 | |||
93 | 754 | foreach ($columns as $column) { |
|
94 | 72 | $this->_addColumn($column); |
|
95 | } |
||
96 | |||
97 | 753 | foreach ($indexes as $idx) { |
|
98 | 30 | $this->_addIndex($idx); |
|
99 | } |
||
100 | |||
101 | 751 | foreach ($fkConstraints as $constraint) { |
|
102 | 6 | $this->_addForeignKeyConstraint($constraint); |
|
103 | } |
||
104 | |||
105 | 751 | $this->_options = $options; |
|
106 | 751 | } |
|
107 | |||
108 | /** |
||
109 | * @param SchemaConfig $schemaConfig |
||
110 | * |
||
111 | * @return void |
||
112 | */ |
||
113 | 61 | public function setSchemaConfig(SchemaConfig $schemaConfig) |
|
114 | { |
||
115 | 61 | $this->_schemaConfig = $schemaConfig; |
|
116 | 61 | } |
|
117 | |||
118 | /** |
||
119 | * @return integer |
||
120 | */ |
||
121 | 144 | protected function _getMaxIdentifierLength() |
|
122 | { |
||
123 | 144 | if ($this->_schemaConfig instanceof SchemaConfig) { |
|
124 | 8 | return $this->_schemaConfig->getMaxIdentifierLength(); |
|
125 | } else { |
||
126 | 136 | return 63; |
|
127 | } |
||
128 | } |
||
129 | |||
130 | /** |
||
131 | * Sets the Primary Key. |
||
132 | * |
||
133 | * @param array $columns |
||
134 | * @param string|boolean $indexName |
||
135 | * |
||
136 | * @return self |
||
137 | */ |
||
138 | 314 | public function setPrimaryKey(array $columns, $indexName = false) |
|
139 | { |
||
140 | 314 | $this->_addIndex($this->_createIndex($columns, $indexName ?: "primary", true, true)); |
|
141 | |||
142 | 314 | foreach ($columns as $columnName) { |
|
143 | 314 | $column = $this->getColumn($columnName); |
|
144 | 314 | $column->setNotnull(true); |
|
145 | } |
||
146 | |||
147 | 314 | return $this; |
|
148 | } |
||
149 | |||
150 | /** |
||
151 | * @param array $columnNames |
||
152 | * @param string|null $indexName |
||
153 | * @param array $flags |
||
154 | * @param array $options |
||
155 | * |
||
156 | * @return self |
||
157 | */ |
||
158 | 95 | View Code Duplication | public function addIndex(array $columnNames, $indexName = null, array $flags = [], array $options = []) |
0 ignored issues
–
show
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...
|
|||
159 | { |
||
160 | 95 | if ($indexName == null) { |
|
161 | 26 | $indexName = $this->_generateIdentifierName( |
|
162 | 26 | array_merge([$this->getName()], $columnNames), "idx", $this->_getMaxIdentifierLength() |
|
163 | ); |
||
164 | } |
||
165 | |||
166 | 95 | return $this->_addIndex($this->_createIndex($columnNames, $indexName, false, false, $flags, $options)); |
|
167 | } |
||
168 | |||
169 | /** |
||
170 | * Drops the primary key from this table. |
||
171 | * |
||
172 | * @return void |
||
173 | */ |
||
174 | 13 | public function dropPrimaryKey() |
|
175 | { |
||
176 | 13 | $this->dropIndex($this->_primaryKeyName); |
|
177 | 13 | $this->_primaryKeyName = false; |
|
178 | 13 | } |
|
179 | |||
180 | /** |
||
181 | * Drops an index from this table. |
||
182 | * |
||
183 | * @param string $indexName The index name. |
||
184 | * |
||
185 | * @return void |
||
186 | * |
||
187 | * @throws SchemaException If the index does not exist. |
||
188 | */ |
||
189 | 25 | View Code Duplication | public function dropIndex($indexName) |
190 | { |
||
191 | 25 | $indexName = $this->normalizeIdentifier($indexName); |
|
192 | 25 | if ( ! $this->hasIndex($indexName)) { |
|
193 | throw SchemaException::indexDoesNotExist($indexName, $this->_name); |
||
194 | } |
||
195 | 25 | unset($this->_indexes[$indexName]); |
|
196 | 25 | } |
|
197 | |||
198 | /** |
||
199 | * @param array $columnNames |
||
200 | * @param string|null $indexName |
||
201 | * @param array $options |
||
202 | * |
||
203 | * @return self |
||
204 | */ |
||
205 | 29 | View Code Duplication | public function addUniqueIndex(array $columnNames, $indexName = null, array $options = []) |
206 | { |
||
207 | 29 | if ($indexName === null) { |
|
208 | 21 | $indexName = $this->_generateIdentifierName( |
|
209 | 21 | array_merge([$this->getName()], $columnNames), "uniq", $this->_getMaxIdentifierLength() |
|
210 | ); |
||
211 | } |
||
212 | |||
213 | 29 | return $this->_addIndex($this->_createIndex($columnNames, $indexName, true, false, [], $options)); |
|
214 | } |
||
215 | |||
216 | /** |
||
217 | * Renames an index. |
||
218 | * |
||
219 | * @param string $oldIndexName The name of the index to rename from. |
||
220 | * @param string|null $newIndexName The name of the index to rename to. |
||
221 | * If null is given, the index name will be auto-generated. |
||
222 | * |
||
223 | * @return self This table instance. |
||
224 | * |
||
225 | * @throws SchemaException if no index exists for the given current name |
||
226 | * or if an index with the given new name already exists on this table. |
||
227 | */ |
||
228 | 13 | public function renameIndex($oldIndexName, $newIndexName = null) |
|
229 | { |
||
230 | 13 | $oldIndexName = $this->normalizeIdentifier($oldIndexName); |
|
231 | 13 | $normalizedNewIndexName = $this->normalizeIdentifier($newIndexName); |
|
232 | |||
233 | 13 | if ($oldIndexName === $normalizedNewIndexName) { |
|
234 | 9 | return $this; |
|
235 | } |
||
236 | |||
237 | 13 | if ( ! $this->hasIndex($oldIndexName)) { |
|
238 | 1 | throw SchemaException::indexDoesNotExist($oldIndexName, $this->_name); |
|
239 | } |
||
240 | |||
241 | 12 | if ($this->hasIndex($normalizedNewIndexName)) { |
|
242 | 1 | throw SchemaException::indexAlreadyExists($normalizedNewIndexName, $this->_name); |
|
243 | } |
||
244 | |||
245 | 11 | $oldIndex = $this->_indexes[$oldIndexName]; |
|
246 | |||
247 | 11 | if ($oldIndex->isPrimary()) { |
|
248 | 1 | $this->dropPrimaryKey(); |
|
249 | |||
250 | 1 | return $this->setPrimaryKey($oldIndex->getColumns(), $newIndexName); |
|
251 | } |
||
252 | |||
253 | 11 | unset($this->_indexes[$oldIndexName]); |
|
254 | |||
255 | 11 | if ($oldIndex->isUnique()) { |
|
256 | 2 | return $this->addUniqueIndex($oldIndex->getColumns(), $newIndexName, $oldIndex->getOptions()); |
|
257 | } |
||
258 | |||
259 | 10 | return $this->addIndex($oldIndex->getColumns(), $newIndexName, $oldIndex->getFlags(), $oldIndex->getOptions()); |
|
260 | } |
||
261 | |||
262 | /** |
||
263 | * Checks if an index begins in the order of the given columns. |
||
264 | * |
||
265 | * @param array $columnsNames |
||
266 | * |
||
267 | * @return boolean |
||
268 | */ |
||
269 | 1 | public function columnsAreIndexed(array $columnsNames) |
|
270 | { |
||
271 | 1 | foreach ($this->getIndexes() as $index) { |
|
272 | /* @var $index Index */ |
||
273 | 1 | if ($index->spansColumns($columnsNames)) { |
|
274 | 1 | return true; |
|
275 | } |
||
276 | } |
||
277 | |||
278 | return false; |
||
279 | } |
||
280 | |||
281 | /** |
||
282 | * @param array $columnNames |
||
283 | * @param string $indexName |
||
284 | * @param boolean $isUnique |
||
285 | * @param boolean $isPrimary |
||
286 | * @param array $flags |
||
287 | * @param array $options |
||
288 | * |
||
289 | * @return Index |
||
290 | * |
||
291 | * @throws SchemaException |
||
292 | */ |
||
293 | 450 | private function _createIndex(array $columnNames, $indexName, $isUnique, $isPrimary, array $flags = [], array $options = []) |
|
294 | { |
||
295 | 450 | if (preg_match('(([^a-zA-Z0-9_]+))', $this->normalizeIdentifier($indexName))) { |
|
296 | 1 | throw SchemaException::indexNameInvalid($indexName); |
|
297 | } |
||
298 | |||
299 | 449 | foreach ($columnNames as $columnName => $indexColOptions) { |
|
300 | 448 | if (is_numeric($columnName) && is_string($indexColOptions)) { |
|
301 | 448 | $columnName = $indexColOptions; |
|
302 | } |
||
303 | |||
304 | 448 | if ( ! $this->hasColumn($columnName)) { |
|
305 | 448 | throw SchemaException::columnDoesNotExist($columnName, $this->_name); |
|
306 | } |
||
307 | } |
||
308 | |||
309 | 448 | return new Index($indexName, $columnNames, $isUnique, $isPrimary, $flags, $options); |
|
310 | } |
||
311 | |||
312 | /** |
||
313 | * @param string $columnName |
||
314 | * @param string $typeName |
||
315 | * @param array $options |
||
316 | * |
||
317 | * @return Column |
||
318 | */ |
||
319 | 609 | public function addColumn($columnName, $typeName, array $options=[]) |
|
320 | { |
||
321 | 609 | $column = new Column($columnName, Type::getType($typeName), $options); |
|
322 | |||
323 | 609 | $this->_addColumn($column); |
|
324 | |||
325 | 609 | return $column; |
|
326 | } |
||
327 | |||
328 | /** |
||
329 | * Renames a Column. |
||
330 | * |
||
331 | * @param string $oldColumnName |
||
332 | * @param string $newColumnName |
||
333 | * |
||
334 | * @deprecated |
||
335 | * |
||
336 | * @throws DBALException |
||
337 | */ |
||
338 | public function renameColumn($oldColumnName, $newColumnName) |
||
339 | { |
||
340 | throw new DBALException("Table#renameColumn() was removed, because it drops and recreates " . |
||
341 | "the column instead. There is no fix available, because a schema diff cannot reliably detect if a " . |
||
342 | "column was renamed or one column was created and another one dropped."); |
||
343 | } |
||
344 | |||
345 | /** |
||
346 | * Change Column Details. |
||
347 | * |
||
348 | * @param string $columnName |
||
349 | * @param array $options |
||
350 | * |
||
351 | * @return self |
||
352 | */ |
||
353 | 12 | public function changeColumn($columnName, array $options) |
|
354 | { |
||
355 | 12 | $column = $this->getColumn($columnName); |
|
356 | 12 | $column->setOptions($options); |
|
357 | |||
358 | 12 | return $this; |
|
359 | } |
||
360 | |||
361 | /** |
||
362 | * Drops a Column from the Table. |
||
363 | * |
||
364 | * @param string $columnName |
||
365 | * |
||
366 | * @return self |
||
367 | */ |
||
368 | 9 | public function dropColumn($columnName) |
|
369 | { |
||
370 | 9 | $columnName = $this->normalizeIdentifier($columnName); |
|
371 | 9 | unset($this->_columns[$columnName]); |
|
372 | |||
373 | 9 | return $this; |
|
374 | } |
||
375 | |||
376 | /** |
||
377 | * Adds a foreign key constraint. |
||
378 | * |
||
379 | * Name is inferred from the local columns. |
||
380 | * |
||
381 | * @param Table|string $foreignTable Table schema instance or table name |
||
382 | * @param array $localColumnNames |
||
383 | * @param array $foreignColumnNames |
||
384 | * @param array $options |
||
385 | * @param string|null $constraintName |
||
386 | * |
||
387 | * @return self |
||
388 | */ |
||
389 | 95 | public function addForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options=[], $constraintName = null) |
|
390 | { |
||
391 | 95 | $constraintName = $constraintName ?: $this->_generateIdentifierName(array_merge((array) $this->getName(), $localColumnNames), "fk", $this->_getMaxIdentifierLength()); |
|
392 | |||
393 | 95 | return $this->addNamedForeignKeyConstraint($constraintName, $foreignTable, $localColumnNames, $foreignColumnNames, $options); |
|
394 | } |
||
395 | |||
396 | /** |
||
397 | * Adds a foreign key constraint. |
||
398 | * |
||
399 | * Name is to be generated by the database itself. |
||
400 | * |
||
401 | * @deprecated Use {@link addForeignKeyConstraint} |
||
402 | * |
||
403 | * @param Table|string $foreignTable Table schema instance or table name |
||
404 | * @param array $localColumnNames |
||
405 | * @param array $foreignColumnNames |
||
406 | * @param array $options |
||
407 | * |
||
408 | * @return self |
||
409 | */ |
||
410 | 5 | public function addUnnamedForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options=[]) |
|
411 | { |
||
412 | 5 | return $this->addForeignKeyConstraint($foreignTable, $localColumnNames, $foreignColumnNames, $options); |
|
413 | } |
||
414 | |||
415 | /** |
||
416 | * Adds a foreign key constraint with a given name. |
||
417 | * |
||
418 | * @deprecated Use {@link addForeignKeyConstraint} |
||
419 | * |
||
420 | * @param string $name |
||
421 | * @param Table|string $foreignTable Table schema instance or table name |
||
422 | * @param array $localColumnNames |
||
423 | * @param array $foreignColumnNames |
||
424 | * @param array $options |
||
425 | * |
||
426 | * @return self |
||
427 | * |
||
428 | * @throws SchemaException |
||
429 | */ |
||
430 | 96 | public function addNamedForeignKeyConstraint($name, $foreignTable, array $localColumnNames, array $foreignColumnNames, array $options=[]) |
|
431 | { |
||
432 | 96 | if ($foreignTable instanceof Table) { |
|
433 | 50 | foreach ($foreignColumnNames as $columnName) { |
|
434 | 50 | if ( ! $foreignTable->hasColumn($columnName)) { |
|
435 | 50 | throw SchemaException::columnDoesNotExist($columnName, $foreignTable->getName()); |
|
436 | } |
||
437 | } |
||
438 | } |
||
439 | |||
440 | 95 | foreach ($localColumnNames as $columnName) { |
|
441 | 95 | if ( ! $this->hasColumn($columnName)) { |
|
442 | 95 | throw SchemaException::columnDoesNotExist($columnName, $this->_name); |
|
443 | } |
||
444 | } |
||
445 | |||
446 | 94 | $constraint = new ForeignKeyConstraint( |
|
447 | 94 | $localColumnNames, $foreignTable, $foreignColumnNames, $name, $options |
|
448 | ); |
||
449 | 94 | $this->_addForeignKeyConstraint($constraint); |
|
450 | |||
451 | 94 | return $this; |
|
452 | } |
||
453 | |||
454 | /** |
||
455 | * @param string $name |
||
456 | * @param string $value |
||
457 | * |
||
458 | * @return self |
||
459 | */ |
||
460 | 35 | public function addOption($name, $value) |
|
461 | { |
||
462 | 35 | $this->_options[$name] = $value; |
|
463 | |||
464 | 35 | return $this; |
|
465 | } |
||
466 | |||
467 | /** |
||
468 | * @param Column $column |
||
469 | * |
||
470 | * @return void |
||
471 | * |
||
472 | * @throws SchemaException |
||
473 | */ |
||
474 | 639 | protected function _addColumn(Column $column) |
|
475 | { |
||
476 | 639 | $columnName = $column->getName(); |
|
477 | 639 | $columnName = $this->normalizeIdentifier($columnName); |
|
478 | |||
479 | 639 | if (isset($this->_columns[$columnName])) { |
|
480 | 1 | throw SchemaException::columnAlreadyExists($this->getName(), $columnName); |
|
481 | } |
||
482 | |||
483 | 639 | $this->_columns[$columnName] = $column; |
|
484 | 639 | } |
|
485 | |||
486 | /** |
||
487 | * Adds an index to the table. |
||
488 | * |
||
489 | * @param Index $indexCandidate |
||
490 | * |
||
491 | * @return self |
||
492 | * |
||
493 | * @throws SchemaException |
||
494 | */ |
||
495 | 455 | protected function _addIndex(Index $indexCandidate) |
|
496 | { |
||
497 | 455 | $indexName = $indexCandidate->getName(); |
|
498 | 455 | $indexName = $this->normalizeIdentifier($indexName); |
|
499 | 455 | $replacedImplicitIndexes = []; |
|
500 | |||
501 | 455 | foreach ($this->implicitIndexes as $name => $implicitIndex) { |
|
502 | 28 | if ($implicitIndex->isFullfilledBy($indexCandidate) && isset($this->_indexes[$name])) { |
|
503 | 28 | $replacedImplicitIndexes[] = $name; |
|
504 | } |
||
505 | } |
||
506 | |||
507 | 455 | if ((isset($this->_indexes[$indexName]) && ! in_array($indexName, $replacedImplicitIndexes, true)) || |
|
508 | 455 | ($this->_primaryKeyName != false && $indexCandidate->isPrimary()) |
|
509 | ) { |
||
510 | 2 | throw SchemaException::indexAlreadyExists($indexName, $this->_name); |
|
511 | } |
||
512 | |||
513 | 455 | foreach ($replacedImplicitIndexes as $name) { |
|
514 | 4 | unset($this->_indexes[$name], $this->implicitIndexes[$name]); |
|
515 | } |
||
516 | |||
517 | 455 | if ($indexCandidate->isPrimary()) { |
|
518 | 316 | $this->_primaryKeyName = $indexName; |
|
519 | } |
||
520 | |||
521 | 455 | $this->_indexes[$indexName] = $indexCandidate; |
|
522 | |||
523 | 455 | return $this; |
|
524 | } |
||
525 | |||
526 | /** |
||
527 | * @param ForeignKeyConstraint $constraint |
||
528 | * |
||
529 | * @return void |
||
530 | */ |
||
531 | 97 | protected function _addForeignKeyConstraint(ForeignKeyConstraint $constraint) |
|
532 | { |
||
533 | 97 | $constraint->setLocalTable($this); |
|
534 | |||
535 | 97 | if (strlen($constraint->getName())) { |
|
536 | 95 | $name = $constraint->getName(); |
|
537 | } else { |
||
538 | 2 | $name = $this->_generateIdentifierName( |
|
539 | 2 | array_merge((array) $this->getName(), $constraint->getLocalColumns()), "fk", $this->_getMaxIdentifierLength() |
|
540 | ); |
||
541 | } |
||
542 | 97 | $name = $this->normalizeIdentifier($name); |
|
543 | |||
544 | 97 | $this->_fkConstraints[$name] = $constraint; |
|
545 | |||
546 | // add an explicit index on the foreign key columns. If there is already an index that fulfils this requirements drop the request. |
||
547 | // In the case of __construct calling this method during hydration from schema-details all the explicitly added indexes |
||
548 | // lead to duplicates. This creates computation overhead in this case, however no duplicate indexes are ever added (based on columns). |
||
549 | 97 | $indexName = $this->_generateIdentifierName( |
|
550 | 97 | array_merge([$this->getName()], $constraint->getColumns()), |
|
551 | 97 | "idx", |
|
552 | 97 | $this->_getMaxIdentifierLength() |
|
553 | ); |
||
554 | 97 | $indexCandidate = $this->_createIndex($constraint->getColumns(), $indexName, false, false); |
|
555 | |||
556 | 97 | foreach ($this->_indexes as $existingIndex) { |
|
557 | 73 | if ($indexCandidate->isFullfilledBy($existingIndex)) { |
|
558 | 73 | return; |
|
559 | } |
||
560 | } |
||
561 | |||
562 | 73 | $this->_addIndex($indexCandidate); |
|
563 | 73 | $this->implicitIndexes[$this->normalizeIdentifier($indexName)] = $indexCandidate; |
|
564 | 73 | } |
|
565 | |||
566 | /** |
||
567 | * Returns whether this table has a foreign key constraint with the given name. |
||
568 | * |
||
569 | * @param string $constraintName |
||
570 | * |
||
571 | * @return boolean |
||
572 | */ |
||
573 | 10 | public function hasForeignKey($constraintName) |
|
574 | { |
||
575 | 10 | $constraintName = $this->normalizeIdentifier($constraintName); |
|
576 | |||
577 | 10 | return isset($this->_fkConstraints[$constraintName]); |
|
578 | } |
||
579 | |||
580 | /** |
||
581 | * Returns the foreign key constraint with the given name. |
||
582 | * |
||
583 | * @param string $constraintName The constraint name. |
||
584 | * |
||
585 | * @return ForeignKeyConstraint |
||
586 | * |
||
587 | * @throws SchemaException If the foreign key does not exist. |
||
588 | */ |
||
589 | 8 | View Code Duplication | public function getForeignKey($constraintName) |
590 | { |
||
591 | 8 | $constraintName = $this->normalizeIdentifier($constraintName); |
|
592 | 8 | if (!$this->hasForeignKey($constraintName)) { |
|
593 | throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name); |
||
594 | } |
||
595 | |||
596 | 8 | return $this->_fkConstraints[$constraintName]; |
|
597 | } |
||
598 | |||
599 | /** |
||
600 | * Removes the foreign key constraint with the given name. |
||
601 | * |
||
602 | * @param string $constraintName The constraint name. |
||
603 | * |
||
604 | * @return void |
||
605 | * |
||
606 | * @throws SchemaException |
||
607 | */ |
||
608 | 10 | View Code Duplication | public function removeForeignKey($constraintName) |
609 | { |
||
610 | 10 | $constraintName = $this->normalizeIdentifier($constraintName); |
|
611 | 10 | if (!$this->hasForeignKey($constraintName)) { |
|
612 | throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name); |
||
613 | } |
||
614 | |||
615 | 10 | unset($this->_fkConstraints[$constraintName]); |
|
616 | 10 | } |
|
617 | |||
618 | /** |
||
619 | * Returns ordered list of columns (primary keys are first, then foreign keys, then the rest) |
||
620 | * @return Column[] |
||
621 | */ |
||
622 | 449 | public function getColumns() |
|
623 | { |
||
624 | 449 | $primaryKeyColumns = []; |
|
625 | 449 | if ($this->hasPrimaryKey()) { |
|
626 | 209 | $primaryKeyColumns = $this->filterColumns($this->getPrimaryKey()->getColumns()); |
|
627 | } |
||
628 | |||
629 | 449 | return array_merge($primaryKeyColumns, $this->getForeignKeyColumns(), $this->_columns); |
|
630 | } |
||
631 | |||
632 | /** |
||
633 | * Returns foreign key columns |
||
634 | * @return Column[] |
||
635 | */ |
||
636 | 449 | private function getForeignKeyColumns() |
|
637 | { |
||
638 | 449 | $foreignKeyColumns = []; |
|
639 | 449 | foreach ($this->getForeignKeys() as $foreignKey) { |
|
640 | /* @var $foreignKey ForeignKeyConstraint */ |
||
641 | 43 | $foreignKeyColumns = array_merge($foreignKeyColumns, $foreignKey->getColumns()); |
|
642 | } |
||
643 | 449 | return $this->filterColumns($foreignKeyColumns); |
|
644 | } |
||
645 | |||
646 | /** |
||
647 | * Returns only columns that have specified names |
||
648 | * @param array $columnNames |
||
649 | * @return Column[] |
||
650 | */ |
||
651 | private function filterColumns(array $columnNames) |
||
652 | { |
||
653 | 449 | return array_filter($this->_columns, function ($columnName) use ($columnNames) { |
|
654 | 425 | return in_array($columnName, $columnNames, true); |
|
655 | 449 | }, ARRAY_FILTER_USE_KEY); |
|
656 | } |
||
657 | |||
658 | /** |
||
659 | * Returns whether this table has a Column with the given name. |
||
660 | * |
||
661 | * @param string $columnName The column name. |
||
662 | * |
||
663 | * @return boolean |
||
664 | */ |
||
665 | 520 | public function hasColumn($columnName) |
|
666 | { |
||
667 | 520 | $columnName = $this->normalizeIdentifier($columnName); |
|
668 | |||
669 | 520 | return isset($this->_columns[$columnName]); |
|
670 | } |
||
671 | |||
672 | /** |
||
673 | * Returns the Column with the given name. |
||
674 | * |
||
675 | * @param string $columnName The column name. |
||
676 | * |
||
677 | * @return Column |
||
678 | * |
||
679 | * @throws SchemaException If the column does not exist. |
||
680 | */ |
||
681 | 399 | public function getColumn($columnName) |
|
682 | { |
||
683 | 399 | $columnName = $this->normalizeIdentifier($columnName); |
|
684 | 399 | if ( ! $this->hasColumn($columnName)) { |
|
685 | 1 | throw SchemaException::columnDoesNotExist($columnName, $this->_name); |
|
686 | } |
||
687 | |||
688 | 398 | return $this->_columns[$columnName]; |
|
689 | } |
||
690 | |||
691 | /** |
||
692 | * Returns the primary key. |
||
693 | * |
||
694 | * @return Index|null The primary key, or null if this Table has no primary key. |
||
695 | */ |
||
696 | 214 | public function getPrimaryKey() |
|
697 | { |
||
698 | 214 | if ( ! $this->hasPrimaryKey()) { |
|
699 | return null; |
||
700 | } |
||
701 | |||
702 | 214 | return $this->getIndex($this->_primaryKeyName); |
|
703 | } |
||
704 | |||
705 | /** |
||
706 | * Returns the primary key columns. |
||
707 | * |
||
708 | * @return array |
||
709 | * |
||
710 | * @throws DBALException |
||
711 | */ |
||
712 | 9 | public function getPrimaryKeyColumns() |
|
713 | { |
||
714 | 9 | if ( ! $this->hasPrimaryKey()) { |
|
715 | throw new DBALException("Table " . $this->getName() . " has no primary key."); |
||
716 | } |
||
717 | 9 | return $this->getPrimaryKey()->getColumns(); |
|
718 | } |
||
719 | |||
720 | /** |
||
721 | * Returns whether this table has a primary key. |
||
722 | * |
||
723 | * @return boolean |
||
724 | */ |
||
725 | 457 | public function hasPrimaryKey() |
|
726 | { |
||
727 | 457 | return ($this->_primaryKeyName && $this->hasIndex($this->_primaryKeyName)); |
|
728 | } |
||
729 | |||
730 | /** |
||
731 | * Returns whether this table has an Index with the given name. |
||
732 | * |
||
733 | * @param string $indexName The index name. |
||
734 | * |
||
735 | * @return boolean |
||
736 | */ |
||
737 | 264 | public function hasIndex($indexName) |
|
738 | { |
||
739 | 264 | $indexName = $this->normalizeIdentifier($indexName); |
|
740 | |||
741 | 264 | return (isset($this->_indexes[$indexName])); |
|
742 | } |
||
743 | |||
744 | /** |
||
745 | * Returns the Index with the given name. |
||
746 | * |
||
747 | * @param string $indexName The index name. |
||
748 | * |
||
749 | * @return Index |
||
750 | * |
||
751 | * @throws SchemaException If the index does not exist. |
||
752 | */ |
||
753 | 242 | View Code Duplication | public function getIndex($indexName) |
754 | { |
||
755 | 242 | $indexName = $this->normalizeIdentifier($indexName); |
|
756 | 242 | if ( ! $this->hasIndex($indexName)) { |
|
757 | 1 | throw SchemaException::indexDoesNotExist($indexName, $this->_name); |
|
758 | } |
||
759 | |||
760 | 241 | return $this->_indexes[$indexName]; |
|
761 | } |
||
762 | |||
763 | /** |
||
764 | * @return Index[] |
||
765 | */ |
||
766 | 425 | public function getIndexes() |
|
767 | { |
||
768 | 425 | return $this->_indexes; |
|
769 | } |
||
770 | |||
771 | /** |
||
772 | * Returns the foreign key constraints. |
||
773 | * |
||
774 | * @return ForeignKeyConstraint[] |
||
775 | */ |
||
776 | 462 | public function getForeignKeys() |
|
777 | { |
||
778 | 462 | return $this->_fkConstraints; |
|
779 | } |
||
780 | |||
781 | /** |
||
782 | * @param string $name |
||
783 | * |
||
784 | * @return boolean |
||
785 | */ |
||
786 | 51 | public function hasOption($name) |
|
787 | { |
||
788 | 51 | return isset($this->_options[$name]); |
|
789 | } |
||
790 | |||
791 | /** |
||
792 | * @param string $name |
||
793 | * |
||
794 | * @return mixed |
||
795 | */ |
||
796 | 5 | public function getOption($name) |
|
797 | { |
||
798 | 5 | return $this->_options[$name]; |
|
799 | } |
||
800 | |||
801 | /** |
||
802 | * @return array |
||
803 | */ |
||
804 | 336 | public function getOptions() |
|
805 | { |
||
806 | 336 | return $this->_options; |
|
807 | } |
||
808 | |||
809 | /** |
||
810 | * @param Visitor $visitor |
||
811 | * |
||
812 | * @return void |
||
813 | */ |
||
814 | 18 | public function visit(Visitor $visitor) |
|
815 | { |
||
816 | 18 | $visitor->acceptTable($this); |
|
817 | |||
818 | 18 | foreach ($this->getColumns() as $column) { |
|
819 | 15 | $visitor->acceptColumn($this, $column); |
|
820 | } |
||
821 | |||
822 | 18 | foreach ($this->getIndexes() as $index) { |
|
823 | 11 | $visitor->acceptIndex($this, $index); |
|
824 | } |
||
825 | |||
826 | 18 | foreach ($this->getForeignKeys() as $constraint) { |
|
827 | 4 | $visitor->acceptForeignKey($this, $constraint); |
|
828 | } |
||
829 | 18 | } |
|
830 | |||
831 | /** |
||
832 | * Clone of a Table triggers a deep clone of all affected assets. |
||
833 | * |
||
834 | * @return void |
||
835 | */ |
||
836 | 50 | public function __clone() |
|
837 | { |
||
838 | 50 | foreach ($this->_columns as $k => $column) { |
|
839 | 49 | $this->_columns[$k] = clone $column; |
|
840 | } |
||
841 | 50 | foreach ($this->_indexes as $k => $index) { |
|
842 | 28 | $this->_indexes[$k] = clone $index; |
|
843 | } |
||
844 | 50 | foreach ($this->_fkConstraints as $k => $fk) { |
|
845 | 6 | $this->_fkConstraints[$k] = clone $fk; |
|
846 | 6 | $this->_fkConstraints[$k]->setLocalTable($this); |
|
847 | } |
||
848 | 50 | } |
|
849 | |||
850 | /** |
||
851 | * Normalizes a given identifier. |
||
852 | * |
||
853 | * Trims quotes and lowercases the given identifier. |
||
854 | * |
||
855 | * @param string $identifier The identifier to normalize. |
||
856 | * |
||
857 | * @return string The normalized identifier. |
||
858 | */ |
||
859 | 643 | private function normalizeIdentifier($identifier) |
|
860 | { |
||
861 | 643 | return $this->trimQuotes(strtolower($identifier)); |
|
862 | } |
||
863 | } |
||
864 |
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.