Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6de4b68

Browse files
authored
Use a dedicated exception for the check added in #10785 (#10881)
This adds a dedicated exception for the case that objects with colliding identities are to be put into the identity map. Implements #10872.
1 parent 16c0151 commit 6de4b68

4 files changed

Lines changed: 59 additions & 37 deletions

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\ORM\Exception;
6+
7+
use function get_class;
8+
use function sprintf;
9+
10+
final class EntityIdentityCollisionException extends ORMException
11+
{
12+
/**
13+
* @param object $existingEntity
14+
* @param object $newEntity
15+
*/
16+
public static function create($existingEntity, $newEntity, string $idHash): self
17+
{
18+
return new self(
19+
sprintf(
20+
<<<'EXCEPTION'
21+
While adding an entity of class %s with an ID hash of "%s" to the identity map,
22+
another object of class %s was already present for the same ID. This exception
23+
is a safeguard against an internal inconsistency - IDs should uniquely map to
24+
entity object instances. This problem may occur if:
25+
26+
- you use application-provided IDs and reuse ID values;
27+
- database-provided IDs are reassigned after truncating the database without
28+
clearing the EntityManager;
29+
- you might have been using EntityManager#getReference() to create a reference
30+
for a nonexistent ID that was subsequently (by the RDBMS) assigned to another
31+
entity.
32+
33+
Otherwise, it might be an ORM-internal inconsistency, please report it.
34+
EXCEPTION
35+
,
36+
get_class($newEntity),
37+
$idHash,
38+
get_class($existingEntity)
39+
)
40+
);
41+
}
42+
}

lib/Doctrine/ORM/UnitOfWork.php

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use Doctrine\ORM\Event\PrePersistEventArgs;
2424
use Doctrine\ORM\Event\PreRemoveEventArgs;
2525
use Doctrine\ORM\Event\PreUpdateEventArgs;
26+
use Doctrine\ORM\Exception\EntityIdentityCollisionException;
2627
use Doctrine\ORM\Exception\ORMException;
2728
use Doctrine\ORM\Exception\UnexpectedAssociationValue;
2829
use Doctrine\ORM\Id\AssignedGenerator;
@@ -1624,6 +1625,7 @@ public function isEntityScheduled($entity)
16241625
* the entity in question is already managed.
16251626
*
16261627
* @throws ORMInvalidArgumentException
1628+
* @throws EntityIdentityCollisionException
16271629
*
16281630
* @ignore
16291631
*/
@@ -1636,34 +1638,13 @@ public function addToIdentityMap($entity)
16361638
if (isset($this->identityMap[$className][$idHash])) {
16371639
if ($this->identityMap[$className][$idHash] !== $entity) {
16381640
if ($this->em->getConfiguration()->isRejectIdCollisionInIdentityMapEnabled()) {
1639-
throw new RuntimeException(
1640-
sprintf(
1641-
<<<'EXCEPTION'
1642-
While adding an entity of class %s with an ID hash of "%s" to the identity map,
1643-
another object of class %s was already present for the same ID. This exception
1644-
is a safeguard against an internal inconsistency - IDs should uniquely map to
1645-
entity object instances. This problem may occur if:
1646-
1647-
- you use application-provided IDs and reuse ID values;
1648-
- database-provided IDs are reassigned after truncating the database without
1649-
clearing the EntityManager;
1650-
- you might have been using EntityManager#getReference() to create a reference
1651-
for a nonexistent ID that was subsequently (by the RDBMS) assigned to another
1652-
entity.
1641+
throw EntityIdentityCollisionException::create($this->identityMap[$className][$idHash], $entity, $idHash);
1642+
}
16531643

1654-
Otherwise, it might be an ORM-internal inconsistency, please report it.
1655-
EXCEPTION
1656-
,
1657-
get_class($entity),
1658-
$idHash,
1659-
get_class($this->identityMap[$className][$idHash])
1660-
)
1661-
);
1662-
} else {
1663-
Deprecation::trigger(
1664-
'doctrine/orm',
1665-
'https://github.com/doctrine/orm/pull/10785',
1666-
<<<'EXCEPTION'
1644+
Deprecation::trigger(
1645+
'doctrine/orm',
1646+
'https://github.com/doctrine/orm/pull/10785',
1647+
<<<'EXCEPTION'
16671648
While adding an entity of class %s with an ID hash of "%s" to the identity map,
16681649
another object of class %s was already present for the same ID. This will trigger
16691650
an exception in ORM 3.0.
@@ -1683,12 +1664,11 @@ public function addToIdentityMap($entity)
16831664
\Doctrine\ORM\Configuration::setRejectIdCollisionInIdentityMap on the entity
16841665
manager's configuration.
16851666
EXCEPTION
1686-
,
1687-
get_class($entity),
1688-
$idHash,
1689-
get_class($this->identityMap[$className][$idHash])
1690-
);
1691-
}
1667+
,
1668+
get_class($entity),
1669+
$idHash,
1670+
get_class($this->identityMap[$className][$idHash])
1671+
);
16921672
}
16931673

