Skip to content

Commit

Permalink
Findby joined lookup (#8285)
Browse files Browse the repository at this point in the history
* [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]>
  • Loading branch information
2 people authored and greg0ire committed Dec 1, 2021
1 parent 15ec77f commit 2c7d7eb
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 18 deletions.
42 changes: 24 additions & 18 deletions lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -1933,36 +1933,42 @@ private function getValues($value): array
return [$newValue];
}

if (is_object($value) && $this->em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value))) {
$class = $this->em->getClassMetadata(get_class($value));
if ($class->isIdentifierComposite) {
$newValue = [];

foreach ($class->getIdentifierValues($value) as $innerValue) {
$newValue = array_merge($newValue, $this->getValues($innerValue));
}

return $newValue;
}
}

return [$this->getIndividualValue($value)];
return $this->getIndividualValue($value);
}

/**
* Retrieves an individual parameter value.
*
* @param mixed $value
*
* @return mixed
* @return array<mixed>
* @psalm-return list<mixed>
*/
private function getIndividualValue($value)
{
if (! is_object($value) || ! $this->em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value))) {
return $value;
if (! is_object($value)) {
return [$value];
}

$valueClass = ClassUtils::getClass($value);

if ($this->em->getMetadataFactory()->isTransient($valueClass)) {
return [$value];
}

$class = $this->em->getClassMetadata($valueClass);

if ($class->isIdentifierComposite) {
$newValue = [];

foreach ($class->getIdentifierValues($value) as $innerValue) {
$newValue = array_merge($newValue, $this->getValues($innerValue));
}

return $newValue;
}

return $this->em->getUnitOfWork()->getSingleIdentifierValue($value);
return [$this->em->getUnitOfWork()->getSingleIdentifierValue($value)];
}

/**
Expand Down
97 changes: 97 additions & 0 deletions tests/Doctrine/Tests/ORM/Functional/Ticket/GH7512Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket;

use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\DiscriminatorMap;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\InheritanceType;
use Doctrine\ORM\Mapping\ManyToOne;
use Doctrine\ORM\Mapping\OneToMany;
use Doctrine\Tests\OrmFunctionalTestCase;

class GH7512Test extends OrmFunctionalTestCase
{
protected function setUp(): void
{
parent::setUp();

$this->setUpEntitySchema([
GH7512EntityA::class,
GH7512EntityB::class,
GH7512EntityC::class,
]);

$this->_em->persist(new GH7512EntityA());
$this->_em->persist(new GH7512EntityC());
$this->_em->flush();
$this->_em->clear();
}

public function testFindEntityByAssociationPropertyJoinedChildWithClearMetadata(): void
{
// unset metadata for entity B as though it hasn't been touched yet in application lifecycle.
$this->_em->getMetadataFactory()->setMetadataFor(GH7512EntityB::class, null);
$result = $this->_em->getRepository(GH7512EntityC::class)->findBy([
'entityA' => new GH7512EntityB(),
]);
$this->assertEmpty($result);
}
}

/**
* @Entity()
* @InheritanceType("JOINED")
* @DiscriminatorMap({
* "entitya"=Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityA::class,
* "entityB"=Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityB::class
* })
*/
class GH7512EntityA
{
/**
* @Column(type="integer")
* @Id()
* @GeneratedValue(strategy="AUTO")
* @var int
*/
public $id;

/**
* @OneToMany(targetEntity="Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityC", mappedBy="entityA")
* @var Collection<int, GH7512EntityC>
*/
public $entityCs;
}

/**
* @Entity()
*/
class GH7512EntityB extends GH7512EntityA
{
}

/**
* @Entity()
*/
class GH7512EntityC
{
/**
* @Column(type="integer")
* @Id()
* @GeneratedValue(strategy="AUTO")
* @var int
*/
public $id;

/**
* @ManyToOne(targetEntity="Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityA", inversedBy="entityCs")
* @var GH7512EntityA
*/
public $entityA;
}

0 comments on commit 2c7d7eb

Please sign in to comment.