diff --git a/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php b/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php index ab4c103e849dd..2cd0a3192a250 100644 --- a/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php +++ b/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php @@ -38,6 +38,11 @@ class LazyChoiceList implements ChoiceListInterface */ private $value; + /** + * @var ChoiceListInterface|null + */ + private $loadedList; + /** * Creates a lazily-loaded list using the given loader. * @@ -58,7 +63,11 @@ public function __construct(ChoiceLoaderInterface $loader, callable $value = nul */ public function getChoices() { - return $this->loader->loadChoiceList($this->value)->getChoices(); + if (null === $this->loadedList) { + $this->loadedList = $this->loader->loadChoiceList($this->value); + } + + return $this->loadedList->getChoices(); } /** @@ -66,7 +75,11 @@ public function getChoices() */ public function getValues() { - return $this->loader->loadChoiceList($this->value)->getValues(); + if (null === $this->loadedList) { + $this->loadedList = $this->loader->loadChoiceList($this->value); + } + + return $this->loadedList->getValues(); } /** @@ -74,6 +87,10 @@ public function getValues() */ public function getStructuredValues() { + if (null !== $this->loadedList) { + return $this->loadedList->getStructuredValues(); + } + return $this->loader->loadChoiceList($this->value)->getStructuredValues(); } @@ -82,6 +99,10 @@ public function getStructuredValues() */ public function getOriginalKeys() { + if (null !== $this->loadedList) { + return $this->loadedList->getOriginalKeys(); + } + return $this->loader->loadChoiceList($this->value)->getOriginalKeys(); } @@ -90,6 +111,10 @@ public function getOriginalKeys() */ public function getChoicesForValues(array $values) { + if (null !== $this->loadedList) { + return $this->loadedList->getChoicesForValues($values); + } + return $this->loader->loadChoicesForValues($values, $this->value); } @@ -98,6 +123,10 @@ public function getChoicesForValues(array $values) */ public function getValuesForChoices(array $choices) { + if (null !== $this->loadedList) { + return $this->loadedList->getValuesForChoices($choices); + } + return $this->loader->loadValuesForChoices($choices, $this->value); } } diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/LazyChoiceListTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/LazyChoiceListTest.php index 6f30d0896e1ba..c8f6d81b52bb4 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/LazyChoiceListTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/LazyChoiceListTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Form\Tests\ChoiceList; use PHPUnit\Framework\TestCase; +use Symfony\Component\Form\ChoiceList\ChoiceListInterface; use Symfony\Component\Form\ChoiceList\LazyChoiceList; use Symfony\Component\Form\Tests\Fixtures\ArrayChoiceLoader; @@ -23,82 +24,67 @@ class LazyChoiceListTest extends TestCase public function testGetChoiceLoadersLoadsLoadedListOnFirstCall() { $choices = ['RESULT']; - $calls = 0; - $list = new LazyChoiceList(new ArrayChoiceLoader($choices), function ($choice) use ($choices, &$calls) { - ++$calls; - + $list = new LazyChoiceList($choiceLoader = new UsageTrackingChoiceLoader($choices), function ($choice) use ($choices) { return array_search($choice, $choices); }); $this->assertSame(['RESULT'], $list->getChoices()); $this->assertSame(['RESULT'], $list->getChoices()); - $this->assertSame(1, $calls); + $this->assertSame(1, $choiceLoader->loadChoiceListCalls); } public function testGetValuesLoadsLoadedListOnFirstCall() { - $calls = 0; - $list = new LazyChoiceList(new ArrayChoiceLoader(['RESULT']), function ($choice) use (&$calls) { - ++$calls; - + $list = new LazyChoiceList($choiceLoader = new UsageTrackingChoiceLoader(['RESULT']), function ($choice) { return $choice; }); $this->assertSame(['RESULT'], $list->getValues()); $this->assertSame(['RESULT'], $list->getValues()); - $this->assertSame(1, $calls); + $this->assertSame(1, $choiceLoader->loadChoiceListCalls); } public function testGetStructuredValuesLoadsLoadedListOnFirstCall() { - $calls = 0; - $list = new LazyChoiceList(new ArrayChoiceLoader(['RESULT']), function ($choice) use (&$calls) { - ++$calls; - + $list = new LazyChoiceList($choiceLoader = new UsageTrackingChoiceLoader(['RESULT']), function ($choice) { return $choice; }); $this->assertSame(['RESULT'], $list->getStructuredValues()); $this->assertSame(['RESULT'], $list->getStructuredValues()); - $this->assertSame(1, $calls); + $this->assertSame(2, $choiceLoader->loadChoiceListCalls); } public function testGetOriginalKeysLoadsLoadedListOnFirstCall() { - $calls = 0; $choices = [ 'a' => 'foo', 'b' => 'bar', 'c' => 'baz', ]; - $list = new LazyChoiceList(new ArrayChoiceLoader($choices), function ($choice) use (&$calls) { - ++$calls; - + $list = new LazyChoiceList($choiceLoader = new UsageTrackingChoiceLoader($choices), function ($choice) { return $choice; }); $this->assertSame(['foo' => 'a', 'bar' => 'b', 'baz' => 'c'], $list->getOriginalKeys()); $this->assertSame(['foo' => 'a', 'bar' => 'b', 'baz' => 'c'], $list->getOriginalKeys()); - $this->assertSame(3, $calls); + $this->assertSame(2, $choiceLoader->loadChoiceListCalls); } public function testGetChoicesForValuesForwardsCallIfListNotLoaded() { - $calls = 0; $choices = [ 'a' => 'foo', 'b' => 'bar', 'c' => 'baz', ]; - $list = new LazyChoiceList(new ArrayChoiceLoader($choices), function ($choice) use ($choices, &$calls) { - ++$calls; - + $list = new LazyChoiceList($choiceLoader = new UsageTrackingChoiceLoader($choices), function ($choice) use ($choices) { return array_search($choice, $choices); }); $this->assertSame(['foo', 'bar'], $list->getChoicesForValues(['a', 'b'])); $this->assertSame(['foo', 'bar'], $list->getChoicesForValues(['a', 'b'])); - $this->assertSame(3, $calls); + $this->assertSame(2, $choiceLoader->loadChoiceListCalls); } public function testGetChoicesForValuesUsesLoadedList() @@ -108,7 +94,7 @@ public function testGetChoicesForValuesUsesLoadedList() 'b' => 'bar', 'c' => 'baz', ]; - $list = new LazyChoiceList(new ArrayChoiceLoader($choices), function ($choice) use ($choices) { + $list = new LazyChoiceList($choiceLoader = new UsageTrackingChoiceLoader($choices), function ($choice) use ($choices) { return array_search($choice, $choices); }); @@ -117,6 +103,7 @@ public function testGetChoicesForValuesUsesLoadedList() $this->assertSame(['foo', 'bar'], $list->getChoicesForValues(['a', 'b'])); $this->assertSame(['foo', 'bar'], $list->getChoicesForValues(['a', 'b'])); + $this->assertSame(1, $choiceLoader->loadChoiceListCalls); } public function testGetValuesForChoicesUsesLoadedList() @@ -126,7 +113,7 @@ public function testGetValuesForChoicesUsesLoadedList() 'b' => 'bar', 'c' => 'baz', ]; - $list = new LazyChoiceList(new ArrayChoiceLoader($choices), function ($choice) use ($choices) { + $list = new LazyChoiceList($choiceLoader = new UsageTrackingChoiceLoader($choices), function ($choice) use ($choices) { return array_search($choice, $choices); }); @@ -135,5 +122,18 @@ public function testGetValuesForChoicesUsesLoadedList() $this->assertSame(['a', 'b'], $list->getValuesForChoices(['foo', 'bar'])); $this->assertSame(['a', 'b'], $list->getValuesForChoices(['foo', 'bar'])); + $this->assertSame(1, $choiceLoader->loadChoiceListCalls); + } +} + +class UsageTrackingChoiceLoader extends ArrayChoiceLoader +{ + public $loadChoiceListCalls = 0; + + public function loadChoiceList($value = null): ChoiceListInterface + { + ++$this->loadChoiceListCalls; + + return parent::loadChoiceList($value); } }