Skip to content

Commit d15624f

Browse files
authored
[GH-11185] Bugfix: do not use collection batch loading for indexBy assocations. (#11380)
1 parent 9d1a497 commit d15624f

File tree

5 files changed

+161
-1
lines changed

5 files changed

+161
-1
lines changed

src/UnitOfWork.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3166,7 +3166,7 @@ public function createEntity($className, array $data, &$hints = [])
31663166

31673167
if ($hints['fetchMode'][$class->name][$field] === ClassMetadata::FETCH_EAGER) {
31683168
$isIteration = isset($hints[Query::HINT_INTERNAL_ITERATION]) && $hints[Query::HINT_INTERNAL_ITERATION];
3169-
if ($assoc['type'] === ClassMetadata::ONE_TO_MANY && ! $isIteration && ! $targetClass->isIdentifierComposite) {
3169+
if ($assoc['type'] === ClassMetadata::ONE_TO_MANY && ! $isIteration && ! $targetClass->isIdentifierComposite && ! isset($assoc['indexBy'])) {
31703170
$this->scheduleCollectionForBatchLoading($pColl, $class);
31713171
} else {
31723172
$this->loadCollection($pColl);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\ORM\Functional\Ticket\GH11149;
6+
7+
use Doctrine\Common\Collections\ArrayCollection;
8+
use Doctrine\ORM\Mapping as ORM;
9+
10+
/**
11+
* @ORM\Entity
12+
* @ORM\Table("gh11149_eager_product")
13+
*/
14+
class EagerProduct
15+
{
16+
/**
17+
* @ORM\Id
18+
* @ORM\Column(type="integer")
19+
*
20+
* @var int
21+
*/
22+
public $id;
23+
24+
/**
25+
* @ORM\OneToMany(
26+
* targetEntity=EagerProductTranslation::class,
27+
* mappedBy="product",
28+
* fetch="EAGER",
29+
* indexBy="locale_code"
30+
* )
31+
*
32+
* @var Collection<string, EagerProductTranslation>
33+
*/
34+
public $translations;
35+
36+
public function __construct(int $id)
37+
{
38+
$this->id = $id;
39+
$this->translations = new ArrayCollection();
40+
}
41+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\ORM\Functional\Ticket\GH11149;
6+
7+
use Doctrine\ORM\Mapping as ORM;
8+
9+
/**
10+
* @ORM\Entity
11+
* @ORM\Table("gh11149_eager_product_translation")
12+
*/
13+
class EagerProductTranslation
14+
{
15+
/**
16+
* @ORM\Id
17+
* @ORM\Column(type="integer")
18+
*
19+
* @var int
20+
*/
21+
private $id;
22+
23+
/**
24+
* @ORM\ManyToOne(targetEntity=EagerProduct::class, inversedBy="translations")
25+
* @ORM\JoinColumn(nullable=false)
26+
*
27+
* @var EagerProduct
28+
*/
29+
public $product;
30+
31+
/**
32+
* @ORM\ManyToOne(targetEntity=Locale::class)
33+
* @ORM\JoinColumn(name="locale_code", referencedColumnName="code", nullable=false)
34+
*
35+
* @var Locale
36+
*/
37+
public $locale;
38+
39+
public function __construct($id, EagerProduct $product, Locale $locale)
40+
{
41+
$this->id = $id;
42+
$this->product = $product;
43+
$this->locale = $locale;
44+
}
45+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\ORM\Functional\Ticket\GH11149;
6+
7+
use Doctrine\ORM\PersistentCollection;
8+
use Doctrine\Persistence\Proxy;
9+
use Doctrine\Tests\OrmFunctionalTestCase;
10+
11+
class GH11149Test extends OrmFunctionalTestCase
12+
{
13+
protected function setUp(): void
14+
{
15+
parent::setUp();
16+
17+
$this->setUpEntitySchema([
18+
Locale::class,
19+
EagerProduct::class,
20+
EagerProductTranslation::class,
21+
]);
22+
}
23+
24+
public function testFetchEagerModeWithIndexBy(): void
25+
{
26+
// Load entities into database
27+
$this->_em->persist($product = new EagerProduct(11149));
28+
$this->_em->persist($locale = new Locale('fr_FR'));
29+
$this->_em->persist(new EagerProductTranslation(11149, $product, $locale));
30+
$this->_em->flush();
31+
$this->_em->clear();
32+
33+
// Fetch entity from database
34+
$product = $this->_em->find(EagerProduct::class, 11149);
35+
36+
// Assert associated entity is loaded eagerly
37+
static::assertInstanceOf(EagerProduct::class, $product);
38+
static::assertInstanceOf(PersistentCollection::class, $product->translations);
39+
static::assertTrue($product->translations->isInitialized());
40+
static::assertCount(1, $product->translations);
41+
42+
// Assert associated entity is indexed by given property
43+
$translation = $product->translations->get('fr_FR');
44+
static::assertInstanceOf(EagerProductTranslation::class, $translation);
45+
static::assertNotInstanceOf(Proxy::class, $translation);
46+
}
47+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\ORM\Functional\Ticket\GH11149;
6+
7+
use Doctrine\ORM\Mapping as ORM;
8+
9+
/**
10+
* @ORM\Entity
11+
* @ORM\Table("gh11149_locale")
12+
*/
13+
class Locale
14+
{
15+
/**
16+
* @ORM\Id
17+
* @ORM\Column(type="string")
18+
*
19+
* @var string
20+
*/
21+
public $code;
22+
23+
public function __construct(string $code)
24+
{
25+
$this->code = $code;
26+
}
27+
}

0 commit comments

Comments
 (0)