|
22 | 22 | class SchemaAnalyzer
|
23 | 23 | {
|
24 | 24 | private static $WEIGHT_FK = 1;
|
| 25 | + private static $WEIGHT_INHERITANCE_FK = 0.1; |
25 | 26 | private static $WEIGHT_JOINTURE_TABLE = 1.5;
|
26 | 27 |
|
27 | 28 | const WEIGHT_IMPORTANT = 0.75;
|
@@ -124,7 +125,11 @@ private function isJunctionTable(Table $table)
|
124 | 125 | return false;
|
125 | 126 | }
|
126 | 127 |
|
127 |
| - $pkColumns = $table->getPrimaryKeyColumns(); |
| 128 | + if ($table->hasPrimaryKey()) { |
| 129 | + $pkColumns = $table->getPrimaryKeyColumns(); |
| 130 | + } else { |
| 131 | + $pkColumns = []; |
| 132 | + } |
128 | 133 |
|
129 | 134 | if (count($pkColumns) == 1 && count($columns) == 2) {
|
130 | 135 | return false;
|
@@ -257,6 +262,8 @@ private function buildSchemaGraph()
|
257 | 262 | $edge = $graph->getVertex($table->getName())->createEdge($graph->getVertex($fk->getForeignTableName()));
|
258 | 263 | if (isset($this->alteredCosts[$fk->getLocalTable()->getName()][implode(',',$fk->getLocalColumns())])) {
|
259 | 264 | $cost = $this->alteredCosts[$fk->getLocalTable()->getName()][implode(',',$fk->getLocalColumns())];
|
| 265 | + } elseif ($this->isInheritanceRelationship($fk)) { |
| 266 | + $cost = self::$WEIGHT_INHERITANCE_FK; |
260 | 267 | } else {
|
261 | 268 | $cost = self::$WEIGHT_FK;
|
262 | 269 | }
|
@@ -421,4 +428,103 @@ public function setTableCostModifiers(array $tableCosts) {
|
421 | 428 | public function setForeignKeyCosts(array $fkCosts) {
|
422 | 429 | $this->alteredCosts = $fkCosts;
|
423 | 430 | }
|
| 431 | + |
| 432 | + /** |
| 433 | + * Returns true if this foreign key represents an inheritance relationship, |
| 434 | + * i.e. if this foreign key is based on a primary key. |
| 435 | + * @param ForeignKeyConstraint $fk |
| 436 | + * @return true |
| 437 | + */ |
| 438 | + private function isInheritanceRelationship(ForeignKeyConstraint $fk) { |
| 439 | + if (!$fk->getLocalTable()->hasPrimaryKey()) { |
| 440 | + return false; |
| 441 | + } |
| 442 | + $fkColumnNames = $fk->getLocalColumns(); |
| 443 | + $pkColumnNames = $fk->getLocalTable()->getPrimaryKeyColumns(); |
| 444 | + |
| 445 | + sort($fkColumnNames); |
| 446 | + sort($pkColumnNames); |
| 447 | + |
| 448 | + return $fkColumnNames == $pkColumnNames; |
| 449 | + } |
| 450 | + |
| 451 | + /** |
| 452 | + * If this table is pointing to a parent table (if its primary key is a foreign key pointing on another table), |
| 453 | + * this function will return the pointed table. |
| 454 | + * This function will return null if there is no parent table. |
| 455 | + * |
| 456 | + * @param string $tableName |
| 457 | + * @return string|null |
| 458 | + */ |
| 459 | + public function getParentTable($tableName) { |
| 460 | + $cacheKey = $this->cachePrefix.'_parent_'.$tableName; |
| 461 | + $parent = $this->cache->fetch($cacheKey); |
| 462 | + if ($parent === false) { |
| 463 | + $parent = $this->getParentTableWithoutCache($tableName); |
| 464 | + $this->cache->save($cacheKey, $parent); |
| 465 | + } |
| 466 | + |
| 467 | + return $parent; |
| 468 | + } |
| 469 | + |
| 470 | + /** |
| 471 | + * If this table is pointing to a parent table (if its primary key is a foreign key pointing on another table), |
| 472 | + * this function will return the pointed table. |
| 473 | + * This function will return null if there is no parent table. |
| 474 | + * |
| 475 | + * @param string $tableName |
| 476 | + * @return string|null |
| 477 | + */ |
| 478 | + private function getParentTableWithoutCache($tableName) { |
| 479 | + $table = $this->getSchema()->getTable($tableName); |
| 480 | + foreach ($table->getForeignKeys() as $fk) { |
| 481 | + if ($this->isInheritanceRelationship($fk)) { |
| 482 | + return $fk->getForeignTableName(); |
| 483 | + } |
| 484 | + } |
| 485 | + return null; |
| 486 | + } |
| 487 | + |
| 488 | + /** |
| 489 | + * If this table is pointed by children tables (if other child tables have a primary key that is also a |
| 490 | + * foreign key to this table), this function will return the list of child tables. |
| 491 | + * This function will return an empty array if there are no children tables. |
| 492 | + * |
| 493 | + * @param string $tableName |
| 494 | + * @return string[] |
| 495 | + */ |
| 496 | + public function getChildrenTables($tableName) { |
| 497 | + $cacheKey = $this->cachePrefix.'_children_'.$tableName; |
| 498 | + $parent = $this->cache->fetch($cacheKey); |
| 499 | + if ($parent === false) { |
| 500 | + $parent = $this->getChildrenTablesWithoutCache($tableName); |
| 501 | + $this->cache->save($cacheKey, $parent); |
| 502 | + } |
| 503 | + |
| 504 | + return $parent; |
| 505 | + } |
| 506 | + |
| 507 | + /** |
| 508 | + * If this table is pointed by children tables (if other child tables have a primary key that is also a |
| 509 | + * foreign key to this table), this function will return the list of child tables. |
| 510 | + * This function will return an empty array if there are no children tables. |
| 511 | + * |
| 512 | + * @param string $tableName |
| 513 | + * @return string[] |
| 514 | + */ |
| 515 | + private function getChildrenTablesWithoutCache($tableName) { |
| 516 | + $schema = $this->getSchema(); |
| 517 | + $children = []; |
| 518 | + foreach ($schema->getTables() as $table) { |
| 519 | + if ($table->getName() === $tableName) { |
| 520 | + continue; |
| 521 | + } |
| 522 | + foreach ($table->getForeignKeys() as $fk) { |
| 523 | + if ($fk->getForeignTableName() === $tableName && $this->isInheritanceRelationship($fk)) { |
| 524 | + $children[] = $fk->getLocalTableName(); |
| 525 | + } |
| 526 | + } |
| 527 | + } |
| 528 | + return $children; |
| 529 | + } |
424 | 530 | }
|
0 commit comments