Skip to content

Commit

Permalink
Avoid returning null from EntityManager::getReference() and `getPar…
Browse files Browse the repository at this point in the history
…tialReference()`
  • Loading branch information
simPod committed Mar 17, 2023
1 parent 8efcaf9 commit 0c89228
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 9 deletions.
4 changes: 4 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,10 @@ following classes and methods:

Use `toIterable()` instead.

## BC BREAK: `Doctrine\ORM\EntityManagerInterface#getReference()` and `getPartialReference()` does not return `null` anymore

Method `Doctrine\ORM\EntityManagerInterface#getReference()` and `getPartialReference()` throws `InstanceOfTheWrongTypeEncountered` in 3.0 when different entity type is found in inheritance hierachy.

# Upgrade to 2.14

## Deprecated annotation mapping driver.
Expand Down
13 changes: 11 additions & 2 deletions lib/Doctrine/ORM/EntityManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Doctrine\DBAL\Exception as DBALException;
use Doctrine\DBAL\LockMode;
use Doctrine\ORM\Exception\EntityManagerClosed;
use Doctrine\ORM\Exception\InstanceOfTheWrongTypeEncountered;
use Doctrine\ORM\Exception\InvalidHydrationMode;
use Doctrine\ORM\Exception\ManagerException;
use Doctrine\ORM\Exception\MismatchedEventManager;
Expand Down Expand Up @@ -402,7 +403,11 @@ public function getReference(string $entityName, $id): object|null

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

return $entity;
}

if ($class->subClasses) {
Expand All @@ -427,7 +432,11 @@ public function getPartialReference(string $entityName, $identifier): object|nul

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

return $entity;
}

if (! is_array($identifier)) {
Expand Down
4 changes: 2 additions & 2 deletions lib/Doctrine/ORM/EntityManagerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public function find(string $className, mixed $id, LockMode|int|null $lockMode =
* @param mixed $id The entity identifier.
* @psalm-param class-string<T> $entityName
*
* @psalm-return T|null
* @psalm-return T
*
* @throws ORMException
*
Expand All @@ -167,7 +167,7 @@ public function getReference(string $entityName, $id): object|null;
* @param mixed $identifier The entity identifier.
* @psalm-param class-string<T> $entityName
*
* @psalm-return T|null
* @psalm-return T
*
* @template T of object
*/
Expand Down
19 changes: 19 additions & 0 deletions lib/Doctrine/ORM/Exception/InstanceOfTheWrongTypeEncountered.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Exception;

use LogicException;

use function get_debug_type;

final class InstanceOfTheWrongTypeEncountered extends LogicException implements ORMException
{
/** @param object $instance */
public static function forInstance($instance): self
{
return new self('Instance of the wrong type (' . get_debug_type($instance) . ') was retrieved in inheritance hierachy.' .
'This happens because identity map aggregates instances by rootEntityName ');
}
}
4 changes: 2 additions & 2 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@
<code>$entity</code>
<code>$entity</code>
<code>$entity</code>
<code>$entity instanceof $class-&gt;name ? $entity : null</code>
<code>$entity instanceof $class-&gt;name ? $entity : null</code>
<code>$entity</code>
<code>$entity</code>
<code>$persister-&gt;load($sortedId, null, null, [], $lockMode)</code>
<code>$persister-&gt;loadById($sortedId)</code>
<code>$this-&gt;metadataFactory</code>
Expand Down
15 changes: 12 additions & 3 deletions tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1041Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Doctrine\Tests\ORM\Functional\Ticket;

use Doctrine\ORM\Exception\InstanceOfTheWrongTypeEncountered;
use Doctrine\Tests\Models\Company\CompanyFixContract;
use Doctrine\Tests\Models\Company\CompanyFlexContract;
use Doctrine\Tests\OrmFunctionalTestCase;
Expand All @@ -17,7 +18,7 @@ protected function setUp(): void
parent::setUp();
}

public function testGrabWrongSubtypeReturnsNull(): void
public function testGrabWrongSubtypeReturnsNullOrThrows(): void
{
$fix = new CompanyFixContract();
$fix->setFixPrice(2000);
Expand All @@ -28,7 +29,15 @@ public function testGrabWrongSubtypeReturnsNull(): void
$id = $fix->getId();

self::assertNull($this->_em->find(CompanyFlexContract::class, $id));
self::assertNull($this->_em->getReference(CompanyFlexContract::class, $id));
self::assertNull($this->_em->getPartialReference(CompanyFlexContract::class, $id));

try {
$this->_em->getReference(CompanyFlexContract::class, $id);
} catch (InstanceOfTheWrongTypeEncountered) {
}

try {
$this->_em->getPartialReference(CompanyFlexContract::class, $id);
} catch (InstanceOfTheWrongTypeEncountered) {
}
}
}

0 comments on commit 0c89228

Please sign in to comment.