Skip to content

Commit

Permalink
EntityManager::getReference() should handle a PK which is also a FK
Browse files Browse the repository at this point in the history
  • Loading branch information
le-yak committed Sep 17, 2024
1 parent cfc0655 commit d29511b
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 3 deletions.
2 changes: 1 addition & 1 deletion docs/en/reference/advanced-configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ for the ``$identifier`` parameter is passed. ``$identifier`` values are
not checked and there is no guarantee that the requested entity instance even
exists – the method will still return a proxy object.

Its only when the proxy has to be fully initialized or associations cannot
It is only when the proxy has to be fully initialized or associations cannot
be written to the database that invalid ``$identifier`` values may lead to
exceptions.

Expand Down
13 changes: 13 additions & 0 deletions src/EntityManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,19 @@ public function getReference(string $entityName, mixed $id): object|null
if (! is_array($id)) {
$id = [$class->identifier[0] => $id];
}

Check failure on line 368 in src/EntityManager.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (8.3)

Whitespace found at end of line
foreach ($id as $i => $value) {
if (is_object($value)) {
$className = DefaultProxyClassNameResolver::getClass($value);
if ($this->metadataFactory->hasMetadataFor($className)) {
$id[$i] = $this->unitOfWork->getSingleIdentifierValue($value);

if ($id[$i] === null) {
throw ORMInvalidArgumentException::invalidIdentifierBindingEntity($className);

Check warning on line 376 in src/EntityManager.php

View check run for this annotation

Codecov / codecov/patch

src/EntityManager.php#L376

Added line #L376 was not covered by tests
}
}
}
}

$sortedId = [];

Expand Down
14 changes: 12 additions & 2 deletions src/Proxy/ProxyFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,9 @@ private function getProxyFactory(string $className): Closure
$initializer = $this->createLazyInitializer($class, $entityPersister, $this->identifierFlattener);
$proxyClassName = $this->loadProxyClass($class);
$identifierFields = array_intersect_key($class->getReflectionProperties(), $identifiers);
$em = $this->em;

$proxyFactory = Closure::bind(static function (array $identifier) use ($initializer, $skippedProperties, $identifierFields, $className): InternalProxy {
$proxyFactory = Closure::bind(static function (array $identifier) use ($initializer, $skippedProperties, $identifierFields, $className, $class, $em): InternalProxy {
$proxy = self::createLazyGhost(static function (InternalProxy $object) use ($initializer, $identifier): void {
$initializer($object, $identifier);
}, $skippedProperties);
Expand All @@ -292,7 +293,16 @@ private function getProxyFactory(string $className): Closure
}

assert($reflector !== null);
$reflector->setValue($proxy, $identifier[$idField]);

$idValue = $identifier[$idField];
if ($class->hasAssociation($idField)) {
$idValue = $em->getReference(
$class->getAssociationTargetClass($idField),
$idValue,
);
}

$reflector->setValue($proxy, $idValue);
}

return $proxy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Doctrine\Tests\Models\GeoNames\Admin1AlternateName;
use Doctrine\Tests\Models\GeoNames\Country;
use Doctrine\Tests\OrmFunctionalTestCase;
use Doctrine\Tests\Proxies\__CG__\Doctrine\Tests\Models\GeoNames\Country as CountryProxy;

class CompositePrimaryKeyWithAssociationsTest extends OrmFunctionalTestCase
{
Expand Down Expand Up @@ -61,4 +62,19 @@ public function testFindByAbleToGetCompositeEntitiesWithMixedTypeIdentifiers():
self::assertEquals(2, $name2->id);
self::assertEquals('Rome', $name2->name);
}

public function testGetReferenceAbleToGetCompositeEntitiesFromId(): void
{
$admin1Rome = $this->_em->getReference(Admin1::class, ['country' => 'IT', 'id' => 1]);
self::assertInstanceOf(CountryProxy::class, $admin1Rome->country);
self::assertEquals('Italy', $admin1Rome->country->name);
}

public function testGetReferenceAbleToGetCompositeEntitiesFromReference(): void
{
$countryRef = $this->_em->getReference(Country::class, 'IT');
$admin1Rome = $this->_em->getReference(Admin1::class, ['country' => $countryRef, 'id' => 1]);
self::assertInstanceOf(CountryProxy::class, $admin1Rome->country);
self::assertEquals('Italy', $admin1Rome->country->name);
}
}

0 comments on commit d29511b

Please sign in to comment.