16941674
return false;

tests/Doctrine/Tests/ORM/Functional/BasicFunctionalTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Doctrine\Tests\ORM\Functional;
66

77
use Doctrine\ORM\EntityNotFoundException;
8+
use Doctrine\ORM\Exception\EntityIdentityCollisionException;
89
use Doctrine\ORM\Mapping\ClassMetadata;
910
use Doctrine\ORM\ORMInvalidArgumentException;
1011
use Doctrine\ORM\PersistentCollection;
@@ -20,7 +21,6 @@
2021
use Doctrine\Tests\Models\CMS\CmsUser;
2122
use Doctrine\Tests\OrmFunctionalTestCase;
2223
use InvalidArgumentException;
23-
use RuntimeException;
2424

2525
use function get_class;
2626

@@ -1347,7 +1347,7 @@ public function testItThrowsWhenReferenceUsesIdAssignedByDatabase(): void
13471347

13481348
// Now the database will assign an ID to the $user2 entity, but that place
13491349
// in the identity map is already taken by user error.
1350-
$this->expectException(RuntimeException::class);
1350+
$this->expectException(EntityIdentityCollisionException::class);
13511351
$this->expectExceptionMessageMatches('/another object .* was already present for the same ID/');
13521352

13531353
// depending on ID generation strategy, the ID may be asssigned already here

tests/Doctrine/Tests/ORM/UnitOfWorkTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Doctrine\Deprecations\PHPUnit\VerifyDeprecations;
1414
use Doctrine\ORM\EntityNotFoundException;
1515
use Doctrine\ORM\Events;
16+
use Doctrine\ORM\Exception\EntityIdentityCollisionException;
1617
use Doctrine\ORM\Mapping\ClassMetadata;
1718
use Doctrine\ORM\Mapping\Column;
1819
use Doctrine\ORM\Mapping\Entity;
@@ -41,7 +42,6 @@
4142
use Doctrine\Tests\OrmTestCase;
4243
use Doctrine\Tests\PHPUnitCompatibility\MockBuilderCompatibilityTools;
4344
use PHPUnit\Framework\MockObject\MockObject;
44-
use RuntimeException;
4545
use stdClass;
4646

4747
use function assert;
@@ -960,7 +960,7 @@ public function testItThrowsWhenApplicationProvidedIdsCollide(): void
960960
$phone2 = new CmsPhonenumber();
961961
$phone2->phonenumber = '1234';
962962

963-
$this->expectException(RuntimeException::class);
963+
$this->expectException(EntityIdentityCollisionException::class);
964964
$this->expectExceptionMessageMatches('/another object .* was already present for the same ID/');
965965

966966
$this->_unitOfWork->persist($phone2);

0 commit comments

Comments
 (0)