diff --git a/src/TableInheritance.php b/src/TableInheritance.php index f614c358..66989258 100644 --- a/src/TableInheritance.php +++ b/src/TableInheritance.php @@ -7,6 +7,7 @@ use Cycle\Annotated\Annotation\Inheritance; use Cycle\Annotated\Exception\AnnotationException; use Cycle\Annotated\Utils\EntityUtils; +use Cycle\Schema\Definition\Entity; use Cycle\Schema\Definition\Entity as EntitySchema; use Cycle\Schema\Definition\Inheritance\JoinedTable as JoinedTableInheritanceSchema; use Cycle\Schema\Definition\Inheritance\SingleTable as SingleTableInheritanceSchema; @@ -57,8 +58,8 @@ public function run(Registry $registry): Registry $childClass = $parent->getClass(); } while ($this->parseMetadata($parent, Inheritance::class) !== null); - if ($entity = $this->initInheritance($annotation, $child, $parent)) { - $found[] = $entity; + if ($inheritanceEntity = $this->initInheritance($annotation, $child, $parent)) { + $found[] = $inheritanceEntity; } } @@ -67,17 +68,10 @@ public function run(Registry $registry): Registry if (!$registry->hasEntity($child->getRole())) { $registry->register($child); - $database = $child->getDatabase(); - $tableName = $child->getTableName(); - if ($entity->getInheritance() instanceof SingleTableInheritanceSchema) { - $database = $parent->getDatabase(); - $tableName = $parent->getTableName(); - } - $registry->linkTable( $child, - $database, - $tableName, + $this->getDatabase($child, $registry), + $this->getTableName($child, $registry) ); } } @@ -285,4 +279,36 @@ private function getOuterFields( return $parent->getPrimaryFields(); } + + private function getTableName(Entity $child, Registry $registry): string + { + $parent = $this->findParent($registry, $this->utils->findParent($child->getClass(), false)); + + $inheritance = $parent->getInheritance(); + if (!$inheritance instanceof SingleTableInheritanceSchema) { + return $child->getTableName(); + } + $entities = \array_map( + static fn (string $role) => $registry->getEntity($role)->getClass(), + $inheritance->getChildren() + ); + + return \in_array($child->getClass(), $entities, true) ? $parent->getTableName() : $child->getTableName(); + } + + private function getDatabase(Entity $child, Registry $registry): ?string + { + $parent = $this->findParent($registry, $this->utils->findParent($child->getClass(), false)); + + $inheritance = $parent->getInheritance(); + if (!$inheritance instanceof SingleTableInheritanceSchema) { + return $child->getDatabase(); + } + $entities = \array_map( + static fn (string $role) => $registry->getEntity($role)->getClass(), + $inheritance->getChildren() + ); + + return \in_array($child->getClass(), $entities, true) ? $parent->getDatabase() : $child->getDatabase(); + } } diff --git a/tests/Annotated/Functional/Driver/Common/InheritanceTest.php b/tests/Annotated/Functional/Driver/Common/InheritanceTest.php index 19c39523..3702e647 100644 --- a/tests/Annotated/Functional/Driver/Common/InheritanceTest.php +++ b/tests/Annotated/Functional/Driver/Common/InheritanceTest.php @@ -12,6 +12,8 @@ use Cycle\Annotated\Tests\Fixtures\Fixtures16\Ceo; use Cycle\Annotated\Tests\Fixtures\Fixtures16\Customer; use Cycle\Annotated\Tests\Fixtures\Fixtures16\Employee; +use Cycle\Annotated\Tests\Fixtures\Fixtures16\Executive; +use Cycle\Annotated\Tests\Fixtures\Fixtures16\Person; use Cycle\ORM\SchemaInterface; use Cycle\Schema\Compiler; use Cycle\Schema\Generator\GenerateRelations; @@ -21,7 +23,9 @@ use Cycle\Schema\Generator\ResetTables; use Cycle\Schema\Generator\SyncTables; use Cycle\Schema\Registry; +use Spiral\Attributes\AttributeReader; use Spiral\Attributes\ReaderInterface; +use Spiral\Tokenizer\ClassesInterface; use Spiral\Tokenizer\Config\TokenizerConfig; use Spiral\Tokenizer\Tokenizer; @@ -128,4 +132,36 @@ public function testTableInheritance(ReaderInterface $reader): void 'hidden' => 'hidden', ], $schema['beaver'][SchemaInterface::COLUMNS]); } + + public function testTableInheritanceWithIncorrectClassesOrder(): void + { + $r = new Registry($this->dbal); + $reader = new AttributeReader(); + $locator = $this->createMock(ClassesInterface::class); + $locator + ->method('getClasses') + ->willReturn([ + new \ReflectionClass(Employee::class), + new \ReflectionClass(Executive::class), + new \ReflectionClass(Person::class), + ]); + + $schema = (new Compiler())->compile($r, [ + new Embeddings($locator, $reader), + new Entities($locator, $reader), + new TableInheritance($reader), + new ResetTables(), + new MergeColumns($reader), + new GenerateRelations(), + new RenderTables(), + new RenderRelations(), + new MergeIndexes($reader), + new SyncTables(), + new GenerateTypecast(), + ]); + + $this->assertSame('executives', $schema['executive'][SchemaInterface::TABLE]); + $this->assertNull($schema['employee'][SchemaInterface::TABLE] ?? null); + $this->assertSame('people', $schema['person'][SchemaInterface::TABLE]); + } }