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 Aug 16, 2021
1 parent a0b739c commit 92b5ac0
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 12 deletions.
4 changes: 4 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ Signatures of overridden methods should be changed accordingly

Method `Doctrine\ORM\EntityManagerInterface#copy()` never got its implementation and is removed in 3.0.

## 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 possibility to extend the doctrine mapping xml schema with anything
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 @@ -14,6 +14,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 @@ -528,7 +529,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 @@ -553,7 +558,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
6 changes: 3 additions & 3 deletions lib/Doctrine/ORM/EntityManagerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,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
* @return object The entity reference.
* @psalm-return T
*
* @throws ORMException
*
Expand All @@ -197,7 +197,7 @@ public function getReference($entityName, $id);
* @param string $entityName The name of the entity type.
* @param mixed $identifier The entity identifier.
*
* @return object|null The (partial) entity reference.
* @return object The (partial) entity reference.
*/
public function getPartialReference($entityName, $identifier);

Expand Down
17 changes: 17 additions & 0 deletions lib/Doctrine/ORM/Exception/InstanceOfTheWrongTypeEncountered.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Exception;

use function get_class;

final class InstanceOfTheWrongTypeEncountered extends 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 @@ -156,12 +156,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 @@ -481,13 +481,13 @@
<code>$entity</code>
<code>$entity</code>
<code>$entity</code>
<code>$entity instanceof $class-&gt;name ? $entity : null</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>
</InvalidReturnStatement>
<InvalidReturnType occurrences="3">
<code>?T</code>
<code>T</code>
<code>getClassMetadata</code>
<code>getReference</code>
</InvalidReturnType>
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 92b5ac0

Please sign in to comment.