Skip to content

Commit 2c7d7eb

Browse files
beberleithemizzi
authored andcommitted
Findby joined lookup (#8285)
* [GH-7512] Bugfix: Load metadata on object-typed value in EntityPersisters * [GH-7512] Refactor double check for object/entity and flatten code. Co-authored-by: Joe Mizzi <[email protected]>
1 parent 15ec77f commit 2c7d7eb

File tree

2 files changed

+121
-18
lines changed

2 files changed

+121
-18
lines changed

lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1933,36 +1933,42 @@ private function getValues($value): array
19331933
return [$newValue];
19341934
}
19351935

1936-
if (is_object($value) && $this->em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value))) {
1937-
$class = $this->em->getClassMetadata(get_class($value));
1938-
if ($class->isIdentifierComposite) {
1939-
$newValue = [];
1940-
1941-
foreach ($class->getIdentifierValues($value) as $innerValue) {
1942-
$newValue = array_merge($newValue, $this->getValues($innerValue));
1943-
}
1944-
1945-
return $newValue;
1946-
}
1947-
}
1948-
1949-
return [$this->getIndividualValue($value)];
1936+
return $this->getIndividualValue($value);
19501937
}
19511938

19521939
/**
19531940
* Retrieves an individual parameter value.
19541941
*
19551942
* @param mixed $value
19561943
*
1957-
* @return mixed
1944+
* @return array<mixed>
1945+
* @psalm-return list<mixed>
19581946
*/
19591947
private function getIndividualValue($value)
19601948
{
1961-
if (! is_object($value) || ! $this->em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value))) {
1962-
return $value;
1949+
if (! is_object($value)) {
1950+
return [$value];
1951+
}
1952+
1953+
$valueClass = ClassUtils::getClass($value);
1954+
1955+
if ($this->em->getMetadataFactory()->isTransient($valueClass)) {
1956+
return [$value];
1957+
}
1958+
1959+
$class = $this->em->getClassMetadata($valueClass);
1960+
1961+
if ($class->isIdentifierComposite) {
1962+
$newValue = [];
1963+
1964+
foreach ($class->getIdentifierValues($value) as $innerValue) {
1965+
$newValue = array_merge($newValue, $this->getValues($innerValue));
1966+
}
1967+
1968+
return $newValue;
19631969
}
19641970

1965-
return $this->em->getUnitOfWork()->getSingleIdentifierValue($value);
1971+
return [$this->em->getUnitOfWork()->getSingleIdentifierValue($value)];
19661972
}
19671973

19681974
/**
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\ORM\Functional\Ticket;
6+
7+
use Doctrine\Common\Collections\Collection;
8+
use Doctrine\ORM\Mapping\Column;
9+
use Doctrine\ORM\Mapping\DiscriminatorMap;
10+
use Doctrine\ORM\Mapping\Entity;
11+
use Doctrine\ORM\Mapping\GeneratedValue;
12+
use Doctrine\ORM\Mapping\Id;
13+
use Doctrine\ORM\Mapping\InheritanceType;
14+
use Doctrine\ORM\Mapping\ManyToOne;
15+
use Doctrine\ORM\Mapping\OneToMany;
16+
use Doctrine\Tests\OrmFunctionalTestCase;
17+
18+
class GH7512Test extends OrmFunctionalTestCase
19+
{
20+
protected function setUp(): void
21+
{
22+
parent::setUp();
23+
24+
$this->setUpEntitySchema([
25+
GH7512EntityA::class,
26+
GH7512EntityB::class,
27+
GH7512EntityC::class,
28+
]);
29+
30+
$this->_em->persist(new GH7512EntityA());
31+
$this->_em->persist(new GH7512EntityC());
32+
$this->_em->flush();
33+
$this->_em->clear();
34+
}
35+
36+
public function testFindEntityByAssociationPropertyJoinedChildWithClearMetadata(): void
37+
{
38+
// unset metadata for entity B as though it hasn't been touched yet in application lifecycle.
39+
$this->_em->getMetadataFactory()->setMetadataFor(GH7512EntityB::class, null);
40+
$result = $this->_em->getRepository(GH7512EntityC::class)->findBy([
41+
'entityA' => new GH7512EntityB(),
42+
]);
43+
$this->assertEmpty($result);
44+
}
45+
}
46+
47+
/**
48+
* @Entity()
49+
* @InheritanceType("JOINED")
50+
* @DiscriminatorMap({
51+
* "entitya"=Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityA::class,
52+
* "entityB"=Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityB::class
53+
* })
54+
*/
55+
class GH7512EntityA
56+
{
57+
/**
58+
* @Column(type="integer")
59+
* @Id()
60+
* @GeneratedValue(strategy="AUTO")
61+
* @var int
62+
*/
63+
public $id;
64+
65+
/**
66+
* @OneToMany(targetEntity="Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityC", mappedBy="entityA")
67+
* @var Collection<int, GH7512EntityC>
68+
*/
69+
public $entityCs;
70+
}
71+
72+
/**
73+
* @Entity()
74+
*/
75+
class GH7512EntityB extends GH7512EntityA
76+
{
77+
}
78+
79+
/**
80+
* @Entity()
81+
*/
82+
class GH7512EntityC
83+
{
84+
/**
85+
* @Column(type="integer")
86+
* @Id()
87+
* @GeneratedValue(strategy="AUTO")
88+
* @var int
89+
*/
90+
public $id;
91+
92+
/**
93+
* @ManyToOne(targetEntity="Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityA", inversedBy="entityCs")
94+
* @var GH7512EntityA
95+
*/
96+
public $entityA;
97+
}

0 commit comments

Comments
 (0)