diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index 5608e296b2..2a356d51be 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +3.2.0 +----- + + * added `CallbackChoiceLoader` + 3.1.0 ----- diff --git a/src/Symfony/Component/Form/ChoiceList/Loader/CallbackChoiceLoader.php b/src/Symfony/Component/Form/ChoiceList/Loader/CallbackChoiceLoader.php new file mode 100644 index 0000000000..d2ca5e013c --- /dev/null +++ b/src/Symfony/Component/Form/ChoiceList/Loader/CallbackChoiceLoader.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\ChoiceList\Loader; + +use Symfony\Component\Form\ChoiceList\ArrayChoiceList; + +/** + * Loads an {@link ArrayChoiceList} instance from a callable returning an array of choices. + * + * @author Jules Pietri + */ +class CallbackChoiceLoader implements ChoiceLoaderInterface +{ + private $callback; + + /** + * The loaded choice list. + * + * @var ArrayChoiceList + */ + private $choiceList; + + /** + * @param callable $callback The callable returning an array of choices + */ + public function __construct(callable $callback) + { + $this->callback = $callback; + } + + /** + * {@inheritdoc} + */ + public function loadChoiceList($value = null) + { + if (null !== $this->choiceList) { + return $this->choiceList; + } + + return $this->choiceList = new ArrayChoiceList(call_user_func($this->callback), $value); + } + + /** + * {@inheritdoc} + */ + public function loadChoicesForValues(array $values, $value = null) + { + // Optimize + if (empty($values)) { + return array(); + } + + return $this->loadChoiceList($value)->getChoicesForValues($values); + } + + /** + * {@inheritdoc} + */ + public function loadValuesForChoices(array $choices, $value = null) + { + // Optimize + if (empty($choices)) { + return array(); + } + + return $this->loadChoiceList($value)->getValuesForChoices($choices); + } +} diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/Loader/CallbackChoiceLoaderTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/Loader/CallbackChoiceLoaderTest.php new file mode 100644 index 0000000000..18c4d9d008 --- /dev/null +++ b/src/Symfony/Component/Form/Tests/ChoiceList/Loader/CallbackChoiceLoaderTest.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Tests\ChoiceList\Loader; + +use Symfony\Component\Form\ChoiceList\LazyChoiceList; +use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader; + +/** + * @author Jules Pietri + */ +class CallbackChoiceLoaderTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader + */ + static private $loader; + + /** + * @var callable + */ + static private $value; + + /** + * @var array + */ + static private $choices; + + /** + * @var string[] + */ + static private $choiceValues; + + /** + * @var \Symfony\Component\Form\ChoiceList\LazyChoiceList + */ + static private $lazyChoiceList; + + static public function setUpBeforeClass() + { + self::$loader = new CallbackChoiceLoader(function() { + return self::$choices; + }); + self::$value = function ($choice) { + return isset($choice->value) ? $choice->value : null; + }; + self::$choices = array( + (object) array('value' => 'choice_one'), + (object) array('value' => 'choice_two'), + ); + self::$choiceValues = array('choice_one', 'choice_two'); + self::$lazyChoiceList = new LazyChoiceList(self::$loader, self::$value); + } + + public function testLoadChoiceList() + { + $this->assertInstanceOf('\Symfony\Component\Form\ChoiceList\ChoiceListInterface', self::$loader->loadChoiceList(self::$value)); + } + + public function testLoadChoiceListOnlyOnce() + { + $loadedChoiceList = self::$loader->loadChoiceList(self::$value); + + $this->assertSame($loadedChoiceList, self::$loader->loadChoiceList(self::$value)); + } + + public function testLoadChoicesForValuesLoadsChoiceListOnFirstCall() + { + $this->assertSame( + self::$loader->loadChoicesForValues(self::$choiceValues, self::$value), + self::$lazyChoiceList->getChoicesForValues(self::$choiceValues), + 'Choice list should not be reloaded.' + ); + } + + public function testLoadValuesForChoicesLoadsChoiceListOnFirstCall() + { + $this->assertSame( + self::$loader->loadValuesForChoices(self::$choices, self::$value), + self::$lazyChoiceList->getValuesForChoices(self::$choices), + 'Choice list should not be reloaded.' + ); + } + + static public function tearDownAfterClass() + { + self::$loader = null; + self::$value = null; + self::$choices = array(); + self::$choiceValues = array(); + self::$lazyChoiceList = null; + } +}