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

Skip to content

Commit 3df05e0

Browse files
committed
feature #30962 [DoctrineBridge] Deprecated implicit optimization in DoctrineChoiceLoader (HeahDude)
This PR was merged into the 4.3-dev branch. Discussion ---------- [DoctrineBridge] Deprecated implicit optimization in DoctrineChoiceLoader | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | no <!-- don't forget to update src/**/CHANGELOG.md files --> | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? | yes <!-- don't forget to update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | ~ | License | MIT | Doc PR | ~ #EUFOSSA Big thanks to @stof for the help with writing the test! ## Description It happens that the `IdReader` is created by the `DoctrineType` and cached for each entity class case. But the type already resolves whether or not it should use it, only when we can optimize query thanks to a single id field when defining the `choice_value` option: https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php#L188. This PR is a first step to optimize the choice loading process. Commits ------- 287c39b [DoctrineBridge] Deprecated implicit optimization in DoctrineChoiceLoader
2 parents 4447f87 + 287c39b commit 3df05e0

File tree

4 files changed

+92
-3
lines changed

4 files changed

+92
-3
lines changed

src/Symfony/Bridge/Doctrine/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
-----
66

77
* changed guessing of DECIMAL to set the `input` option of `NumberType` to string
8+
* deprecated not passing an `IdReader` to the `DoctrineChoiceLoader` when query can be optimized with a single id field
89

910
4.2.0
1011
-----

src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,19 @@ public function __construct(ObjectManager $manager, string $class, IdReader $idR
4949
{
5050
$classMetadata = $manager->getClassMetadata($class);
5151

52+
if ((5 > \func_num_args() || false !== func_get_arg(4)) && null === $idReader) {
53+
$idReader = new IdReader($manager, $classMetadata);
54+
55+
if ($idReader->isSingleId()) {
56+
@trigger_error(sprintf('Not explicitly passing an instance of "%s" when it can optimize single id entity "%s" has been deprecated in 4.3 and will not apply any optimization in 5.0.', IdReader::class, $class), E_USER_DEPRECATED);
57+
} else {
58+
$idReader = null;
59+
}
60+
}
61+
5262
$this->manager = $manager;
5363
$this->class = $classMetadata->getName();
54-
$this->idReader = $idReader ?: new IdReader($manager, $classMetadata);
64+
$this->idReader = $idReader;
5565
$this->objectLoader = $objectLoader;
5666
}
5767

@@ -120,7 +130,7 @@ public function loadChoicesForValues(array $values, $value = null)
120130

121131
// Optimize performance in case we have an object loader and
122132
// a single-field identifier
123-
$optimize = null === $value || \is_array($value) && $this->idReader === $value[0];
133+
$optimize = $this->idReader && (null === $value || \is_array($value) && $this->idReader === $value[0]);
124134

125135
if ($optimize && !$this->choiceList && $this->objectLoader && $this->idReader->isSingleId()) {
126136
$unorderedObjects = $this->objectLoader->getEntitiesByIds($this->idReader->getIdField(), $values);

src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@ public function configureOptions(OptionsResolver $resolver)
150150
$options['em'],
151151
$options['class'],
152152
$options['id_reader'],
153-
$entityLoader
153+
$entityLoader,
154+
false
154155
);
155156

156157
if (null !== $hash) {

src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader;
1919
use Symfony\Bridge\Doctrine\Form\ChoiceList\EntityLoaderInterface;
2020
use Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader;
21+
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity;
2122
use Symfony\Component\Form\ChoiceList\ArrayChoiceList;
2223
use Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface;
2324

@@ -393,4 +394,80 @@ public function testLoadChoicesForValuesLoadsOnlyChoicesIfValueIsIdReader()
393394

394395
$this->assertSame([$this->obj2], $loader->loadChoicesForValues(['2'], $value));
395396
}
397+
398+
/**
399+
* @group legacy
400+
*
401+
* @expectedDeprecation Not explicitly passing an instance of "Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader" when it can optimize single id entity "%s" has been deprecated in 4.3 and will not apply any optimization in 5.0.
402+
*/
403+
public function testLoaderWithoutIdReaderCanBeOptimized()
404+
{
405+
$obj1 = new SingleIntIdEntity('1', 'one');
406+
$obj2 = new SingleIntIdEntity('2', 'two');
407+
408+
$metadata = $this->createMock(ClassMetadata::class);
409+
$metadata->expects($this->once())
410+
->method('getIdentifierFieldNames')
411+
->willReturn(['idField'])
412+
;
413+
$metadata->expects($this->any())
414+
->method('getIdentifierValues')
415+
->willReturnCallback(function ($obj) use ($obj1, $obj2) {
416+
if ($obj === $obj1) {
417+
return ['idField' => '1'];
418+
}
419+
if ($obj === $obj2) {
420+
return ['idField' => '2'];
421+
}
422+
423+
return null;
424+
})
425+
;
426+
427+
$this->om = $this->createMock(ObjectManager::class);
428+
$this->om->expects($this->once())
429+
->method('getClassMetadata')
430+
->with(SingleIntIdEntity::class)
431+
->willReturn($metadata)
432+
;
433+
$this->om->expects($this->any())
434+
->method('contains')
435+
->with($this->isInstanceOf(SingleIntIdEntity::class))
436+
->willReturn(true)
437+
;
438+
439+
$loader = new DoctrineChoiceLoader(
440+
$this->om,
441+
SingleIntIdEntity::class,
442+
null,
443+
$this->objectLoader
444+
);
445+
446+
$choices = [$obj1, $obj2];
447+
448+
$this->idReader->expects($this->any())
449+
->method('isSingleId')
450+
->willReturn(true);
451+
452+
$this->idReader->expects($this->any())
453+
->method('getIdField')
454+
->willReturn('idField');
455+
456+
$this->repository->expects($this->never())
457+
->method('findAll');
458+
459+
$this->objectLoader->expects($this->once())
460+
->method('getEntitiesByIds')
461+
->with('idField', ['1'])
462+
->willReturn($choices);
463+
464+
$this->idReader->expects($this->any())
465+
->method('getIdValue')
466+
->willReturnMap([
467+
[$obj1, '1'],
468+
[$obj2, '2'],
469+
]);
470+
471+
$this->assertSame([$obj1], $loader->loadChoicesForValues(['1']));
472+
}
396473
}

0 commit comments

Comments
 (0)