From 7988b08d46663a17a2567cf5578e7060a326ebf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Pel=C3=AD=C5=A1ek?= Date: Fri, 21 Jun 2024 11:26:07 +0200 Subject: [PATCH 01/12] Update Configurator.php --- src/Configurator.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Configurator.php b/src/Configurator.php index e5b06eb..cf3dc6f 100644 --- a/src/Configurator.php +++ b/src/Configurator.php @@ -120,6 +120,11 @@ public function initFields(EntitySchema $entity, \ReflectionClass $class, string public function initRelations(EntitySchema $entity, \ReflectionClass $class): void { foreach ($class->getProperties() as $property) { + // ignore relations declared by parent class - otherwise all the relation columns declared in parent would be duplicated across all child tables in JTI + if ($property->getDeclaringClass()->getName() !== $class->getName()) { + continue; + } + $metadata = $this->getPropertyMetadata($property, RelationAnnotation\RelationInterface::class); foreach ($metadata as $meta) { From fb0f28f0e7ed3ae577b6f68ded1007280fd60e63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Pel=C3=AD=C5=A1ek?= Date: Fri, 21 Jun 2024 11:35:25 +0200 Subject: [PATCH 02/12] Codestyle --- src/Configurator.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Configurator.php b/src/Configurator.php index cf3dc6f..5e47e67 100644 --- a/src/Configurator.php +++ b/src/Configurator.php @@ -120,11 +120,12 @@ public function initFields(EntitySchema $entity, \ReflectionClass $class, string public function initRelations(EntitySchema $entity, \ReflectionClass $class): void { foreach ($class->getProperties() as $property) { - // ignore relations declared by parent class - otherwise all the relation columns declared in parent would be duplicated across all child tables in JTI + // ignore properties declared by parent class + // otherwise all the relation columns declared in parent would be duplicated across all child tables in JTI if ($property->getDeclaringClass()->getName() !== $class->getName()) { continue; } - + $metadata = $this->getPropertyMetadata($property, RelationAnnotation\RelationInterface::class); foreach ($metadata as $meta) { From ad298862f2a6fabd152a91b3adb9a8b4e4256b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Pel=C3=AD=C5=A1ek?= Date: Fri, 21 Jun 2024 12:13:59 +0200 Subject: [PATCH 03/12] Implement logic to identity ownership of property --- src/Configurator.php | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Configurator.php b/src/Configurator.php index 5e47e67..05c3522 100644 --- a/src/Configurator.php +++ b/src/Configurator.php @@ -122,7 +122,7 @@ public function initRelations(EntitySchema $entity, \ReflectionClass $class): vo foreach ($class->getProperties() as $property) { // ignore properties declared by parent class // otherwise all the relation columns declared in parent would be duplicated across all child tables in JTI - if ($property->getDeclaringClass()->getName() !== $class->getName()) { + if ($this->propertyBelongsToOtherEntity($class, $property->getDeclaringClass())) { continue; } @@ -419,4 +419,26 @@ private function isOnInsertGeneratedField(Field $field): bool default => $field->isPrimary() }; } + + private function propertyBelongsToOtherEntity(\ReflectionClass $currentClass, \ReflectionClass $declaringClass): bool + { + if ($currentClass->getName() === $declaringClass->getName()) { + return false; + } + + $parentClass = $currentClass->getParentClass(); + + // not possible to happen for logical reasons, but defensively check anyway + if (!$parentClass instanceof \ReflectionClass) { + return false; + } + + // if a parent class in hierarchy is an Entity on its own, the property belongs to that Entity + if (\count($parentClass->getAttributes(Entity::class)) > 0) { + return true; + } + + // continue until we find a declaringClass or Entity attribute + return $this->propertyBelongsToOtherEntity($parentClass, $declaringClass); + } } From 8954c013030a3089868bc5edfd079e5183a8d19b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Pel=C3=AD=C5=A1ek?= Date: Fri, 21 Jun 2024 12:19:10 +0200 Subject: [PATCH 04/12] Added comment --- src/Configurator.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Configurator.php b/src/Configurator.php index 05c3522..8c40402 100644 --- a/src/Configurator.php +++ b/src/Configurator.php @@ -422,6 +422,7 @@ private function isOnInsertGeneratedField(Field $field): bool private function propertyBelongsToOtherEntity(\ReflectionClass $currentClass, \ReflectionClass $declaringClass): bool { + // if the current class is the same as declaring class, than the property belongs to current Entity if ($currentClass->getName() === $declaringClass->getName()) { return false; } From 90989a4e88d68e7c3504e47587ede43cc42f1ef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Pel=C3=AD=C5=A1ek?= Date: Fri, 21 Jun 2024 23:48:35 +0200 Subject: [PATCH 05/12] Implement entity lookup in hierarchy, closes #101 --- src/Configurator.php | 51 +++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/src/Configurator.php b/src/Configurator.php index 8c40402..1b38aa4 100644 --- a/src/Configurator.php +++ b/src/Configurator.php @@ -112,7 +112,7 @@ public function initFields(EntitySchema $entity, \ReflectionClass $class, string } $field = $this->initField($property->getName(), $column, $class, $columnPrefix); - $field->setEntityClass($property->getDeclaringClass()->getName()); + $field->setEntityClass($this->findOwningEntity($class, $property->getDeclaringClass())->getName()); $entity->getFields()->set($property->getName(), $field); } } @@ -120,9 +120,9 @@ public function initFields(EntitySchema $entity, \ReflectionClass $class, string public function initRelations(EntitySchema $entity, \ReflectionClass $class): void { foreach ($class->getProperties() as $property) { - // ignore properties declared by parent class + // ignore properties declared by parent entties // otherwise all the relation columns declared in parent would be duplicated across all child tables in JTI - if ($this->propertyBelongsToOtherEntity($class, $property->getDeclaringClass())) { + if ($this->findOwningEntity($class, $property->getDeclaringClass())->getName() !== $class->getName()) { continue; } @@ -420,26 +420,37 @@ private function isOnInsertGeneratedField(Field $field): bool }; } - private function propertyBelongsToOtherEntity(\ReflectionClass $currentClass, \ReflectionClass $declaringClass): bool + /** + * Function to find an owning entity class in the inheritance hierarchy. + * + * Entity classes may extend a base class and this function is needed route the properties from declaring class to the entity class. + * The function stops only when the declaring class is truly found, it does not naively stop on first entity. + * This behaviour makes it also functional in cases of Joined Table Inheritance on theoretically any number of nesting levels. + */ + private function findOwningEntity(\ReflectionClass $currentClass, \ReflectionClass $declaringClass): \ReflectionClass { - // if the current class is the same as declaring class, than the property belongs to current Entity - if ($currentClass->getName() === $declaringClass->getName()) { - return false; - } - - $parentClass = $currentClass->getParentClass(); + // latest found entityClass before declaringClass + $latestEntityClass = $currentClass; + + do { + // we found declaringClass in the hierarchy + // in most cases the execution will stop here in first loop + if ($currentClass->getName() === $declaringClass->getName()) { + return $latestEntityClass; + } - // not possible to happen for logical reasons, but defensively check anyway - if (!$parentClass instanceof \ReflectionClass) { - return false; - } + $currentClass = $currentClass->getParentClass(); - // if a parent class in hierarchy is an Entity on its own, the property belongs to that Entity - if (\count($parentClass->getAttributes(Entity::class)) > 0) { - return true; - } + // not possible to happen for logical reasons, but defensively check anyway + if (!$currentClass instanceof \ReflectionClass) { + return $latestEntityClass; + } - // continue until we find a declaringClass or Entity attribute - return $this->propertyBelongsToOtherEntity($parentClass, $declaringClass); + // if a currentClass in hierarchy is an entity on its own, the property belongs to that entity + if (\count($currentClass->getAttributes(Entity::class)) > 0) { + $latestEntityClass = $currentClass; + } + } while (true); // the inheritance hierarchy cannot be infinite } } + From 300e21d0005225594e53421d199b678d8ac08753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Pel=C3=AD=C5=A1ek?= Date: Fri, 21 Jun 2024 23:49:28 +0200 Subject: [PATCH 06/12] Codestyle --- src/Configurator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Configurator.php b/src/Configurator.php index 1b38aa4..16592e8 100644 --- a/src/Configurator.php +++ b/src/Configurator.php @@ -422,7 +422,7 @@ private function isOnInsertGeneratedField(Field $field): bool /** * Function to find an owning entity class in the inheritance hierarchy. - * + * * Entity classes may extend a base class and this function is needed route the properties from declaring class to the entity class. * The function stops only when the declaring class is truly found, it does not naively stop on first entity. * This behaviour makes it also functional in cases of Joined Table Inheritance on theoretically any number of nesting levels. From 5b965a00acc4965986bcaa811ff0c15e7796d43e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Pel=C3=AD=C5=A1ek?= Date: Sun, 23 Jun 2024 11:01:56 +0200 Subject: [PATCH 07/12] Codestyle --- src/Configurator.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Configurator.php b/src/Configurator.php index 16592e8..fb42215 100644 --- a/src/Configurator.php +++ b/src/Configurator.php @@ -453,4 +453,3 @@ private function findOwningEntity(\ReflectionClass $currentClass, \ReflectionCla } while (true); // the inheritance hierarchy cannot be infinite } } - From 3b612fcf4f9be424f9203bb9e1a548aefce48bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Pel=C3=AD=C5=A1ek?= Date: Sun, 23 Jun 2024 11:03:07 +0200 Subject: [PATCH 08/12] Downgrade mysql in tests to 8.0 --- tests/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml index 5ee2054..2c2cf73 100644 --- a/tests/docker-compose.yml +++ b/tests/docker-compose.yml @@ -11,7 +11,7 @@ services: ACCEPT_EULA: "Y" mysql_latest: - image: mysql:latest + image: mysql:8.0 restart: always command: --default-authentication-plugin=mysql_native_password ports: From 309bf55909e3118568f6d91ff4954570406baa7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Pel=C3=AD=C5=A1ek?= Date: Sun, 23 Jun 2024 11:29:04 +0200 Subject: [PATCH 09/12] Fixed dataprovider deprecations introduced in phpunit 10.5.17 --- tests/Annotated/Functional/Driver/Common/BaseTestCase.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Annotated/Functional/Driver/Common/BaseTestCase.php b/tests/Annotated/Functional/Driver/Common/BaseTestCase.php index 05fbcda..54f3a2c 100644 --- a/tests/Annotated/Functional/Driver/Common/BaseTestCase.php +++ b/tests/Annotated/Functional/Driver/Common/BaseTestCase.php @@ -115,14 +115,14 @@ public function getDriver(): Driver public static function singularReadersProvider(): \Traversable { - yield ['Annotation reader' => new AnnotationReader()]; - yield ['Attribute reader' => new AttributeReader()]; + yield ['reader' => new AnnotationReader()]; + yield ['reader' => new AttributeReader()]; } public static function allReadersProvider(): \Traversable { yield from static::singularReadersProvider(); - yield ['Selective reader' => new SelectiveReader([new AttributeReader(), new AnnotationReader()])]; + yield ['reader' => new SelectiveReader([new AttributeReader(), new AnnotationReader()])]; } protected function getDatabase(): Database From c7ed9bdae626d6edea6fea05307791adf9b9bb30 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 25 Jun 2024 11:15:13 +0400 Subject: [PATCH 10/12] Fix inheritance tests; revert changes in metadata reader providers --- src/TableInheritance.php | 6 +++++- tests/Annotated/Fixtures/Fixtures16/ExecutiveProxy.php | 5 ++--- tests/Annotated/Functional/Driver/Common/BaseTestCase.php | 6 +++--- .../Driver/Common/Inheritance/JoinedTableTestCase.php | 2 +- .../Functional/Driver/Common/InheritanceTestCase.php | 7 ++++++- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/TableInheritance.php b/src/TableInheritance.php index 176a36f..3152c15 100644 --- a/src/TableInheritance.php +++ b/src/TableInheritance.php @@ -66,7 +66,11 @@ public function run(Registry $registry): Registry // All child should be presented in a schema as separated entity // Every child will be handled according its table inheritance type - \assert($child->getRole() !== null && $entity !== null && isset($parent)); + // todo should $parent be not null? + // \assert(isset($parent)); + + \assert($child->getRole() !== null && $entity !== null); + if (!$registry->hasEntity($child->getRole())) { $registry->register($child); diff --git a/tests/Annotated/Fixtures/Fixtures16/ExecutiveProxy.php b/tests/Annotated/Fixtures/Fixtures16/ExecutiveProxy.php index c4d6356..0adf88d 100644 --- a/tests/Annotated/Fixtures/Fixtures16/ExecutiveProxy.php +++ b/tests/Annotated/Fixtures/Fixtures16/ExecutiveProxy.php @@ -10,12 +10,11 @@ /** * This proxy class doesn't have an {@see Entity} annotation (attribute) declaration, * and it shouldn't be presented in Schema. - * Note: this behavior might be improved. There will be added support for - * annotated base class columns without Entity annotation declaration. + * But all the classes that extend this class should contain all the fields from this class. */ class ExecutiveProxy extends Employee { - /** @Column(type="string") */ + /** @Column(type="string", name="proxy") */ #[Column(type: 'string', name: 'proxy')] public ?string $proxyFieldWithAnnotation = null; diff --git a/tests/Annotated/Functional/Driver/Common/BaseTestCase.php b/tests/Annotated/Functional/Driver/Common/BaseTestCase.php index 54f3a2c..05fbcda 100644 --- a/tests/Annotated/Functional/Driver/Common/BaseTestCase.php +++ b/tests/Annotated/Functional/Driver/Common/BaseTestCase.php @@ -115,14 +115,14 @@ public function getDriver(): Driver public static function singularReadersProvider(): \Traversable { - yield ['reader' => new AnnotationReader()]; - yield ['reader' => new AttributeReader()]; + yield ['Annotation reader' => new AnnotationReader()]; + yield ['Attribute reader' => new AttributeReader()]; } public static function allReadersProvider(): \Traversable { yield from static::singularReadersProvider(); - yield ['reader' => new SelectiveReader([new AttributeReader(), new AnnotationReader()])]; + yield ['Selective reader' => new SelectiveReader([new AttributeReader(), new AnnotationReader()])]; } protected function getDatabase(): Database diff --git a/tests/Annotated/Functional/Driver/Common/Inheritance/JoinedTableTestCase.php b/tests/Annotated/Functional/Driver/Common/Inheritance/JoinedTableTestCase.php index 52ec0e6..64d32f5 100644 --- a/tests/Annotated/Functional/Driver/Common/Inheritance/JoinedTableTestCase.php +++ b/tests/Annotated/Functional/Driver/Common/Inheritance/JoinedTableTestCase.php @@ -125,7 +125,7 @@ public function testTableInheritance(ReaderInterface $reader): void $this->assertSame('secret', $loadedExecutive->hidden); $this->assertSame(15000, $loadedExecutive->bonus); $this->assertSame('executive', $loadedExecutive->getType()); - $this->assertNull($loadedExecutive->proxyFieldWithAnnotation); + $this->assertSame('value', $loadedExecutive->proxyFieldWithAnnotation); } #[DataProvider('allReadersProvider')] diff --git a/tests/Annotated/Functional/Driver/Common/InheritanceTestCase.php b/tests/Annotated/Functional/Driver/Common/InheritanceTestCase.php index 515fd52..2445741 100644 --- a/tests/Annotated/Functional/Driver/Common/InheritanceTestCase.php +++ b/tests/Annotated/Functional/Driver/Common/InheritanceTestCase.php @@ -109,7 +109,12 @@ public function testTableInheritance(ReaderInterface $reader): void $this->assertSame('foo_id', $schema['executive'][SchemaInterface::PARENT_KEY]); $this->assertSame('executives', $schema['executive'][SchemaInterface::TABLE]); $this->assertSame( - ['bonus' => 'bonus', 'foo_id' => 'id', 'hidden' => 'hidden'], + [ + 'bonus' => 'bonus', + 'proxyFieldWithAnnotation' => 'proxy', + 'foo_id' => 'id', + 'hidden' => 'hidden', + ], $schema['executive'][SchemaInterface::COLUMNS] ); From eba2dba083b930ec5c2d76f2205743b55da573ee Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 25 Jun 2024 13:19:37 +0400 Subject: [PATCH 11/12] Fix data provider keys --- tests/Annotated/Functional/Driver/Common/BaseTestCase.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Annotated/Functional/Driver/Common/BaseTestCase.php b/tests/Annotated/Functional/Driver/Common/BaseTestCase.php index 05fbcda..4d1111b 100644 --- a/tests/Annotated/Functional/Driver/Common/BaseTestCase.php +++ b/tests/Annotated/Functional/Driver/Common/BaseTestCase.php @@ -115,14 +115,14 @@ public function getDriver(): Driver public static function singularReadersProvider(): \Traversable { - yield ['Annotation reader' => new AnnotationReader()]; - yield ['Attribute reader' => new AttributeReader()]; + yield 'Annotation reader' => [new AnnotationReader()]; + yield 'Attribute reader' => [new AttributeReader()]; } public static function allReadersProvider(): \Traversable { yield from static::singularReadersProvider(); - yield ['Selective reader' => new SelectiveReader([new AttributeReader(), new AnnotationReader()])]; + yield 'Selective reader' => [new SelectiveReader([new AttributeReader(), new AnnotationReader()])]; } protected function getDatabase(): Database From 8da78c1608b2dde5ccae09daa789bd9a86f67d7e Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 2 Jul 2024 17:08:41 +0400 Subject: [PATCH 12/12] Add test with inherited relation --- src/Configurator.php | 2 +- .../Fixtures/Fixtures16/Executive.php | 9 +++++++ .../Fixtures/Fixtures16/Executive2.php | 18 +++++++++++++ .../Annotated/Fixtures/Fixtures16/Person.php | 9 +++++++ tests/Annotated/Fixtures/Fixtures16/Tool.php | 22 ++++++++++++++++ .../Driver/Common/InheritanceTestCase.php | 26 ++++++++++++++++--- 6 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 tests/Annotated/Fixtures/Fixtures16/Executive2.php create mode 100644 tests/Annotated/Fixtures/Fixtures16/Tool.php diff --git a/src/Configurator.php b/src/Configurator.php index fb42215..4a1d9a4 100644 --- a/src/Configurator.php +++ b/src/Configurator.php @@ -120,7 +120,7 @@ public function initFields(EntitySchema $entity, \ReflectionClass $class, string public function initRelations(EntitySchema $entity, \ReflectionClass $class): void { foreach ($class->getProperties() as $property) { - // ignore properties declared by parent entties + // ignore properties declared by parent entities // otherwise all the relation columns declared in parent would be duplicated across all child tables in JTI if ($this->findOwningEntity($class, $property->getDeclaringClass())->getName() !== $class->getName()) { continue; diff --git a/tests/Annotated/Fixtures/Fixtures16/Executive.php b/tests/Annotated/Fixtures/Fixtures16/Executive.php index 4e9f4f9..b09be11 100644 --- a/tests/Annotated/Fixtures/Fixtures16/Executive.php +++ b/tests/Annotated/Fixtures/Fixtures16/Executive.php @@ -7,6 +7,7 @@ use Cycle\Annotated\Annotation\Column; use Cycle\Annotated\Annotation\Entity; use Cycle\Annotated\Annotation\Inheritance\JoinedTable as InheritanceJoinedTable; +use Cycle\Annotated\Annotation\Relation\HasOne; /** * @Entity @@ -21,4 +22,12 @@ class Executive extends ExecutiveProxy /** @Column(type="int") */ #[Column(type: 'int')] public int $bonus; + + /** @Column(type="int", nullable=true, typecast="int") */ + #[Column(type: 'int', nullable: true, typecast: 'int')] + public ?int $added_tool_id; + + /** @HasOne(target=Tool::class, innerKey="added_tool_id", outerKey="added_tool_id", nullable=true) */ + #[HasOne(target: Tool::class, innerKey: 'added_tool_id', outerKey: 'added_tool_id', nullable: true)] + public Tool $addedTool; } diff --git a/tests/Annotated/Fixtures/Fixtures16/Executive2.php b/tests/Annotated/Fixtures/Fixtures16/Executive2.php new file mode 100644 index 0000000..571707f --- /dev/null +++ b/tests/Annotated/Fixtures/Fixtures16/Executive2.php @@ -0,0 +1,18 @@ +foo_id; diff --git a/tests/Annotated/Fixtures/Fixtures16/Tool.php b/tests/Annotated/Fixtures/Fixtures16/Tool.php new file mode 100644 index 0000000..5a19424 --- /dev/null +++ b/tests/Annotated/Fixtures/Fixtures16/Tool.php @@ -0,0 +1,22 @@ +assertArrayHasKey('tool', $schema); + // Person $this->assertCount(3, $schema['person'][SchemaInterface::CHILDREN]); $this->assertEquals([ @@ -86,43 +90,56 @@ public function testTableInheritance(ReaderInterface $reader): void // 'bonus' => 'bonus', // JTI 'preferences' => 'preferences', 'stocks' => 'stocks', + 'tool_id' => 'tool_id', // 'teethAmount' => 'teeth_amount', // Not child ], $schema['person'][SchemaInterface::COLUMNS]); $this->assertEmpty($schema['person'][SchemaInterface::PARENT] ?? null); $this->assertEmpty($schema['person'][SchemaInterface::PARENT_KEY] ?? null); $this->assertSame('people', $schema['person'][SchemaInterface::TABLE]); + $this->assertCount(1, $schema['person'][SchemaInterface::RELATIONS]); // Employee $this->assertArrayHasKey('employee', $schema); $this->assertCount(1, $schema['employee']); $this->assertSame(Employee::class, $schema['employee'][SchemaInterface::ENTITY]); $this->assertNull($schema['employee'][SchemaInterface::TABLE] ?? null); + $this->assertCount(0, $schema['employee'][SchemaInterface::RELATIONS] ?? []); // Customer $this->assertArrayHasKey('customer', $schema); $this->assertCount(1, $schema['customer']); $this->assertSame(Customer::class, $schema['customer'][SchemaInterface::ENTITY]); $this->assertNull($schema['customer'][SchemaInterface::TABLE] ?? null); + $this->assertCount(0, $schema['customer'][SchemaInterface::RELATIONS] ?? []); // Executive $this->assertSame('employee', $schema['executive'][SchemaInterface::PARENT]); $this->assertSame('foo_id', $schema['executive'][SchemaInterface::PARENT_KEY]); $this->assertSame('executives', $schema['executive'][SchemaInterface::TABLE]); - $this->assertSame( + $this->assertEquals( [ 'bonus' => 'bonus', 'proxyFieldWithAnnotation' => 'proxy', 'foo_id' => 'id', 'hidden' => 'hidden', + 'added_tool_id' => 'added_tool_id', ], - $schema['executive'][SchemaInterface::COLUMNS] + $schema['executive'][SchemaInterface::COLUMNS], ); + $this->assertCount(1, $schema['executive'][SchemaInterface::RELATIONS]); + + // Executive2 + $this->assertSame('executive', $schema['executive2'][SchemaInterface::PARENT]); + $this->assertSame('foo_id', $schema['executive2'][SchemaInterface::PARENT_KEY]); + $this->assertEquals(['foo_id' => 'id'], $schema['executive2'][SchemaInterface::COLUMNS]); + $this->assertCount(0, $schema['executive2'][SchemaInterface::RELATIONS]); // Ceo $this->assertArrayHasKey('ceo', $schema); $this->assertCount(1, $schema['ceo']); $this->assertSame(Ceo::class, $schema['ceo'][SchemaInterface::ENTITY]); $this->assertNull($schema['ceo'][SchemaInterface::TABLE] ?? null); + $this->assertCount(0, $schema['ceo'][SchemaInterface::RELATIONS] ?? []); // Beaver $this->assertEmpty($schema['beaver'][SchemaInterface::DISCRIMINATOR] ?? null); @@ -130,13 +147,15 @@ public function testTableInheritance(ReaderInterface $reader): void $this->assertEmpty($schema['beaver'][SchemaInterface::PARENT_KEY] ?? null); $this->assertEmpty($schema['beaver'][SchemaInterface::CHILDREN] ?? null); $this->assertSame('beavers', $schema['beaver'][SchemaInterface::TABLE]); - $this->assertSame([ + $this->assertEquals([ 'teethAmount' => 'teeth_amount', 'foo_id' => 'id', 'name' => 'name', 'type' => 'type', 'hidden' => 'hidden', + 'tool_id' => 'tool_id', ], $schema['beaver'][SchemaInterface::COLUMNS]); + $this->assertCount(1, $schema['beaver'][SchemaInterface::RELATIONS] ?? []); } public function testTableInheritanceWithIncorrectClassesOrder(): void @@ -150,6 +169,7 @@ public function testTableInheritanceWithIncorrectClassesOrder(): void new \ReflectionClass(Employee::class), new \ReflectionClass(Executive::class), new \ReflectionClass(Person::class), + new \ReflectionClass(Tool::class), ]); $schema = (new Compiler())->compile($r, [