Skip to content

Commit

Permalink
extract a common EntityManager::getCanonicalId() method for find() an…
Browse files Browse the repository at this point in the history
…d getReference()
  • Loading branch information
le-yak committed Oct 6, 2024
1 parent b7e1d0b commit 6ae5153
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 85 deletions.
154 changes: 69 additions & 85 deletions src/EntityManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -434,50 +434,9 @@ public function find($className, $id, $lockMode = null, $lockVersion = null)
$this->checkLockRequirements($lockMode, $class);
}

if (! is_array($id)) {
if ($class->isIdentifierComposite) {
throw ORMInvalidArgumentException::invalidCompositeIdentifier();
}
$canonicalId = $this->getCanonicalId($class, $id);

$id = [$class->identifier[0] => $id];
}

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);
}
}
}
}

$sortedId = [];

foreach ($class->identifier as $identifier) {
if (! isset($id[$identifier])) {
throw MissingIdentifierField::fromFieldAndClass($identifier, $class->name);
}

if ($id[$identifier] instanceof BackedEnum) {
$sortedId[$identifier] = $id[$identifier]->value;
} else {
$sortedId[$identifier] = $id[$identifier];
}

unset($id[$identifier]);
}

if ($id) {
throw UnrecognizedIdentifierFields::fromClassAndFieldNames($class->name, array_keys($id));
}

$unitOfWork = $this->getUnitOfWork();

$entity = $unitOfWork->tryGetById($sortedId, $class->rootEntityName);
$entity = $this->unitOfWork->tryGetById($canonicalId, $class->rootEntityName);

// Check identity map first
if ($entity !== false) {
Expand All @@ -493,32 +452,32 @@ public function find($className, $id, $lockMode = null, $lockVersion = null)
case $lockMode === LockMode::NONE:
case $lockMode === LockMode::PESSIMISTIC_READ:
case $lockMode === LockMode::PESSIMISTIC_WRITE:
$persister = $unitOfWork->getEntityPersister($class->name);
$persister->refresh($sortedId, $entity, $lockMode);
$persister = $this->unitOfWork->getEntityPersister($class->name);
$persister->refresh($canonicalId, $entity, $lockMode);
break;
}

return $entity; // Hit!
}

$persister = $unitOfWork->getEntityPersister($class->name);
$persister = $this->unitOfWork->getEntityPersister($class->name);

switch (true) {
case $lockMode === LockMode::OPTIMISTIC:
$entity = $persister->load($sortedId);
$entity = $persister->load($canonicalId);

if ($entity !== null) {
$unitOfWork->lock($entity, $lockMode, $lockVersion);
$this->unitOfWork->lock($entity, $lockMode, $lockVersion);
}

return $entity;

case $lockMode === LockMode::PESSIMISTIC_READ:
case $lockMode === LockMode::PESSIMISTIC_WRITE:
return $persister->load($sortedId, null, null, [], $lockMode);
return $persister->load($canonicalId, null, null, [], $lockMode);

Check failure on line 477 in src/EntityManager.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm

InvalidReturnStatement

src/EntityManager.php:477:24: InvalidReturnStatement: The inferred type 'null|object' does not match the declared return type '(T:fn-doctrine\orm\entitymanager::find as object)|null' for Doctrine\ORM\EntityManager::find (see https://psalm.dev/128)

default:
return $persister->loadById($sortedId);
return $persister->loadById($canonicalId);

Check failure on line 480 in src/EntityManager.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm

InvalidReturnStatement

src/EntityManager.php:480:24: InvalidReturnStatement: The inferred type 'null|object' does not match the declared return type '(T:fn-doctrine\orm\entitymanager::find as object)|null' for Doctrine\ORM\EntityManager::find (see https://psalm.dev/128)
}
}

Expand All @@ -529,52 +488,22 @@ public function getReference($entityName, $id)
{
$class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));

if (! is_array($id)) {
$id = [$class->identifier[0] => $id];
}

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);
}
}
}
}
$canonicalId = $this->getCanonicalId($class, $id);

$sortedId = [];

foreach ($class->identifier as $identifier) {
if (! isset($id[$identifier])) {
throw MissingIdentifierField::fromFieldAndClass($identifier, $class->name);
}

$sortedId[$identifier] = $id[$identifier];
unset($id[$identifier]);
}

if ($id) {
throw UnrecognizedIdentifierFields::fromClassAndFieldNames($class->name, array_keys($id));
}

$entity = $this->unitOfWork->tryGetById($sortedId, $class->rootEntityName);
$entity = $this->unitOfWork->tryGetById($canonicalId, $class->rootEntityName);

// Check identity map first, if its already in there just return it.
if ($entity !== false) {
return $entity instanceof $class->name ? $entity : null;
}

if ($class->subClasses) {
return $this->find($entityName, $sortedId);
return $this->find($entityName, $canonicalId);
}

$entity = $this->proxyFactory->getProxy($class->name, $sortedId);
$entity = $this->proxyFactory->getProxy($class->name, $canonicalId);

$this->unitOfWork->registerManaged($entity, $sortedId, []);
$this->unitOfWork->registerManaged($entity, $canonicalId, []);

return $entity;
}
Expand Down Expand Up @@ -1130,4 +1059,59 @@ private function configureLegacyMetadataCache(): void
// Wrap doctrine/cache to provide PSR-6 interface
$this->metadataFactory->setCache(CacheAdapter::wrap($metadataCache));
}

/**
* @param mixed $id The identitifiers to sort.
*
* @return mixed The sorted identifiers.
*
* @throws ORMInvalidArgumentException
* @throws MissingIdentifierField
* @throws UnrecognizedIdentifierFields
*/
private function getCanonicalId(ClassMetadata $class, $id): mixed
{
if (! is_array($id)) {
if ($class->isIdentifierComposite) {
throw ORMInvalidArgumentException::invalidCompositeIdentifier();
}

$id = [$class->identifier[0] => $id];
}

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);
}
}
}
}

$canonicalId = [];

foreach ($class->identifier as $identifier) {
if (! isset($id[$identifier])) {
throw MissingIdentifierField::fromFieldAndClass($identifier, $class->name);
}

if ($id[$identifier] instanceof BackedEnum) {
$canonicalId[$identifier] = $id[$identifier]->value;
} else {
$canonicalId[$identifier] = $id[$identifier];
}

unset($id[$identifier]);
}

if ($id) {
throw UnrecognizedIdentifierFields::fromClassAndFieldNames($class->name, array_keys($id));
}

return $canonicalId;
}
}
3 changes: 3 additions & 0 deletions tests/Tests/ORM/Functional/GetReferenceOnRelationAsIdTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
use Doctrine\Tests\Proxies\__CG__\Doctrine\Tests\Models\RelationAsId\Membership as MembershipProxy;
use Doctrine\Tests\Proxies\__CG__\Doctrine\Tests\Models\RelationAsId\User as UserProxy;

/**
* @group pkfk
*/
class GetReferenceOnRelationAsIdTest extends OrmFunctionalTestCase
{
protected function setUp(): void
Expand Down

0 comments on commit 6ae5153

Please sign in to comment.