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 Nov 20, 2021
1 parent 203cd6e commit 53434ca
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 13 deletions.
4 changes: 4 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ Because of that, functionality that aims to do so has been deprecated:
* `Configuration::ensureProductionSettings()`
* the `orm:ensure-production-settings` console command

## 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.10

## BC Break: Removed `TABLE` id generator strategy
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 @@ -13,6 +13,7 @@
use Doctrine\DBAL\LockMode;
use Doctrine\Deprecations\Deprecation;
use Doctrine\ORM\Exception\EntityManagerClosed;
use Doctrine\ORM\Exception\InstanceOfTheWrongTypeEncountered;
use Doctrine\ORM\Exception\InvalidHydrationMode;
use Doctrine\ORM\Exception\MismatchedEventManager;
use Doctrine\ORM\Exception\MissingIdentifierField;
Expand Down Expand Up @@ -529,7 +530,11 @@ public function getReference($entityName, $id)

// 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 @@ -554,7 +559,11 @@ public function getPartialReference($entityName, $identifier)

// 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
8 changes: 4 additions & 4 deletions lib/Doctrine/ORM/EntityManagerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ public function createQueryBuilder();
* @param mixed $id The entity identifier.
* @psalm-param class-string<T> $entityName
*
* @return object|null The entity reference.
* @psalm-return T|null
* @return object The entity reference.
* @psalm-return T
*
* @throws ORMException
*
Expand All @@ -201,8 +201,8 @@ public function getReference($entityName, $id);
* @param mixed $identifier The entity identifier.
* @psalm-param class-string<T> $entityName
*
* @return object|null The (partial) entity reference
* @psalm-return T|null
* @return object The (partial) entity reference
* @psalm-return T
*
* @template T
*/
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_class;

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_class($instance) . ') was retrieved in inheritance hierachy.' .
'This happens because identity map aggregates instances by rootEntityName ');
}
}
4 changes: 2 additions & 2 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,12 @@ parameters:
path: lib/Doctrine/ORM/EntityManager.php

-
message: "#^Method Doctrine\\\\ORM\\\\EntityManager\\:\\:getReference\\(\\) should return T\\|null but returns Doctrine\\\\Common\\\\Proxy\\\\Proxy\\.$#"
message: "#^Method Doctrine\\\\ORM\\\\EntityManager\\:\\:getReference\\(\\) should return T but returns Doctrine\\\\Common\\\\Proxy\\\\Proxy\\.$#"
count: 1
path: lib/Doctrine/ORM/EntityManager.php

-
message: "#^Method Doctrine\\\\ORM\\\\EntityManager\\:\\:getReference\\(\\) should return T\\|null but returns object\\|null\\.$#"
message: "#^Method Doctrine\\\\ORM\\\\EntityManager\\:\\:getReference\\(\\) should return T but returns object\\.$#"
count: 1
path: lib/Doctrine/ORM/EntityManager.php

Expand Down
4 changes: 2 additions & 2 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -460,8 +460,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-&gt;getMetadataFor($className)</code>
Expand Down
11 changes: 8 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;
use Doctrine\Tests\OrmFunctionalTestCase;

Expand All @@ -18,7 +19,7 @@ protected function setUp(): void
parent::setUp();
}

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

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

$this->expectException(InstanceOfTheWrongTypeEncountered::class);
$this->_em->getReference(Models\Company\CompanyFlexContract::class, $id);

$this->expectException(InstanceOfTheWrongTypeEncountered::class);
$this->_em->getPartialReference(Models\Company\CompanyFlexContract::class, $id);
}
}

0 comments on commit 53434ca

Please sign in to comment.