[Form] Added a "choice_filter" option to ChoiceType
This commit is contained in:
parent
df1caaeaa6
commit
ed2c312609
@ -23,6 +23,7 @@ Form
|
||||
is deprecated. The method will be added to the interface in 6.0.
|
||||
* Implementing the `FormConfigBuilderInterface` without implementing the `setIsEmptyCallback()` method
|
||||
is deprecated. The method will be added to the interface in 6.0.
|
||||
* Added argument `callable|null $filter` to `ChoiceListFactoryInterface::createListFromChoices()` and `createListFromLoader()` - not defining them is deprecated.
|
||||
|
||||
FrameworkBundle
|
||||
---------------
|
||||
|
@ -21,6 +21,7 @@ Form
|
||||
|
||||
* Added the `getIsEmptyCallback()` method to the `FormConfigInterface`.
|
||||
* Added the `setIsEmptyCallback()` method to the `FormConfigBuilderInterface`.
|
||||
* Added argument `callable|null $filter` to `ChoiceListFactoryInterface::createListFromChoices()` and `createListFromLoader()`.
|
||||
|
||||
FrameworkBundle
|
||||
---------------
|
||||
|
@ -4,6 +4,8 @@ CHANGELOG
|
||||
5.1.0
|
||||
-----
|
||||
|
||||
* Added a `choice_filter` option to `ChoiceType`
|
||||
* Added argument `callable|null $filter` to `ChoiceListFactoryInterface::createListFromChoices()` and `createListFromLoader()` - not defining them is deprecated.
|
||||
* Added a `ChoiceList` facade to leverage explicit choice list caching based on options
|
||||
* Added an `AbstractChoiceLoader` to simplify implementations and handle global optimizations
|
||||
* The `view_timezone` option defaults to the `model_timezone` if no `reference_date` is configured.
|
||||
|
@ -13,6 +13,7 @@ namespace Symfony\Component\Form\ChoiceList;
|
||||
|
||||
use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceAttr;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceFieldName;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceFilter;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceLabel;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceLoader;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceValue;
|
||||
@ -66,6 +67,16 @@ final class ChoiceList
|
||||
return new ChoiceValue($formType, $value, $vary);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FormTypeInterface|FormTypeExtensionInterface $formType A form type or type extension configuring a cacheable choice list
|
||||
* @param callable $filter Any pseudo callable to filter a choice list
|
||||
* @param mixed|null $vary Dynamic data used to compute a unique hash when caching the callback
|
||||
*/
|
||||
public static function filter($formType, $filter, $vary = null): ChoiceFilter
|
||||
{
|
||||
return new ChoiceFilter($formType, $filter, $vary);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorates a "choice_label" option to make it cacheable.
|
||||
*
|
||||
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\ChoiceList\Factory\Cache;
|
||||
|
||||
use Symfony\Component\Form\FormTypeExtensionInterface;
|
||||
use Symfony\Component\Form\FormTypeInterface;
|
||||
|
||||
/**
|
||||
* A cacheable wrapper for any {@see FormTypeInterface} or {@see FormTypeExtensionInterface}
|
||||
* which configures a "choice_filter" option.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @author Jules Pietri <jules@heahprod.com>
|
||||
*/
|
||||
final class ChoiceFilter extends AbstractStaticOption
|
||||
{
|
||||
}
|
@ -19,6 +19,9 @@ use Symfony\Contracts\Service\ResetInterface;
|
||||
/**
|
||||
* Caches the choice lists created by the decorated factory.
|
||||
*
|
||||
* To cache a list based on its options, arguments must be decorated
|
||||
* by a {@see Cache\AbstractStaticOption} implementation.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
* @author Jules Pietri <jules@heahprod.com>
|
||||
*/
|
||||
@ -80,25 +83,42 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface, ResetInterf
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param callable|Cache\ChoiceValue|null $value The callable or static option for
|
||||
* generating the choice values
|
||||
* @param callable|Cache\ChoiceFilter|null $filter The callable or static option for
|
||||
* filtering the choices
|
||||
*/
|
||||
public function createListFromChoices(iterable $choices, $value = null)
|
||||
public function createListFromChoices(iterable $choices, $value = null/*, $filter = null*/)
|
||||
{
|
||||
$filter = \func_num_args() > 2 ? func_get_arg(2) : null;
|
||||
|
||||
if ($choices instanceof \Traversable) {
|
||||
$choices = iterator_to_array($choices);
|
||||
}
|
||||
|
||||
// Only cache per value when needed. The value is not validated on purpose.
|
||||
$cache = true;
|
||||
// Only cache per value and filter when needed. The value is not validated on purpose.
|
||||
// The decorated factory may decide which values to accept and which not.
|
||||
if ($value instanceof Cache\ChoiceValue) {
|
||||
$value = $value->getOption();
|
||||
} elseif ($value) {
|
||||
return $this->decoratedFactory->createListFromChoices($choices, $value);
|
||||
$cache = false;
|
||||
}
|
||||
if ($filter instanceof Cache\ChoiceFilter) {
|
||||
$filter = $filter->getOption();
|
||||
} elseif ($filter) {
|
||||
$cache = false;
|
||||
}
|
||||
|
||||
$hash = self::generateHash([$choices, $value], 'fromChoices');
|
||||
if (!$cache) {
|
||||
return $this->decoratedFactory->createListFromChoices($choices, $value, $filter);
|
||||
}
|
||||
|
||||
$hash = self::generateHash([$choices, $value, $filter], 'fromChoices');
|
||||
|
||||
if (!isset($this->lists[$hash])) {
|
||||
$this->lists[$hash] = $this->decoratedFactory->createListFromChoices($choices, $value);
|
||||
$this->lists[$hash] = $this->decoratedFactory->createListFromChoices($choices, $value, $filter);
|
||||
}
|
||||
|
||||
return $this->lists[$hash];
|
||||
@ -106,9 +126,18 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface, ResetInterf
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param ChoiceLoaderInterface|Cache\ChoiceLoader $loader The loader or static loader to load
|
||||
* the choices lazily
|
||||
* @param callable|Cache\ChoiceValue|null $value The callable or static option for
|
||||
* generating the choice values
|
||||
* @param callable|Cache\ChoiceFilter|null $filter The callable or static option for
|
||||
* filtering the choices
|
||||
*/
|
||||
public function createListFromLoader(ChoiceLoaderInterface $loader, $value = null)
|
||||
public function createListFromLoader(ChoiceLoaderInterface $loader, $value = null/*, $filter = null*/)
|
||||
{
|
||||
$filter = \func_num_args() > 2 ? func_get_arg(2) : null;
|
||||
|
||||
$cache = true;
|
||||
|
||||
if ($loader instanceof Cache\ChoiceLoader) {
|
||||
@ -123,14 +152,20 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface, ResetInterf
|
||||
$cache = false;
|
||||
}
|
||||
|
||||
if (!$cache) {
|
||||
return $this->decoratedFactory->createListFromLoader($loader, $value);
|
||||
if ($filter instanceof Cache\ChoiceFilter) {
|
||||
$filter = $filter->getOption();
|
||||
} elseif ($filter) {
|
||||
$cache = false;
|
||||
}
|
||||
|
||||
$hash = self::generateHash([$loader, $value], 'fromLoader');
|
||||
if (!$cache) {
|
||||
return $this->decoratedFactory->createListFromLoader($loader, $value, $filter);
|
||||
}
|
||||
|
||||
$hash = self::generateHash([$loader, $value, $filter], 'fromLoader');
|
||||
|
||||
if (!isset($this->lists[$hash])) {
|
||||
$this->lists[$hash] = $this->decoratedFactory->createListFromLoader($loader, $value);
|
||||
$this->lists[$hash] = $this->decoratedFactory->createListFromLoader($loader, $value, $filter);
|
||||
}
|
||||
|
||||
return $this->lists[$hash];
|
||||
@ -138,6 +173,12 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface, ResetInterf
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param array|callable|Cache\PreferredChoice|null $preferredChoices The preferred choices
|
||||
* @param callable|false|Cache\ChoiceLabel|null $label The option or static option generating the choice labels
|
||||
* @param callable|Cache\ChoiceFieldName|null $index The option or static option generating the view indices
|
||||
* @param callable|Cache\GroupBy|null $groupBy The option or static option generating the group names
|
||||
* @param array|callable|Cache\ChoiceAttr|null $attr The option or static option generating the HTML attributes
|
||||
*/
|
||||
public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, $index = null, $groupBy = null, $attr = null)
|
||||
{
|
||||
|
@ -31,9 +31,11 @@ interface ChoiceListFactoryInterface
|
||||
* The callable receives the choice as only argument.
|
||||
* Null may be passed when the choice list contains the empty value.
|
||||
*
|
||||
* @param callable|null $filter The callable filtering the choices
|
||||
*
|
||||
* @return ChoiceListInterface The choice list
|
||||
*/
|
||||
public function createListFromChoices(iterable $choices, callable $value = null);
|
||||
public function createListFromChoices(iterable $choices, callable $value = null/*, callable $filter = null*/);
|
||||
|
||||
/**
|
||||
* Creates a choice list that is loaded with the given loader.
|
||||
@ -42,9 +44,11 @@ interface ChoiceListFactoryInterface
|
||||
* The callable receives the choice as only argument.
|
||||
* Null may be passed when the choice list contains the empty value.
|
||||
*
|
||||
* @param callable|null $filter The callable filtering the choices
|
||||
*
|
||||
* @return ChoiceListInterface The choice list
|
||||
*/
|
||||
public function createListFromLoader(ChoiceLoaderInterface $loader, callable $value = null);
|
||||
public function createListFromLoader(ChoiceLoaderInterface $loader, callable $value = null/*, callable $filter = null*/);
|
||||
|
||||
/**
|
||||
* Creates a view for the given choice list.
|
||||
|
@ -14,7 +14,9 @@ namespace Symfony\Component\Form\ChoiceList\Factory;
|
||||
use Symfony\Component\Form\ChoiceList\ArrayChoiceList;
|
||||
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
|
||||
use Symfony\Component\Form\ChoiceList\LazyChoiceList;
|
||||
use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader;
|
||||
use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface;
|
||||
use Symfony\Component\Form\ChoiceList\Loader\FilterChoiceLoaderDecorator;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceListView;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
|
||||
@ -23,22 +25,44 @@ use Symfony\Component\Form\ChoiceList\View\ChoiceView;
|
||||
* Default implementation of {@link ChoiceListFactoryInterface}.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
* @author Jules Pietri <jules@heahprod.com>
|
||||
*/
|
||||
class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param callable|null $filter
|
||||
*/
|
||||
public function createListFromChoices(iterable $choices, callable $value = null)
|
||||
public function createListFromChoices(iterable $choices, callable $value = null/*, callable $filter = null*/)
|
||||
{
|
||||
$filter = \func_num_args() > 2 ? func_get_arg(2) : null;
|
||||
|
||||
if ($filter) {
|
||||
// filter the choice list lazily
|
||||
return $this->createListFromLoader(new FilterChoiceLoaderDecorator(
|
||||
new CallbackChoiceLoader(static function () use ($choices) {
|
||||
return $choices;
|
||||
}
|
||||
), $filter), $value);
|
||||
}
|
||||
|
||||
return new ArrayChoiceList($choices, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param callable|null $filter
|
||||
*/
|
||||
public function createListFromLoader(ChoiceLoaderInterface $loader, callable $value = null)
|
||||
public function createListFromLoader(ChoiceLoaderInterface $loader, callable $value = null/*, callable $filter = null*/)
|
||||
{
|
||||
$filter = \func_num_args() > 2 ? func_get_arg(2) : null;
|
||||
|
||||
if ($filter) {
|
||||
$loader = new FilterChoiceLoaderDecorator($loader, $filter);
|
||||
}
|
||||
|
||||
return new LazyChoiceList($loader, $value);
|
||||
}
|
||||
|
||||
|
@ -59,13 +59,17 @@ class PropertyAccessDecorator implements ChoiceListFactoryInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param callable|string|PropertyPath|null $value The callable or path for
|
||||
* generating the choice values
|
||||
* @param callable|string|PropertyPath|null $value The callable or path for
|
||||
* generating the choice values
|
||||
* @param callable|string|PropertyPath|null $filter The callable or path for
|
||||
* filtering the choices
|
||||
*
|
||||
* @return ChoiceListInterface The choice list
|
||||
*/
|
||||
public function createListFromChoices(iterable $choices, $value = null)
|
||||
public function createListFromChoices(iterable $choices, $value = null/*, $filter = null*/)
|
||||
{
|
||||
$filter = \func_num_args() > 2 ? func_get_arg(2) : null;
|
||||
|
||||
if (\is_string($value)) {
|
||||
$value = new PropertyPath($value);
|
||||
}
|
||||
@ -81,19 +85,34 @@ class PropertyAccessDecorator implements ChoiceListFactoryInterface
|
||||
};
|
||||
}
|
||||
|
||||
return $this->decoratedFactory->createListFromChoices($choices, $value);
|
||||
if (\is_string($filter)) {
|
||||
$filter = new PropertyPath($filter);
|
||||
}
|
||||
|
||||
if ($filter instanceof PropertyPath) {
|
||||
$accessor = $this->propertyAccessor;
|
||||
$filter = static function ($choice) use ($accessor, $filter) {
|
||||
return (\is_object($choice) || \is_array($choice)) && $accessor->getValue($choice, $filter);
|
||||
};
|
||||
}
|
||||
|
||||
return $this->decoratedFactory->createListFromChoices($choices, $value, $filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param callable|string|PropertyPath|null $value The callable or path for
|
||||
* generating the choice values
|
||||
* @param callable|string|PropertyPath|null $value The callable or path for
|
||||
* generating the choice values
|
||||
* @param callable|string|PropertyPath|null $filter The callable or path for
|
||||
* filtering the choices
|
||||
*
|
||||
* @return ChoiceListInterface The choice list
|
||||
*/
|
||||
public function createListFromLoader(ChoiceLoaderInterface $loader, $value = null)
|
||||
public function createListFromLoader(ChoiceLoaderInterface $loader, $value = null/*, $filter = null*/)
|
||||
{
|
||||
$filter = \func_num_args() > 2 ? func_get_arg(2) : null;
|
||||
|
||||
if (\is_string($value)) {
|
||||
$value = new PropertyPath($value);
|
||||
}
|
||||
@ -109,7 +128,18 @@ class PropertyAccessDecorator implements ChoiceListFactoryInterface
|
||||
};
|
||||
}
|
||||
|
||||
return $this->decoratedFactory->createListFromLoader($loader, $value);
|
||||
if (\is_string($filter)) {
|
||||
$filter = new PropertyPath($filter);
|
||||
}
|
||||
|
||||
if ($filter instanceof PropertyPath) {
|
||||
$accessor = $this->propertyAccessor;
|
||||
$filter = static function ($choice) use ($accessor, $filter) {
|
||||
return (\is_object($choice) || \is_array($choice)) && $accessor->getValue($choice, $filter);
|
||||
};
|
||||
}
|
||||
|
||||
return $this->decoratedFactory->createListFromLoader($loader, $value, $filter);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* A decorator to filter choices only when they are loaded or partially loaded.
|
||||
*
|
||||
* @author Jules Pietri <jules@heahprod.com>
|
||||
*/
|
||||
class FilterChoiceLoaderDecorator extends AbstractChoiceLoader
|
||||
{
|
||||
private $decoratedLoader;
|
||||
private $filter;
|
||||
|
||||
public function __construct(ChoiceLoaderInterface $loader, callable $filter)
|
||||
{
|
||||
$this->decoratedLoader = $loader;
|
||||
$this->filter = $filter;
|
||||
}
|
||||
|
||||
protected function loadChoices(): iterable
|
||||
{
|
||||
$list = $this->decoratedLoader->loadChoiceList();
|
||||
|
||||
if (array_values($list->getValues()) === array_values($structuredValues = $list->getStructuredValues())) {
|
||||
return array_filter(array_combine($list->getOriginalKeys(), $list->getChoices()), $this->filter);
|
||||
}
|
||||
|
||||
foreach ($structuredValues as $group => $values) {
|
||||
if ($values && $filtered = array_filter($list->getChoicesForValues($values), $this->filter)) {
|
||||
$choices[$group] = $filtered;
|
||||
}
|
||||
// filter empty groups
|
||||
}
|
||||
|
||||
return $choices ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadChoicesForValues(array $values, callable $value = null): array
|
||||
{
|
||||
return array_filter($this->decoratedLoader->loadChoicesForValues($values, $value), $this->filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadValuesForChoices(array $choices, callable $value = null): array
|
||||
{
|
||||
return $this->decoratedLoader->loadValuesForChoices(array_filter($choices, $this->filter), $value);
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceAttr;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceFieldName;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceFilter;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceLabel;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceLoader;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceValue;
|
||||
@ -40,6 +41,7 @@ use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Form\FormView;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\PropertyAccess\PropertyPath;
|
||||
|
||||
class ChoiceType extends AbstractType
|
||||
{
|
||||
@ -52,6 +54,17 @@ class ChoiceType extends AbstractType
|
||||
new DefaultChoiceListFactory()
|
||||
)
|
||||
);
|
||||
|
||||
// BC, to be removed in 6.0
|
||||
if ($this->choiceListFactory instanceof CachingFactoryDecorator) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ref = new \ReflectionMethod($this->choiceListFactory, 'createListFromChoices');
|
||||
|
||||
if ($ref->getNumberOfParameters() < 3) {
|
||||
trigger_deprecation('symfony/form', '5.1', 'Not defining a third parameter "callable|null $filter" in "%s::%s()" is deprecated.', $ref->class, $ref->name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -307,6 +320,7 @@ class ChoiceType extends AbstractType
|
||||
'multiple' => false,
|
||||
'expanded' => false,
|
||||
'choices' => [],
|
||||
'choice_filter' => null,
|
||||
'choice_loader' => null,
|
||||
'choice_label' => null,
|
||||
'choice_name' => null,
|
||||
@ -332,6 +346,7 @@ class ChoiceType extends AbstractType
|
||||
$resolver->setAllowedTypes('choices', ['null', 'array', '\Traversable']);
|
||||
$resolver->setAllowedTypes('choice_translation_domain', ['null', 'bool', 'string']);
|
||||
$resolver->setAllowedTypes('choice_loader', ['null', 'Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface', ChoiceLoader::class]);
|
||||
$resolver->setAllowedTypes('choice_filter', ['null', 'callable', 'string', PropertyPath::class, ChoiceFilter::class]);
|
||||
$resolver->setAllowedTypes('choice_label', ['null', 'bool', 'callable', 'string', 'Symfony\Component\PropertyAccess\PropertyPath', ChoiceLabel::class]);
|
||||
$resolver->setAllowedTypes('choice_name', ['null', 'callable', 'string', 'Symfony\Component\PropertyAccess\PropertyPath', ChoiceFieldName::class]);
|
||||
$resolver->setAllowedTypes('choice_value', ['null', 'callable', 'string', 'Symfony\Component\PropertyAccess\PropertyPath', ChoiceValue::class]);
|
||||
@ -396,14 +411,19 @@ class ChoiceType extends AbstractType
|
||||
if (null !== $options['choice_loader']) {
|
||||
return $this->choiceListFactory->createListFromLoader(
|
||||
$options['choice_loader'],
|
||||
$options['choice_value']
|
||||
$options['choice_value'],
|
||||
$options['choice_filter']
|
||||
);
|
||||
}
|
||||
|
||||
// Harden against NULL values (like in EntityType and ModelType)
|
||||
$choices = null !== $options['choices'] ? $options['choices'] : [];
|
||||
|
||||
return $this->choiceListFactory->createListFromChoices($choices, $options['choice_value']);
|
||||
return $this->choiceListFactory->createListFromChoices(
|
||||
$choices,
|
||||
$options['choice_value'],
|
||||
$options['choice_filter']
|
||||
);
|
||||
}
|
||||
|
||||
private function createChoiceListView(ChoiceListInterface $choiceList, array $options)
|
||||
|
@ -135,16 +135,21 @@ class CachingFactoryDecoratorTest extends TestCase
|
||||
public function testCreateFromChoicesSameValueClosure()
|
||||
{
|
||||
$choices = [1];
|
||||
$list = new ArrayChoiceList([]);
|
||||
$list1 = new ArrayChoiceList([]);
|
||||
$list2 = new ArrayChoiceList([]);
|
||||
$closure = function () {};
|
||||
|
||||
$this->decoratedFactory->expects($this->exactly(2))
|
||||
$this->decoratedFactory->expects($this->at(0))
|
||||
->method('createListFromChoices')
|
||||
->with($choices, $closure)
|
||||
->willReturn($list);
|
||||
->willReturn($list1);
|
||||
$this->decoratedFactory->expects($this->at(1))
|
||||
->method('createListFromChoices')
|
||||
->with($choices, $closure)
|
||||
->willReturn($list2);
|
||||
|
||||
$this->assertSame($list, $this->factory->createListFromChoices($choices, $closure));
|
||||
$this->assertSame($list, $this->factory->createListFromChoices($choices, $closure));
|
||||
$this->assertSame($list1, $this->factory->createListFromChoices($choices, $closure));
|
||||
$this->assertSame($list2, $this->factory->createListFromChoices($choices, $closure));
|
||||
}
|
||||
|
||||
public function testCreateFromChoicesSameValueClosureUseCache()
|
||||
@ -185,6 +190,64 @@ class CachingFactoryDecoratorTest extends TestCase
|
||||
$this->assertSame($list2, $this->factory->createListFromChoices($choices, $closure2));
|
||||
}
|
||||
|
||||
public function testCreateFromChoicesSameFilterClosure()
|
||||
{
|
||||
$choices = [1];
|
||||
$list1 = new ArrayChoiceList([]);
|
||||
$list2 = new ArrayChoiceList([]);
|
||||
$filter = function () {};
|
||||
|
||||
$this->decoratedFactory->expects($this->at(0))
|
||||
->method('createListFromChoices')
|
||||
->with($choices, null, $filter)
|
||||
->willReturn($list1);
|
||||
$this->decoratedFactory->expects($this->at(1))
|
||||
->method('createListFromChoices')
|
||||
->with($choices, null, $filter)
|
||||
->willReturn($list2);
|
||||
|
||||
$this->assertSame($list1, $this->factory->createListFromChoices($choices, null, $filter));
|
||||
$this->assertSame($list2, $this->factory->createListFromChoices($choices, null, $filter));
|
||||
}
|
||||
|
||||
public function testCreateFromChoicesSameFilterClosureUseCache()
|
||||
{
|
||||
$choices = [1];
|
||||
$list = new ArrayChoiceList([]);
|
||||
$formType = $this->createMock(FormTypeInterface::class);
|
||||
$filterCallback = function () {};
|
||||
|
||||
$this->decoratedFactory->expects($this->once())
|
||||
->method('createListFromChoices')
|
||||
->with($choices, null, $filterCallback)
|
||||
->willReturn($list)
|
||||
;
|
||||
|
||||
$this->assertSame($list, $this->factory->createListFromChoices($choices, null, ChoiceList::filter($formType, $filterCallback)));
|
||||
$this->assertSame($list, $this->factory->createListFromChoices($choices, null, ChoiceList::filter($formType, function () {})));
|
||||
}
|
||||
|
||||
public function testCreateFromChoicesDifferentFilterClosure()
|
||||
{
|
||||
$choices = [1];
|
||||
$list1 = new ArrayChoiceList([]);
|
||||
$list2 = new ArrayChoiceList([]);
|
||||
$closure1 = function () {};
|
||||
$closure2 = function () {};
|
||||
|
||||
$this->decoratedFactory->expects($this->at(0))
|
||||
->method('createListFromChoices')
|
||||
->with($choices, null, $closure1)
|
||||
->willReturn($list1);
|
||||
$this->decoratedFactory->expects($this->at(1))
|
||||
->method('createListFromChoices')
|
||||
->with($choices, null, $closure2)
|
||||
->willReturn($list2);
|
||||
|
||||
$this->assertSame($list1, $this->factory->createListFromChoices($choices, null, $closure1));
|
||||
$this->assertSame($list2, $this->factory->createListFromChoices($choices, null, $closure2));
|
||||
}
|
||||
|
||||
public function testCreateFromLoaderSameLoader()
|
||||
{
|
||||
$loader = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface')->getMock();
|
||||
@ -310,6 +373,76 @@ class CachingFactoryDecoratorTest extends TestCase
|
||||
$this->assertSame($list2, $this->factory->createListFromLoader(ChoiceList::loader($type, $this->createMock(ChoiceLoaderInterface::class)), $closure2));
|
||||
}
|
||||
|
||||
public function testCreateFromLoaderSameFilterClosure()
|
||||
{
|
||||
$loader = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface')->getMock();
|
||||
$type = $this->createMock(FormTypeInterface::class);
|
||||
$list = new ArrayChoiceList([]);
|
||||
$list2 = new ArrayChoiceList([]);
|
||||
$closure = function () {};
|
||||
|
||||
$this->decoratedFactory->expects($this->at(0))
|
||||
->method('createListFromLoader')
|
||||
->with($loader, null, $closure)
|
||||
->willReturn($list)
|
||||
;
|
||||
$this->decoratedFactory->expects($this->at(1))
|
||||
->method('createListFromLoader')
|
||||
->with($loader, null, $closure)
|
||||
->willReturn($list2)
|
||||
;
|
||||
|
||||
$this->assertSame($list, $this->factory->createListFromLoader(ChoiceList::loader($type, $loader), null, $closure));
|
||||
$this->assertSame($list2, $this->factory->createListFromLoader(ChoiceList::loader($type, $this->createMock(ChoiceLoaderInterface::class)), null, $closure));
|
||||
}
|
||||
|
||||
public function testCreateFromLoaderSameFilterClosureUseCache()
|
||||
{
|
||||
$type = $this->createMock(FormTypeInterface::class);
|
||||
$loader = $this->createMock(ChoiceLoaderInterface::class);
|
||||
$list = new ArrayChoiceList([]);
|
||||
$closure = function () {};
|
||||
|
||||
$this->decoratedFactory->expects($this->once())
|
||||
->method('createListFromLoader')
|
||||
->with($loader, null, $closure)
|
||||
->willReturn($list)
|
||||
;
|
||||
|
||||
$this->assertSame($list, $this->factory->createListFromLoader(
|
||||
ChoiceList::loader($type, $loader),
|
||||
null,
|
||||
ChoiceList::filter($type, $closure)
|
||||
));
|
||||
$this->assertSame($list, $this->factory->createListFromLoader(
|
||||
ChoiceList::loader($type, $this->createMock(ChoiceLoaderInterface::class)),
|
||||
null,
|
||||
ChoiceList::filter($type, function () {})
|
||||
));
|
||||
}
|
||||
|
||||
public function testCreateFromLoaderDifferentFilterClosure()
|
||||
{
|
||||
$loader = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface')->getMock();
|
||||
$type = $this->createMock(FormTypeInterface::class);
|
||||
$list1 = new ArrayChoiceList([]);
|
||||
$list2 = new ArrayChoiceList([]);
|
||||
$closure1 = function () {};
|
||||
$closure2 = function () {};
|
||||
|
||||
$this->decoratedFactory->expects($this->at(0))
|
||||
->method('createListFromLoader')
|
||||
->with($loader, null, $closure1)
|
||||
->willReturn($list1);
|
||||
$this->decoratedFactory->expects($this->at(1))
|
||||
->method('createListFromLoader')
|
||||
->with($loader, null, $closure2)
|
||||
->willReturn($list2);
|
||||
|
||||
$this->assertSame($list1, $this->factory->createListFromLoader(ChoiceList::loader($type, $loader), null, $closure1));
|
||||
$this->assertSame($list2, $this->factory->createListFromLoader(ChoiceList::loader($type, $this->createMock(ChoiceLoaderInterface::class)), null, $closure2));
|
||||
}
|
||||
|
||||
public function testCreateViewSamePreferredChoices()
|
||||
{
|
||||
$preferred = ['a'];
|
||||
|
@ -16,6 +16,7 @@ use Symfony\Component\Form\ChoiceList\ArrayChoiceList;
|
||||
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
|
||||
use Symfony\Component\Form\ChoiceList\LazyChoiceList;
|
||||
use Symfony\Component\Form\ChoiceList\Loader\FilterChoiceLoaderDecorator;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceListView;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
|
||||
@ -30,6 +31,10 @@ class DefaultChoiceListFactoryTest extends TestCase
|
||||
|
||||
private $obj4;
|
||||
|
||||
private $obj5;
|
||||
|
||||
private $obj6;
|
||||
|
||||
private $list;
|
||||
|
||||
/**
|
||||
@ -191,6 +196,55 @@ class DefaultChoiceListFactoryTest extends TestCase
|
||||
$this->assertObjectListWithCustomValues($list);
|
||||
}
|
||||
|
||||
public function testCreateFromFilteredChoices()
|
||||
{
|
||||
$list = $this->factory->createListFromChoices(
|
||||
['A' => $this->obj1, 'B' => $this->obj2, 'C' => $this->obj3, 'D' => $this->obj4, 'E' => $this->obj5, 'F' => $this->obj6],
|
||||
null,
|
||||
function ($choice) {
|
||||
return $choice !== $this->obj5 && $choice !== $this->obj6;
|
||||
}
|
||||
);
|
||||
|
||||
$this->assertObjectListWithGeneratedValues($list);
|
||||
}
|
||||
|
||||
public function testCreateFromChoicesGroupedAndFiltered()
|
||||
{
|
||||
$list = $this->factory->createListFromChoices(
|
||||
[
|
||||
'Group 1' => ['A' => $this->obj1, 'B' => $this->obj2],
|
||||
'Group 2' => ['C' => $this->obj3, 'D' => $this->obj4],
|
||||
'Group 3' => ['E' => $this->obj5, 'F' => $this->obj6],
|
||||
'Group 4' => [/* empty group should be filtered */],
|
||||
],
|
||||
null,
|
||||
function ($choice) {
|
||||
return $choice !== $this->obj5 && $choice !== $this->obj6;
|
||||
}
|
||||
);
|
||||
|
||||
$this->assertObjectListWithGeneratedValues($list);
|
||||
}
|
||||
|
||||
public function testCreateFromChoicesGroupedAndFilteredTraversable()
|
||||
{
|
||||
$list = $this->factory->createListFromChoices(
|
||||
new \ArrayIterator([
|
||||
'Group 1' => ['A' => $this->obj1, 'B' => $this->obj2],
|
||||
'Group 2' => ['C' => $this->obj3, 'D' => $this->obj4],
|
||||
'Group 3' => ['E' => $this->obj5, 'F' => $this->obj6],
|
||||
'Group 4' => [/* empty group should be filtered */],
|
||||
]),
|
||||
null,
|
||||
function ($choice) {
|
||||
return $choice !== $this->obj5 && $choice !== $this->obj6;
|
||||
}
|
||||
);
|
||||
|
||||
$this->assertObjectListWithGeneratedValues($list);
|
||||
}
|
||||
|
||||
public function testCreateFromLoader()
|
||||
{
|
||||
$loader = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface')->getMock();
|
||||
@ -210,6 +264,16 @@ class DefaultChoiceListFactoryTest extends TestCase
|
||||
$this->assertEquals(new LazyChoiceList($loader, $value), $list);
|
||||
}
|
||||
|
||||
public function testCreateFromLoaderWithFilter()
|
||||
{
|
||||
$loader = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface')->getMock();
|
||||
$filter = function () {};
|
||||
|
||||
$list = $this->factory->createListFromLoader($loader, null, $filter);
|
||||
|
||||
$this->assertEquals(new LazyChoiceList(new FilterChoiceLoaderDecorator($loader, $filter)), $list);
|
||||
}
|
||||
|
||||
public function testCreateViewFlat()
|
||||
{
|
||||
$view = $this->factory->createView($this->list);
|
||||
|
@ -67,6 +67,47 @@ class PropertyAccessDecoratorTest extends TestCase
|
||||
$this->assertSame(['value' => 'value'], $this->factory->createListFromChoices($choices, new PropertyPath('property'))->getChoices());
|
||||
}
|
||||
|
||||
public function testCreateFromChoicesFilterPropertyPath()
|
||||
{
|
||||
$filteredChoices = [
|
||||
'two' => (object) ['property' => 'value 2', 'filter' => true],
|
||||
];
|
||||
$choices = [
|
||||
'one' => (object) ['property' => 'value 1', 'filter' => false],
|
||||
] + $filteredChoices;
|
||||
|
||||
$this->decoratedFactory->expects($this->once())
|
||||
->method('createListFromChoices')
|
||||
->with($choices, $this->isInstanceOf('\Closure'), $this->isInstanceOf('\Closure'))
|
||||
->willReturnCallback(function ($choices, $value, $callback) {
|
||||
return new ArrayChoiceList(array_map($value, array_filter($choices, $callback)));
|
||||
});
|
||||
|
||||
$this->assertSame(['value 2' => 'value 2'], $this->factory->createListFromChoices($choices, 'property', 'filter')->getChoices());
|
||||
}
|
||||
|
||||
public function testCreateFromChoicesFilterPropertyPathInstance()
|
||||
{
|
||||
$filteredChoices = [
|
||||
'two' => (object) ['property' => 'value 2', 'filter' => true],
|
||||
];
|
||||
$choices = [
|
||||
'one' => (object) ['property' => 'value 1', 'filter' => false],
|
||||
] + $filteredChoices;
|
||||
|
||||
$this->decoratedFactory->expects($this->once())
|
||||
->method('createListFromChoices')
|
||||
->with($choices, $this->isInstanceOf('\Closure'), $this->isInstanceOf('\Closure'))
|
||||
->willReturnCallback(function ($choices, $value, $callback) {
|
||||
return new ArrayChoiceList(array_map($value, array_filter($choices, $callback)));
|
||||
});
|
||||
|
||||
$this->assertSame(
|
||||
['value 2' => 'value 2'],
|
||||
$this->factory->createListFromChoices($choices, new PropertyPath('property'), new PropertyPath('filter'))->getChoices()
|
||||
);
|
||||
}
|
||||
|
||||
public function testCreateFromLoaderPropertyPath()
|
||||
{
|
||||
$loader = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface')->getMock();
|
||||
@ -81,6 +122,26 @@ class PropertyAccessDecoratorTest extends TestCase
|
||||
$this->assertSame(['value' => 'value'], $this->factory->createListFromLoader($loader, 'property')->getChoices());
|
||||
}
|
||||
|
||||
public function testCreateFromLoaderFilterPropertyPath()
|
||||
{
|
||||
$loader = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface')->getMock();
|
||||
$filteredChoices = [
|
||||
'two' => (object) ['property' => 'value 2', 'filter' => true],
|
||||
];
|
||||
$choices = [
|
||||
'one' => (object) ['property' => 'value 1', 'filter' => false],
|
||||
] + $filteredChoices;
|
||||
|
||||
$this->decoratedFactory->expects($this->once())
|
||||
->method('createListFromLoader')
|
||||
->with($loader, $this->isInstanceOf('\Closure'), $this->isInstanceOf('\Closure'))
|
||||
->willReturnCallback(function ($loader, $value, $callback) use ($choices) {
|
||||
return new ArrayChoiceList(array_map($value, array_filter($choices, $callback)));
|
||||
});
|
||||
|
||||
$this->assertSame(['value 2' => 'value 2'], $this->factory->createListFromLoader($loader, 'property', 'filter')->getChoices());
|
||||
}
|
||||
|
||||
// https://github.com/symfony/symfony/issues/5494
|
||||
public function testCreateFromChoicesAssumeNullIfValuePropertyPathUnreadable()
|
||||
{
|
||||
|
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Form\Tests\ChoiceList\Loader;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Form\ChoiceList\ArrayChoiceList;
|
||||
use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface;
|
||||
use Symfony\Component\Form\ChoiceList\Loader\FilterChoiceLoaderDecorator;
|
||||
|
||||
class FilterChoiceLoaderDecoratorTest extends TestCase
|
||||
{
|
||||
public function testLoadChoiceList()
|
||||
{
|
||||
$decorated = $this->getMockBuilder(ChoiceLoaderInterface::class)->getMock();
|
||||
$decorated->expects($this->once())
|
||||
->method('loadChoiceList')
|
||||
->willReturn(new ArrayChoiceList(range(1, 4)))
|
||||
;
|
||||
|
||||
$filter = function ($choice) {
|
||||
return 0 === $choice % 2;
|
||||
};
|
||||
|
||||
$loader = new FilterChoiceLoaderDecorator($decorated, $filter);
|
||||
|
||||
$this->assertEquals(new ArrayChoiceList([1 => 2, 3 => 4]), $loader->loadChoiceList());
|
||||
}
|
||||
|
||||
public function testLoadChoiceListWithGroupedChoices()
|
||||
{
|
||||
$decorated = $this->getMockBuilder(ChoiceLoaderInterface::class)->getMock();
|
||||
$decorated->expects($this->once())
|
||||
->method('loadChoiceList')
|
||||
->willReturn(new ArrayChoiceList(['units' => range(1, 9), 'tens' => range(10, 90, 10)]))
|
||||
;
|
||||
|
||||
$filter = function ($choice) {
|
||||
return $choice < 9 && 0 === $choice % 2;
|
||||
};
|
||||
|
||||
$loader = new FilterChoiceLoaderDecorator($decorated, $filter);
|
||||
|
||||
$this->assertEquals(new ArrayChoiceList([
|
||||
'units' => [
|
||||
1 => 2,
|
||||
3 => 4,
|
||||
5 => 6,
|
||||
7 => 8,
|
||||
],
|
||||
]), $loader->loadChoiceList());
|
||||
}
|
||||
|
||||
public function testLoadValuesForChoices()
|
||||
{
|
||||
$evenValues = [1 => '2', 3 => '4'];
|
||||
|
||||
$decorated = $this->getMockBuilder(ChoiceLoaderInterface::class)->getMock();
|
||||
$decorated->expects($this->never())
|
||||
->method('loadChoiceList')
|
||||
;
|
||||
$decorated->expects($this->once())
|
||||
->method('loadValuesForChoices')
|
||||
->with([1 => 2, 3 => 4])
|
||||
->willReturn($evenValues)
|
||||
;
|
||||
|
||||
$filter = function ($choice) {
|
||||
return 0 === $choice % 2;
|
||||
};
|
||||
|
||||
$loader = new FilterChoiceLoaderDecorator($decorated, $filter);
|
||||
|
||||
$this->assertSame($evenValues, $loader->loadValuesForChoices(range(1, 4)));
|
||||
}
|
||||
|
||||
public function testLoadChoicesForValues()
|
||||
{
|
||||
$evenChoices = [1 => 2, 3 => 4];
|
||||
$values = array_map('strval', range(1, 4));
|
||||
|
||||
$decorated = $this->getMockBuilder(ChoiceLoaderInterface::class)->getMock();
|
||||
$decorated->expects($this->never())
|
||||
->method('loadChoiceList')
|
||||
;
|
||||
$decorated->expects($this->once())
|
||||
->method('loadChoicesForValues')
|
||||
->with($values)
|
||||
->willReturn(range(1, 4))
|
||||
;
|
||||
|
||||
$filter = function ($choice) {
|
||||
return 0 === $choice % 2;
|
||||
};
|
||||
|
||||
$loader = new FilterChoiceLoaderDecorator($decorated, $filter);
|
||||
|
||||
$this->assertEquals($evenChoices, $loader->loadChoicesForValues($values));
|
||||
}
|
||||
}
|
@ -11,8 +11,11 @@
|
||||
|
||||
namespace Symfony\Component\Form\Tests\Extension\Core\Type;
|
||||
|
||||
use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Tests\Fixtures\ChoiceList\DeprecatedChoiceListFactory;
|
||||
|
||||
class ChoiceTypeTest extends BaseTypeTest
|
||||
{
|
||||
@ -2090,4 +2093,66 @@ class ChoiceTypeTest extends BaseTypeTest
|
||||
'Placeholder submitted / single / not required / with a placeholder -> should not be empty' => [false, '', false, false, 'ccc'], // The placeholder is a selected value
|
||||
];
|
||||
}
|
||||
|
||||
public function testFilteredChoices()
|
||||
{
|
||||
$form = $this->factory->create(static::TESTED_TYPE, null, [
|
||||
'choices' => $this->choices,
|
||||
'choice_filter' => function ($choice) {
|
||||
return \in_array($choice, range('a', 'c'), true);
|
||||
},
|
||||
]);
|
||||
|
||||
$this->assertEquals([
|
||||
new ChoiceView('a', 'a', 'Bernhard'),
|
||||
new ChoiceView('b', 'b', 'Fabien'),
|
||||
new ChoiceView('c', 'c', 'Kris'),
|
||||
], $form->createView()->vars['choices']);
|
||||
}
|
||||
|
||||
public function testFilteredGroupedChoices()
|
||||
{
|
||||
$form = $this->factory->create(static::TESTED_TYPE, null, [
|
||||
'choices' => $this->groupedChoices,
|
||||
'choice_filter' => function ($choice) {
|
||||
return \in_array($choice, range('a', 'c'), true);
|
||||
},
|
||||
]);
|
||||
|
||||
$this->assertEquals(['Symfony' => new ChoiceGroupView('Symfony', [
|
||||
new ChoiceView('a', 'a', 'Bernhard'),
|
||||
new ChoiceView('b', 'b', 'Fabien'),
|
||||
new ChoiceView('c', 'c', 'Kris'),
|
||||
])], $form->createView()->vars['choices']);
|
||||
}
|
||||
|
||||
public function testFilteredChoiceLoader()
|
||||
{
|
||||
$form = $this->factory->create(static::TESTED_TYPE, null, [
|
||||
'choice_loader' => new CallbackChoiceLoader(function () {
|
||||
return $this->choices;
|
||||
}),
|
||||
'choice_filter' => function ($choice) {
|
||||
return \in_array($choice, range('a', 'c'), true);
|
||||
},
|
||||
]);
|
||||
|
||||
$this->assertEquals([
|
||||
new ChoiceView('a', 'a', 'Bernhard'),
|
||||
new ChoiceView('b', 'b', 'Fabien'),
|
||||
new ChoiceView('c', 'c', 'Kris'),
|
||||
], $form->createView()->vars['choices']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*
|
||||
* @expectedDeprecation The "Symfony\Component\Form\Tests\Fixtures\ChoiceList\DeprecatedChoiceListFactory::createListFromChoices()" method will require a new "callable|null $filter" argument in the next major version of its interface "Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface", not defining it is deprecated.
|
||||
* @expectedDeprecation The "Symfony\Component\Form\Tests\Fixtures\ChoiceList\DeprecatedChoiceListFactory::createListFromLoader()" method will require a new "callable|null $filter" argument in the next major version of its interface "Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface", not defining it is deprecated.
|
||||
* @expectedDeprecation Since symfony/form 5.1: Not defining a third parameter "callable|null $filter" in "Symfony\Component\Form\Tests\Fixtures\ChoiceList\DeprecatedChoiceListFactory::createListFromChoices()" is deprecated.
|
||||
*/
|
||||
public function testUsingDeprecatedChoiceListFactory()
|
||||
{
|
||||
new ChoiceType(new DeprecatedChoiceListFactory());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Form\Tests\Fixtures\ChoiceList;
|
||||
|
||||
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface;
|
||||
use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface;
|
||||
|
||||
class DeprecatedChoiceListFactory implements ChoiceListFactoryInterface
|
||||
{
|
||||
public function createListFromChoices(iterable $choices, callable $value = null)
|
||||
{
|
||||
}
|
||||
|
||||
public function createListFromLoader(ChoiceLoaderInterface $loader, callable $value = null)
|
||||
{
|
||||
}
|
||||
|
||||
public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, callable $index = null, callable $groupBy = null, $attr = null)
|
||||
{
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
"options": {
|
||||
"own": [
|
||||
"choice_attr",
|
||||
"choice_filter",
|
||||
"choice_label",
|
||||
"choice_loader",
|
||||
"choice_name",
|
||||
|
@ -6,18 +6,18 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (Block prefix: "choice")
|
||||
Options Overridden options Parent options Extension options
|
||||
--------------------------- -------------------- ------------------------------ -----------------------
|
||||
choice_attr FormType FormType FormTypeCsrfExtension
|
||||
choice_label -------------------- ------------------------------ -----------------------
|
||||
choice_loader compound action csrf_field_name
|
||||
choice_name data_class allow_file_upload csrf_message
|
||||
choice_translation_domain empty_data attr csrf_protection
|
||||
choice_value error_bubbling attr_translation_parameters csrf_token_id
|
||||
choices trim auto_initialize csrf_token_manager
|
||||
expanded block_name
|
||||
group_by block_prefix
|
||||
multiple by_reference
|
||||
placeholder data
|
||||
preferred_choices disabled
|
||||
help
|
||||
choice_filter -------------------- ------------------------------ -----------------------
|
||||
choice_label compound action csrf_field_name
|
||||
choice_loader data_class allow_file_upload csrf_message
|
||||
choice_name empty_data attr csrf_protection
|
||||
choice_translation_domain error_bubbling attr_translation_parameters csrf_token_id
|
||||
choice_value trim auto_initialize csrf_token_manager
|
||||
choices block_name
|
||||
expanded block_prefix
|
||||
group_by by_reference
|
||||
multiple data
|
||||
placeholder disabled
|
||||
preferred_choices help
|
||||
help_attr
|
||||
help_html
|
||||
help_translation_parameters
|
||||
|
@ -43,6 +43,7 @@
|
||||
"symfony/console": "<4.4",
|
||||
"symfony/dependency-injection": "<4.4",
|
||||
"symfony/doctrine-bridge": "<4.4",
|
||||
"symfony/error-handler": "<4.4.5",
|
||||
"symfony/framework-bundle": "<4.4",
|
||||
"symfony/http-kernel": "<4.4",
|
||||
"symfony/intl": "<4.4",
|
||||
|
Reference in New Issue
Block a user