diff --git a/src/Mapper/Proxy/Hydrator/ClosureHydrator.php b/src/Mapper/Proxy/Hydrator/ClosureHydrator.php index cb0a3cf0..20054c39 100644 --- a/src/Mapper/Proxy/Hydrator/ClosureHydrator.php +++ b/src/Mapper/Proxy/Hydrator/ClosureHydrator.php @@ -109,9 +109,12 @@ private function setRelationProperties(array $properties, RelationMap $relMap, o ? $prop->getType()->getTypes() : [$prop->getType()]; + $relation = $relMap->getRelations()[$property]; foreach ($types as $type) { $c = $type->getName(); - if ($c === 'object' || $value instanceof $c) { + if ($c === 'object' || $c === 'mixed' || $value instanceof $c) { + $value = $relation->collect($relation->resolve($value, false)) ?? $value; + $object->{$property} = $value; unset($data[$property]); @@ -119,11 +122,7 @@ private function setRelationProperties(array $properties, RelationMap $relMap, o continue 2; } } - - $relation = $relMap->getRelations()[$property] ?? null; - if ($relation !== null) { - $value = $relation->collect($relation->resolve($value, true)); - } + $value = $relation->collect($relation->resolve($value, true)); } } diff --git a/src/Mapper/Proxy/ProxyEntityFactory.php b/src/Mapper/Proxy/ProxyEntityFactory.php index 0aaf78ca..46ab592b 100644 --- a/src/Mapper/Proxy/ProxyEntityFactory.php +++ b/src/Mapper/Proxy/ProxyEntityFactory.php @@ -50,7 +50,7 @@ public function create( ): object { $class = \array_key_exists($sourceClass, $this->classMap) ? $this->classMap[$sourceClass] - : $this->defineClass($relMap, $sourceClass); + : $this->defineClass($sourceClass); $proxy = $this->instantiator->instantiate($class); $proxy->__cycle_orm_rel_map = $relMap; @@ -137,7 +137,7 @@ private function entityToArray(object $entity): array return $result; } - private function defineClass(RelationMap $relMap, string $class): string + private function defineClass(string $class): string { if (!class_exists($class, true)) { throw new \RuntimeException(sprintf( diff --git a/tests/ORM/Functional/Driver/Common/Mapper/ProxyEntityMapper/EntityWithRelationHydrationTest.php b/tests/ORM/Functional/Driver/Common/Mapper/ProxyEntityMapper/EntityWithRelationHydrationTest.php index 60b36155..1da5d214 100644 --- a/tests/ORM/Functional/Driver/Common/Mapper/ProxyEntityMapper/EntityWithRelationHydrationTest.php +++ b/tests/ORM/Functional/Driver/Common/Mapper/ProxyEntityMapper/EntityWithRelationHydrationTest.php @@ -24,7 +24,7 @@ public function setUp(): void { parent::setUp(); - $this->makeTable('user', ['id' => 'primary', 'email' => 'string']); + $this->makeTable('user', ['id' => 'primary', 'email' => 'string', 'friend_id' => 'integer,nullable']); $this->makeTable('profile', ['id' => 'primary', 'name' => 'string', 'user_id' => 'integer']); $this->makeTable('tag', ['id' => 'primary', 'name' => 'string',]); $this->makeTable('tag_user', ['user_id' => 'integer', 'tag_id' => 'integer',]); @@ -210,10 +210,38 @@ public function setUp(): void ], ], ], + EntityWithMixedTypeRelation::class => [ + Schema::ROLE => 'mixed_type', + Schema::MAPPER => Mapper::class, + Schema::DATABASE => 'default', + Schema::TABLE => 'user', + Schema::PRIMARY_KEY => 'id', + Schema::COLUMNS => [ + 'id' => 'id', + 'email' => 'email', + 'friend_id' => 'friend_id', + ], + Schema::TYPECAST => ['id' => 'int', 'friend_id' => 'int'], + Schema::SCHEMA => [], + Schema::RELATIONS => [ + 'friend' => [ + Relation::TYPE => Relation::BELONGS_TO, + Relation::TARGET => EntityWithMixedTypeRelation::class, + Relation::LOAD => Relation::LOAD_PROMISE, + + Relation::SCHEMA => [ + Relation::NULLABLE => false, + Relation::CASCADE => true, + Relation::OUTER_KEY => 'id', + Relation::INNER_KEY => 'friend_id', + ], + ], + ], + ], ])); } - public function testPrivateBelongsToRelationPropertyWithoutProxyShouldBeFilled() + public function testPrivateBelongsToRelationPropertyWithoutProxyShouldBeFilled(): void { $profile = new EntityWithRelationHydrationProfile('test'); $profile->user_id = 1; @@ -224,7 +252,30 @@ public function testPrivateBelongsToRelationPropertyWithoutProxyShouldBeFilled() // $this->assertInstanceOf(ReferenceInterface::class, $profile->getRefersUser()); } - public function testPrivateHasManyRelationPropertyWithoutProxyShouldBeFilled() + public function testRelationWithMixedTypeShouldBeFilledAsReference(): void + { + $user = new EntityWithMixedTypeRelation(); + $user->email = 'foo@bar.com'; + $user->friend_id = 1; + + $this->save($user); + + $this->assertInstanceOf(ReferenceInterface::class, $user->friend); + } + + public function testRelationExistedInHeapMustFilledAsEntity(): void + { + $user = new EntityWithMixedTypeRelation(); + $user->email = 'foo@bar.com'; + $user->friend_id = 1; + + $this->orm->getRepository(EntityWithMixedTypeRelation::class)->findByPK(1); + + $this->save($user); + $this->assertInstanceOf(EntityWithMixedTypeRelation::class, $user->friend); + } + + public function testPrivateHasManyRelationPropertyWithoutProxyShouldBeFilled(): void { $profile = new EntityWithRelationHydrationProfile('test'); $user = new EntityWithRelationHydrationUser('admin@site.com'); @@ -235,7 +286,7 @@ public function testPrivateHasManyRelationPropertyWithoutProxyShouldBeFilled() $this->assertSame($user, $profile->getUser()); } - public function testPrivateManyToManyRelationPropertyWithoutProxyShouldBeFilled() + public function testPrivateManyToManyRelationPropertyWithoutProxyShouldBeFilled(): void { $tagContext = new EntityWithRelationHydrationTagContext(); $tagContext->user_id = 1; @@ -250,7 +301,7 @@ public function testPrivateManyToManyRelationPropertyWithoutProxyShouldBeFilled( /** * TODO: error with shadow belongs to */ - public function testPrivatMorphBelongsToRelationPropertyWithoutProxyShouldBeFilled() + public function testPrivateMorphBelongsToRelationPropertyWithoutProxyShouldBeFilled(): void { $profile = new EntityWithRelationHydrationProfile('test'); $profile->user_id = 1; @@ -307,7 +358,7 @@ public function testChangeLazyOverloadedArray(): void $this->assertContains('test-value', $user->profiles); } - public function testGetLinkValueFromLazyOverloadedRelation() + public function testGetLinkValueFromLazyOverloadedRelation(): void { $user = (new Select($this->orm, EntityWithRelationHydrationUser::class)) ->fetchOne(); @@ -433,3 +484,11 @@ public function setParent($parent): void $this->parent = $parent; } } + +class EntityWithMixedTypeRelation +{ + public int $id; + public string $email; + public ?int $friend_id = null; + public mixed $friend; +}