[Form] Fixed handling of choices passed in choice groups
This commit is contained in:
parent
cc13cc5584
commit
7623dc87e8
@ -30,14 +30,21 @@ class ArrayChoiceList implements ChoiceListInterface
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $choices = array();
|
||||
protected $choices;
|
||||
|
||||
/**
|
||||
* The values of the choices.
|
||||
* The values indexed by the original keys.
|
||||
*
|
||||
* @var string[]
|
||||
* @var array
|
||||
*/
|
||||
protected $values = array();
|
||||
protected $structuredValues;
|
||||
|
||||
/**
|
||||
* The original keys of the choices array.
|
||||
*
|
||||
* @var int[]|string[]
|
||||
*/
|
||||
protected $originalKeys;
|
||||
|
||||
/**
|
||||
* The callback for creating the value for a choice.
|
||||
@ -51,31 +58,41 @@ class ArrayChoiceList implements ChoiceListInterface
|
||||
*
|
||||
* The given choice array must have the same array keys as the value array.
|
||||
*
|
||||
* @param array $choices The selectable choices
|
||||
* @param callable|null $value The callable for creating the value for a
|
||||
* choice. If `null` is passed, incrementing
|
||||
* integers are used as values
|
||||
* @param array|\Traversable $choices The selectable choices
|
||||
* @param callable|null $value The callable for creating the value
|
||||
* for a choice. If `null` is passed,
|
||||
* incrementing integers are used as
|
||||
* values
|
||||
*/
|
||||
public function __construct(array $choices, $value = null)
|
||||
public function __construct($choices, $value = null)
|
||||
{
|
||||
if (null !== $value && !is_callable($value)) {
|
||||
throw new UnexpectedTypeException($value, 'null or callable');
|
||||
}
|
||||
|
||||
$this->choices = $choices;
|
||||
$this->values = array();
|
||||
$this->valueCallback = $value;
|
||||
if ($choices instanceof \Traversable) {
|
||||
$choices = iterator_to_array($choices);
|
||||
}
|
||||
|
||||
if (null === $value) {
|
||||
$i = 0;
|
||||
foreach ($this->choices as $key => $choice) {
|
||||
$this->values[$key] = (string) $i++;
|
||||
}
|
||||
if (null !== $value) {
|
||||
// If a deterministic value generator was passed, use it later
|
||||
$this->valueCallback = $value;
|
||||
} else {
|
||||
foreach ($choices as $key => $choice) {
|
||||
$this->values[$key] = (string) call_user_func($value, $choice);
|
||||
}
|
||||
// Otherwise simply generate incrementing integers as values
|
||||
$i = 0;
|
||||
$value = function () use (&$i) {
|
||||
return $i++;
|
||||
};
|
||||
}
|
||||
|
||||
// If the choices are given as recursive array (i.e. with explicit
|
||||
// choice groups), flatten the array. The grouping information is needed
|
||||
// in the view only.
|
||||
$this->flatten($choices, $value, $choicesByValues, $keysByValues, $structuredValues);
|
||||
|
||||
$this->choices = $choicesByValues;
|
||||
$this->originalKeys = $keysByValues;
|
||||
$this->structuredValues = $structuredValues;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,7 +108,23 @@ class ArrayChoiceList implements ChoiceListInterface
|
||||
*/
|
||||
public function getValues()
|
||||
{
|
||||
return $this->values;
|
||||
return array_map('strval', array_keys($this->choices));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getStructuredValues()
|
||||
{
|
||||
return $this->structuredValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOriginalKeys()
|
||||
{
|
||||
return $this->originalKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,17 +135,8 @@ class ArrayChoiceList implements ChoiceListInterface
|
||||
$choices = array();
|
||||
|
||||
foreach ($values as $i => $givenValue) {
|
||||
foreach ($this->values as $j => $value) {
|
||||
if ($value !== (string) $givenValue) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$choices[$i] = $this->choices[$j];
|
||||
unset($values[$i]);
|
||||
|
||||
if (0 === count($values)) {
|
||||
break 2;
|
||||
}
|
||||
if (isset($this->choices[$givenValue])) {
|
||||
$choices[$i] = $this->choices[$givenValue];
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,28 +155,56 @@ class ArrayChoiceList implements ChoiceListInterface
|
||||
$givenValues = array();
|
||||
|
||||
foreach ($choices as $i => $givenChoice) {
|
||||
$givenValues[$i] = (string) call_user_func($this->valueCallback, $givenChoice);
|
||||
$givenValues[$i] = call_user_func($this->valueCallback, $givenChoice);
|
||||
}
|
||||
|
||||
return array_intersect($givenValues, $this->values);
|
||||
return array_intersect($givenValues, array_keys($this->choices));
|
||||
}
|
||||
|
||||
// Otherwise compare choices by identity
|
||||
foreach ($choices as $i => $givenChoice) {
|
||||
foreach ($this->choices as $j => $choice) {
|
||||
if ($choice !== $givenChoice) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$values[$i] = $this->values[$j];
|
||||
unset($choices[$i]);
|
||||
|
||||
if (0 === count($choices)) {
|
||||
break 2;
|
||||
foreach ($this->choices as $value => $choice) {
|
||||
if ($choice === $givenChoice) {
|
||||
$values[$i] = (string) $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens an array into the given output variables.
|
||||
*
|
||||
* @param array $choices The array to flatten
|
||||
* @param callable $value The callable for generating choice values
|
||||
* @param array $choicesByValues The flattened choices indexed by the
|
||||
* corresponding values
|
||||
* @param array $keysByValues The original keys indexed by the
|
||||
* corresponding values
|
||||
*
|
||||
* @internal Must not be used by user-land code
|
||||
*/
|
||||
protected function flatten(array $choices, $value, &$choicesByValues, &$keysByValues, &$structuredValues)
|
||||
{
|
||||
if (null === $choicesByValues) {
|
||||
$choicesByValues = array();
|
||||
$keysByValues = array();
|
||||
$structuredValues = array();
|
||||
}
|
||||
|
||||
foreach ($choices as $key => $choice) {
|
||||
if (is_array($choice)) {
|
||||
$this->flatten($choice, $value, $choicesByValues, $keysByValues, $structuredValues[$key]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$choiceValue = (string) call_user_func($value, $choice);
|
||||
$choicesByValues[$choiceValue] = $choice;
|
||||
$keysByValues[$choiceValue] = $key;
|
||||
$structuredValues[$key] = $choiceValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,6 +62,8 @@ class ArrayKeyChoiceList extends ArrayChoiceList
|
||||
* @return int|string The choice as PHP array key
|
||||
*
|
||||
* @throws InvalidArgumentException If the choice is not scalar
|
||||
*
|
||||
* @internal Must not be used outside this class
|
||||
*/
|
||||
public static function toArrayKey($choice)
|
||||
{
|
||||
@ -89,23 +91,27 @@ class ArrayKeyChoiceList extends ArrayChoiceList
|
||||
* If no values are given, the choices are cast to strings and used as
|
||||
* values.
|
||||
*
|
||||
* @param array $choices The selectable choices
|
||||
* @param callable $value The callable for creating the value for a
|
||||
* choice. If `null` is passed, the choices are
|
||||
* cast to strings and used as values
|
||||
* @param array|\Traversable $choices The selectable choices
|
||||
* @param callable $value The callable for creating the value
|
||||
* for a choice. If `null` is passed, the
|
||||
* choices are cast to strings and used
|
||||
* as values
|
||||
*
|
||||
* @throws InvalidArgumentException If the keys of the choices don't match
|
||||
* the keys of the values or if any of the
|
||||
* choices is not scalar
|
||||
*/
|
||||
public function __construct(array $choices, $value = null)
|
||||
public function __construct($choices, $value = null)
|
||||
{
|
||||
$choices = array_map(array(__CLASS__, 'toArrayKey'), $choices);
|
||||
|
||||
// If no values are given, use the choices as values
|
||||
// Since the choices are stored in the collection keys, i.e. they are
|
||||
// strings or integers, we are guaranteed to be able to convert them
|
||||
// to strings
|
||||
if (null === $value) {
|
||||
$value = function ($choice) {
|
||||
return (string) $choice;
|
||||
};
|
||||
|
||||
$this->useChoicesAsValues = true;
|
||||
}
|
||||
|
||||
@ -122,7 +128,7 @@ class ArrayKeyChoiceList extends ArrayChoiceList
|
||||
|
||||
// If the values are identical to the choices, so we can just return
|
||||
// them to improve performance a little bit
|
||||
return array_map(array(__CLASS__, 'toArrayKey'), array_intersect($values, $this->values));
|
||||
return array_map(array(__CLASS__, 'toArrayKey'), array_intersect($values, array_keys($this->choices)));
|
||||
}
|
||||
|
||||
return parent::getChoicesForValues($values);
|
||||
@ -143,4 +149,38 @@ class ArrayKeyChoiceList extends ArrayChoiceList
|
||||
|
||||
return parent::getValuesForChoices($choices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens and flips an array into the given output variable.
|
||||
*
|
||||
* @param array $choices The array to flatten
|
||||
* @param callable $value The callable for generating choice values
|
||||
* @param array $choicesByValues The flattened choices indexed by the
|
||||
* corresponding values
|
||||
* @param array $keysByValues The original keys indexed by the
|
||||
* corresponding values
|
||||
*
|
||||
* @internal Must not be used by user-land code
|
||||
*/
|
||||
protected function flatten(array $choices, $value, &$choicesByValues, &$keysByValues, &$structuredValues)
|
||||
{
|
||||
if (null === $choicesByValues) {
|
||||
$choicesByValues = array();
|
||||
$keysByValues = array();
|
||||
$structuredValues = array();
|
||||
}
|
||||
|
||||
foreach ($choices as $choice => $key) {
|
||||
if (is_array($key)) {
|
||||
$this->flatten($key, $value, $choicesByValues, $keysByValues, $structuredValues[$choice]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$choiceValue = (string) call_user_func($value, $choice);
|
||||
$choicesByValues[$choiceValue] = $choice;
|
||||
$keysByValues[$choiceValue] = $key;
|
||||
$structuredValues[$key] = $choiceValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,16 +14,13 @@ namespace Symfony\Component\Form\ChoiceList;
|
||||
/**
|
||||
* A list of choices that can be selected in a choice field.
|
||||
*
|
||||
* A choice list assigns string values to each of a list of choices. These
|
||||
* string values are displayed in the "value" attributes in HTML and submitted
|
||||
* back to the server.
|
||||
* A choice list assigns unique string values to each of a list of choices.
|
||||
* These string values are displayed in the "value" attributes in HTML and
|
||||
* submitted back to the server.
|
||||
*
|
||||
* The acceptable data types for the choices depend on the implementation.
|
||||
* Values must always be strings and (within the list) free of duplicates.
|
||||
*
|
||||
* The choices returned by {@link getChoices()} and the values returned by
|
||||
* {@link getValues()} must have the same array indices.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface ChoiceListInterface
|
||||
@ -31,23 +28,66 @@ interface ChoiceListInterface
|
||||
/**
|
||||
* Returns all selectable choices.
|
||||
*
|
||||
* The keys of the choices correspond to the keys of the values returned by
|
||||
* {@link getValues()}.
|
||||
*
|
||||
* @return array The selectable choices
|
||||
* @return array The selectable choices indexed by the corresponding values
|
||||
*/
|
||||
public function getChoices();
|
||||
|
||||
/**
|
||||
* Returns the values for the choices.
|
||||
*
|
||||
* The keys of the values correspond to the keys of the choices returned by
|
||||
* {@link getChoices()}.
|
||||
* The values are strings that do not contain duplicates.
|
||||
*
|
||||
* @return string[] The choice values
|
||||
*/
|
||||
public function getValues();
|
||||
|
||||
/**
|
||||
* Returns the values in the structure originally passed to the list.
|
||||
*
|
||||
* Contrary to {@link getValues()}, the result is indexed by the original
|
||||
* keys of the choices. If the original array contained nested arrays, these
|
||||
* nested arrays are represented here as well:
|
||||
*
|
||||
* $form->add('field', 'choice', array(
|
||||
* 'choices' => array(
|
||||
* 'Decided' => array('Yes' => true, 'No' => false),
|
||||
* 'Undecided' => array('Maybe' => null),
|
||||
* ),
|
||||
* ));
|
||||
*
|
||||
* In this example, the result of this method is:
|
||||
*
|
||||
* array(
|
||||
* 'Decided' => array('Yes' => '0', 'No' => '1'),
|
||||
* 'Undecided' => array('Maybe' => '2'),
|
||||
* )
|
||||
*
|
||||
* @return string[] The choice values
|
||||
*/
|
||||
public function getStructuredValues();
|
||||
|
||||
/**
|
||||
* Returns the original keys of the choices.
|
||||
*
|
||||
* The original keys are the keys of the choice array that was passed in the
|
||||
* "choice" option of the choice type. Note that this array may contain
|
||||
* duplicates if the "choice" option contained choice groups:
|
||||
*
|
||||
* $form->add('field', 'choice', array(
|
||||
* 'choices' => array(
|
||||
* 'Decided' => array(true, false),
|
||||
* 'Undecided' => array(null),
|
||||
* ),
|
||||
* ));
|
||||
*
|
||||
* In this example, the original key 0 appears twice, once for `true` and
|
||||
* once for `null`.
|
||||
*
|
||||
* @return int[]|string[] The original choice keys indexed by the
|
||||
* corresponding choice values
|
||||
*/
|
||||
public function getOriginalKeys();
|
||||
|
||||
/**
|
||||
* Returns the choices corresponding to the given values.
|
||||
*
|
||||
|
@ -65,6 +65,30 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface
|
||||
return hash('sha256', $namespace.':'.json_encode($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens an array into the given output variable.
|
||||
*
|
||||
* @param array $array The array to flatten
|
||||
* @param array $output The flattened output
|
||||
*
|
||||
* @internal Should not be used by user-land code
|
||||
*/
|
||||
private static function flatten(array $array, &$output)
|
||||
{
|
||||
if (null === $output) {
|
||||
$output = array();
|
||||
}
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
self::flatten($value, $output);
|
||||
continue;
|
||||
}
|
||||
|
||||
$output[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorates the given factory.
|
||||
*
|
||||
@ -100,7 +124,7 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface
|
||||
// We ignore the choice groups for caching. If two choice lists are
|
||||
// requested with the same choices, but a different grouping, the same
|
||||
// choice list is returned.
|
||||
DefaultChoiceListFactory::flatten($choices, $flatChoices);
|
||||
self::flatten($choices, $flatChoices);
|
||||
|
||||
$hash = self::generateHash(array($flatChoices, $value), 'fromChoices');
|
||||
|
||||
@ -129,7 +153,7 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface
|
||||
// We ignore the choice groups for caching. If two choice lists are
|
||||
// requested with the same choices, but a different grouping, the same
|
||||
// choice list is returned.
|
||||
DefaultChoiceListFactory::flattenFlipped($choices, $flatChoices);
|
||||
self::flatten($choices, $flatChoices);
|
||||
|
||||
$hash = self::generateHash(array($flatChoices, $value), 'fromFlippedChoices');
|
||||
|
||||
@ -161,7 +185,6 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface
|
||||
{
|
||||
// The input is not validated on purpose. This way, the decorated
|
||||
// factory may decide which input to accept and which not.
|
||||
|
||||
$hash = self::generateHash(array($list, $preferredChoices, $label, $index, $groupBy, $attr));
|
||||
|
||||
if (!isset($this->views[$hash])) {
|
||||
|
@ -98,25 +98,20 @@ interface ChoiceListFactoryInterface
|
||||
* The preferred choices can also be passed as array. Each choice that is
|
||||
* contained in that array will be marked as preferred.
|
||||
*
|
||||
* The groups can be passed as a multi-dimensional array. In that case, a
|
||||
* group will be created for each array entry containing a nested array.
|
||||
* For all other entries, the choice for the corresponding key will be
|
||||
* inserted at that position.
|
||||
*
|
||||
* The attributes can be passed as multi-dimensional array. The keys should
|
||||
* match the keys of the choices. The values should be arrays of HTML
|
||||
* attributes that should be added to the respective choice.
|
||||
*
|
||||
* @param ChoiceListInterface $list The choice list
|
||||
* @param null|array|callable $preferredChoices The preferred choices
|
||||
* @param null|callable $label The callable generating
|
||||
* the choice labels
|
||||
* @param null|callable $index The callable generating
|
||||
* the view indices
|
||||
* @param null|array|\Traversable|callable $groupBy The callable generating
|
||||
* the group names
|
||||
* @param null|array|callable $attr The callable generating
|
||||
* the HTML attributes
|
||||
* @param null|callable $label The callable generating the
|
||||
* choice labels
|
||||
* @param null|callable $index The callable generating the
|
||||
* view indices
|
||||
* @param null|callable $groupBy The callable generating the
|
||||
* group names
|
||||
* @param null|array|callable $attr The callable generating the
|
||||
* HTML attributes
|
||||
*
|
||||
* @return ChoiceListView The choice list view
|
||||
*/
|
||||
|
@ -15,11 +15,11 @@ use Symfony\Component\Form\ChoiceList\ArrayKeyChoiceList;
|
||||
use Symfony\Component\Form\ChoiceList\ArrayChoiceList;
|
||||
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
|
||||
use Symfony\Component\Form\ChoiceList\LazyChoiceList;
|
||||
use Symfony\Component\Form\ChoiceList\LegacyChoiceListAdapter;
|
||||
use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceListView;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
|
||||
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface as LegacyChoiceListInterface;
|
||||
use Symfony\Component\Form\Extension\Core\View\ChoiceView as LegacyChoiceView;
|
||||
|
||||
/**
|
||||
@ -29,72 +29,12 @@ use Symfony\Component\Form\Extension\Core\View\ChoiceView as LegacyChoiceView;
|
||||
*/
|
||||
class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
||||
{
|
||||
/**
|
||||
* Flattens an array into the given output variable.
|
||||
*
|
||||
* @param array $array The array to flatten
|
||||
* @param array $output The flattened output
|
||||
*
|
||||
* @internal Should not be used by user-land code
|
||||
*/
|
||||
public static function flatten(array $array, &$output)
|
||||
{
|
||||
if (null === $output) {
|
||||
$output = array();
|
||||
}
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
self::flatten($value, $output);
|
||||
continue;
|
||||
}
|
||||
|
||||
$output[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens and flips an array into the given output variable.
|
||||
*
|
||||
* During the flattening, the keys and values of the input array are
|
||||
* flipped.
|
||||
*
|
||||
* @param array $array The array to flatten
|
||||
* @param array $output The flattened output
|
||||
*
|
||||
* @internal Should not be used by user-land code
|
||||
*/
|
||||
public static function flattenFlipped(array $array, &$output)
|
||||
{
|
||||
if (null === $output) {
|
||||
$output = array();
|
||||
}
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
self::flattenFlipped($value, $output);
|
||||
continue;
|
||||
}
|
||||
|
||||
$output[$value] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createListFromChoices($choices, $value = null)
|
||||
{
|
||||
if ($choices instanceof \Traversable) {
|
||||
$choices = iterator_to_array($choices);
|
||||
}
|
||||
|
||||
// If the choices are given as recursive array (i.e. with explicit
|
||||
// choice groups), flatten the array. The grouping information is needed
|
||||
// in the view only.
|
||||
self::flatten($choices, $flatChoices);
|
||||
|
||||
return new ArrayChoiceList($flatChoices, $value);
|
||||
return new ArrayChoiceList($choices, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,26 +45,7 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
||||
*/
|
||||
public function createListFromFlippedChoices($choices, $value = null)
|
||||
{
|
||||
if ($choices instanceof \Traversable) {
|
||||
$choices = iterator_to_array($choices);
|
||||
}
|
||||
|
||||
// If the choices are given as recursive array (i.e. with explicit
|
||||
// choice groups), flatten the array. The grouping information is needed
|
||||
// in the view only.
|
||||
self::flattenFlipped($choices, $flatChoices);
|
||||
|
||||
// If no values are given, use the choices as values
|
||||
// Since the choices are stored in the collection keys, i.e. they are
|
||||
// strings or integers, we are guaranteed to be able to convert them
|
||||
// to strings
|
||||
if (null === $value) {
|
||||
$value = function ($choice) {
|
||||
return (string) $choice;
|
||||
};
|
||||
}
|
||||
|
||||
return new ArrayKeyChoiceList($flatChoices, $value);
|
||||
return new ArrayKeyChoiceList($choices, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -141,22 +62,24 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
||||
public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, $index = null, $groupBy = null, $attr = null)
|
||||
{
|
||||
// Backwards compatibility
|
||||
if ($list instanceof LegacyChoiceListInterface && empty($preferredChoices)
|
||||
if ($list instanceof LegacyChoiceListAdapter && empty($preferredChoices)
|
||||
&& null === $label && null === $index && null === $groupBy && null === $attr) {
|
||||
$mapToNonLegacyChoiceView = function (LegacyChoiceView $choiceView) {
|
||||
return new ChoiceView($choiceView->data, $choiceView->value, $choiceView->label);
|
||||
};
|
||||
|
||||
$adaptedList = $list->getAdaptedList();
|
||||
|
||||
return new ChoiceListView(
|
||||
array_map($mapToNonLegacyChoiceView, $list->getRemainingViews()),
|
||||
array_map($mapToNonLegacyChoiceView, $list->getPreferredViews())
|
||||
array_map($mapToNonLegacyChoiceView, $adaptedList->getRemainingViews()),
|
||||
array_map($mapToNonLegacyChoiceView, $adaptedList->getPreferredViews())
|
||||
);
|
||||
}
|
||||
|
||||
$preferredViews = array();
|
||||
$otherViews = array();
|
||||
$choices = $list->getChoices();
|
||||
$values = $list->getValues();
|
||||
$keys = $list->getOriginalKeys();
|
||||
|
||||
if (!is_callable($preferredChoices) && !empty($preferredChoices)) {
|
||||
$preferredChoices = function ($choice) use ($preferredChoices) {
|
||||
@ -169,36 +92,17 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
||||
$index = 0;
|
||||
}
|
||||
|
||||
// If $groupBy is not given, no grouping is done
|
||||
if (empty($groupBy)) {
|
||||
foreach ($choices as $key => $choice) {
|
||||
self::addChoiceView(
|
||||
$choice,
|
||||
$key,
|
||||
$label,
|
||||
$values,
|
||||
$index,
|
||||
$attr,
|
||||
$preferredChoices,
|
||||
$preferredViews,
|
||||
$otherViews
|
||||
);
|
||||
}
|
||||
|
||||
return new ChoiceListView($otherViews, $preferredViews);
|
||||
}
|
||||
|
||||
// If $groupBy is a callable, choices are added to the group with the
|
||||
// name returned by the callable. If the callable returns null, the
|
||||
// choice is not added to any group
|
||||
if (is_callable($groupBy)) {
|
||||
foreach ($choices as $key => $choice) {
|
||||
foreach ($choices as $value => $choice) {
|
||||
self::addChoiceViewGroupedBy(
|
||||
$groupBy,
|
||||
$choice,
|
||||
$key,
|
||||
(string) $value,
|
||||
$label,
|
||||
$values,
|
||||
$keys,
|
||||
$index,
|
||||
$attr,
|
||||
$preferredChoices,
|
||||
@ -207,13 +111,12 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// If $groupBy is passed as array, use that array as template for
|
||||
// constructing the groups
|
||||
// Otherwise use the original structure of the choices
|
||||
self::addChoiceViewsGroupedBy(
|
||||
$groupBy,
|
||||
$list->getStructuredValues(),
|
||||
$label,
|
||||
$choices,
|
||||
$values,
|
||||
$keys,
|
||||
$index,
|
||||
$attr,
|
||||
$preferredChoices,
|
||||
@ -239,15 +142,17 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
||||
return new ChoiceListView($otherViews, $preferredViews);
|
||||
}
|
||||
|
||||
private static function addChoiceView($choice, $key, $label, $values, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews)
|
||||
private static function addChoiceView($choice, $value, $label, $keys, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews)
|
||||
{
|
||||
$value = $values[$key];
|
||||
// $value may be an integer or a string, since it's stored in the array
|
||||
// keys. We want to guarantee it's a string though.
|
||||
$key = $keys[$value];
|
||||
$nextIndex = is_int($index) ? $index++ : call_user_func($index, $choice, $key, $value);
|
||||
|
||||
$view = new ChoiceView(
|
||||
$choice,
|
||||
$value,
|
||||
// If the labels are null, use the choice key by default
|
||||
// If the labels are null, use the original choice key by default
|
||||
null === $label ? (string) $key : (string) call_user_func($label, $choice, $key, $value),
|
||||
// The attributes may be a callable or a mapping from choice indices
|
||||
// to nested arrays
|
||||
@ -262,19 +167,19 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
||||
}
|
||||
}
|
||||
|
||||
private static function addChoiceViewsGroupedBy($groupBy, $label, $choices, $values, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews)
|
||||
private static function addChoiceViewsGroupedBy($groupBy, $label, $choices, $keys, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews)
|
||||
{
|
||||
foreach ($groupBy as $key => $content) {
|
||||
foreach ($groupBy as $key => $value) {
|
||||
// Add the contents of groups to new ChoiceGroupView instances
|
||||
if (is_array($content)) {
|
||||
if (is_array($value)) {
|
||||
$preferredViewsForGroup = array();
|
||||
$otherViewsForGroup = array();
|
||||
|
||||
self::addChoiceViewsGroupedBy(
|
||||
$content,
|
||||
$value,
|
||||
$label,
|
||||
$choices,
|
||||
$values,
|
||||
$keys,
|
||||
$index,
|
||||
$attr,
|
||||
$isPreferred,
|
||||
@ -295,10 +200,10 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
||||
|
||||
// Add ungrouped items directly
|
||||
self::addChoiceView(
|
||||
$choices[$key],
|
||||
$key,
|
||||
$choices[$value],
|
||||
$value,
|
||||
$label,
|
||||
$values,
|
||||
$keys,
|
||||
$index,
|
||||
$attr,
|
||||
$isPreferred,
|
||||
@ -308,17 +213,17 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
||||
}
|
||||
}
|
||||
|
||||
private static function addChoiceViewGroupedBy($groupBy, $choice, $key, $label, $values, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews)
|
||||
private static function addChoiceViewGroupedBy($groupBy, $choice, $value, $label, $keys, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews)
|
||||
{
|
||||
$groupLabel = call_user_func($groupBy, $choice, $key, $values[$key]);
|
||||
$groupLabel = call_user_func($groupBy, $choice, $keys[$value], $value);
|
||||
|
||||
if (null === $groupLabel) {
|
||||
// If the callable returns null, don't group the choice
|
||||
self::addChoiceView(
|
||||
$choice,
|
||||
$key,
|
||||
$value,
|
||||
$label,
|
||||
$values,
|
||||
$keys,
|
||||
$index,
|
||||
$attr,
|
||||
$isPreferred,
|
||||
@ -338,9 +243,9 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
||||
|
||||
self::addChoiceView(
|
||||
$choice,
|
||||
$key,
|
||||
$value,
|
||||
$label,
|
||||
$values,
|
||||
$keys,
|
||||
$index,
|
||||
$attr,
|
||||
$isPreferred,
|
||||
|
@ -98,8 +98,6 @@ class PropertyAccessDecorator implements ChoiceListFactoryInterface
|
||||
if (is_object($choice) || is_array($choice)) {
|
||||
return $accessor->getValue($choice, $value);
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -43,13 +43,6 @@ class LazyChoiceList implements ChoiceListInterface
|
||||
*/
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* Whether to use the value callback to compare choices.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $compareByValue;
|
||||
|
||||
/**
|
||||
* @var ChoiceListInterface|null
|
||||
*/
|
||||
@ -66,11 +59,10 @@ class LazyChoiceList implements ChoiceListInterface
|
||||
* @param null|callable $value The callable generating the choice
|
||||
* values
|
||||
*/
|
||||
public function __construct(ChoiceLoaderInterface $loader, $value = null, $compareByValue = false)
|
||||
public function __construct(ChoiceLoaderInterface $loader, $value = null)
|
||||
{
|
||||
$this->loader = $loader;
|
||||
$this->value = $value;
|
||||
$this->compareByValue = $compareByValue;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -97,6 +89,30 @@ class LazyChoiceList implements ChoiceListInterface
|
||||
return $this->loadedList->getValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getStructuredValues()
|
||||
{
|
||||
if (!$this->loadedList) {
|
||||
$this->loadedList = $this->loader->loadChoiceList($this->value);
|
||||
}
|
||||
|
||||
return $this->loadedList->getStructuredValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOriginalKeys()
|
||||
{
|
||||
if (!$this->loadedList) {
|
||||
$this->loadedList = $this->loader->loadChoiceList($this->value);
|
||||
}
|
||||
|
||||
return $this->loadedList->getOriginalKeys();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -0,0 +1,144 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface as LegacyChoiceListInterface;
|
||||
|
||||
/**
|
||||
* Adapts a legacy choice list implementation to {@link ChoiceListInterface}.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*
|
||||
* @deprecated Added for backwards compatibility in Symfony 2.7, to be
|
||||
* removed in Symfony 3.0.
|
||||
*/
|
||||
class LegacyChoiceListAdapter implements ChoiceListInterface
|
||||
{
|
||||
/**
|
||||
* @var LegacyChoiceListInterface
|
||||
*/
|
||||
private $adaptedList;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
private $choices;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
private $values;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
private $structuredValues;
|
||||
|
||||
/**
|
||||
* Adapts a legacy choice list to {@link ChoiceListInterface}.
|
||||
*
|
||||
* @param LegacyChoiceListInterface $adaptedList The adapted list
|
||||
*/
|
||||
public function __construct(LegacyChoiceListInterface $adaptedList)
|
||||
{
|
||||
$this->adaptedList = $adaptedList;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getChoices()
|
||||
{
|
||||
if (!$this->choices) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return $this->choices;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValues()
|
||||
{
|
||||
if (!$this->values) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getStructuredValues()
|
||||
{
|
||||
if (!$this->structuredValues) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return $this->structuredValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOriginalKeys()
|
||||
{
|
||||
if (!$this->structuredValues) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return array_flip($this->structuredValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getChoicesForValues(array $values)
|
||||
{
|
||||
return $this->adaptedList->getChoicesForValues($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValuesForChoices(array $choices)
|
||||
{
|
||||
return $this->adaptedList->getValuesForChoices($choices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the adapted choice list.
|
||||
*
|
||||
* @return LegacyChoiceListInterface The adapted list
|
||||
*/
|
||||
public function getAdaptedList()
|
||||
{
|
||||
return $this->adaptedList;
|
||||
}
|
||||
|
||||
private function initialize()
|
||||
{
|
||||
$this->choices = array();
|
||||
$this->values = array();
|
||||
$this->structuredValues = $this->adaptedList->getValues();
|
||||
|
||||
$innerChoices = $this->adaptedList->getChoices();
|
||||
|
||||
foreach ($innerChoices as $index => $choice) {
|
||||
$value = $this->structuredValues[$index];
|
||||
$this->values[] = $value;
|
||||
$this->choices[$value] = $choice;
|
||||
}
|
||||
}
|
||||
}
|
@ -11,9 +11,6 @@
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Core\ChoiceList;
|
||||
|
||||
use Symfony\Component\Form\ChoiceList\ChoiceListInterface as BaseChoiceListInterface;
|
||||
use Symfony\Component\Form\FormConfigBuilder;
|
||||
|
||||
/**
|
||||
* Contains choices that can be selected in a form field.
|
||||
*
|
||||
@ -30,10 +27,24 @@ use Symfony\Component\Form\FormConfigBuilder;
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*
|
||||
* @deprecated since version 2.7, to be removed in 3.0.
|
||||
* Use {@link BaseChoiceListInterface} instead.
|
||||
* Use {@link \Symfony\Component\Form\ChoiceList\ChoiceListInterface} instead.
|
||||
*/
|
||||
interface ChoiceListInterface extends BaseChoiceListInterface
|
||||
interface ChoiceListInterface
|
||||
{
|
||||
/**
|
||||
* Returns the list of choices.
|
||||
*
|
||||
* @return array The choices with their indices as keys
|
||||
*/
|
||||
public function getChoices();
|
||||
|
||||
/**
|
||||
* Returns the values for the choices.
|
||||
*
|
||||
* @return array The values with the corresponding choice indices as keys
|
||||
*/
|
||||
public function getValues();
|
||||
|
||||
/**
|
||||
* Returns the choice views of the preferred choices as nested array with
|
||||
* the choice groups as top-level keys.
|
||||
@ -84,6 +95,37 @@ interface ChoiceListInterface extends BaseChoiceListInterface
|
||||
*/
|
||||
public function getRemainingViews();
|
||||
|
||||
/**
|
||||
* Returns the choices corresponding to the given values.
|
||||
*
|
||||
* The choices can have any data type.
|
||||
*
|
||||
* The choices must be returned with the same keys and in the same order
|
||||
* as the corresponding values in the given array.
|
||||
*
|
||||
* @param array $values An array of choice values. Not existing values in
|
||||
* this array are ignored
|
||||
*
|
||||
* @return array An array of choices with ascending, 0-based numeric keys
|
||||
*/
|
||||
public function getChoicesForValues(array $values);
|
||||
|
||||
/**
|
||||
* Returns the values corresponding to the given choices.
|
||||
*
|
||||
* The values must be strings.
|
||||
*
|
||||
* The values must be returned with the same keys and in the same order
|
||||
* as the corresponding choices in the given array.
|
||||
*
|
||||
* @param array $choices An array of choices. Not existing choices in this
|
||||
* array are ignored
|
||||
*
|
||||
* @return array An array of choice values with ascending, 0-based numeric
|
||||
* keys
|
||||
*/
|
||||
public function getValuesForChoices(array $choices);
|
||||
|
||||
/**
|
||||
* Returns the indices corresponding to the given choices.
|
||||
*
|
||||
|
@ -13,6 +13,7 @@ namespace Symfony\Component\Form\Extension\Core\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator;
|
||||
use Symfony\Component\Form\ChoiceList\LegacyChoiceListAdapter;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
|
||||
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
|
||||
@ -27,6 +28,7 @@ use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Form\FormView;
|
||||
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface as LegacyChoiceListInterface;
|
||||
use Symfony\Component\Form\Extension\Core\EventListener\MergeCollectionListener;
|
||||
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer;
|
||||
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer;
|
||||
@ -259,6 +261,10 @@ class ChoiceType extends AbstractType
|
||||
if ($choiceList) {
|
||||
@trigger_error('The "choice_list" option is deprecated since version 2.7 and will be removed in 3.0. Use "choice_loader" instead.', E_USER_DEPRECATED);
|
||||
|
||||
if ($choiceList instanceof LegacyChoiceListInterface) {
|
||||
return new LegacyChoiceListAdapter($choiceList);
|
||||
}
|
||||
|
||||
return $choiceList;
|
||||
}
|
||||
|
||||
@ -338,7 +344,7 @@ class ChoiceType extends AbstractType
|
||||
$resolver->setNormalizer('placeholder', $placeholderNormalizer);
|
||||
$resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer);
|
||||
|
||||
$resolver->setAllowedTypes('choice_list', array('null', 'Symfony\Component\Form\ChoiceList\ChoiceListInterface'));
|
||||
$resolver->setAllowedTypes('choice_list', array('null', 'Symfony\Component\Form\ChoiceList\ChoiceListInterface', 'Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface'));
|
||||
$resolver->setAllowedTypes('choices', array('null', 'array', '\Traversable'));
|
||||
$resolver->setAllowedTypes('choice_translation_domain', array('null', 'bool', 'string'));
|
||||
$resolver->setAllowedTypes('choices_as_values', 'bool');
|
||||
|
@ -31,6 +31,16 @@ abstract class AbstractChoiceListTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
protected $values;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $structuredValues;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $keys;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
@ -71,25 +81,52 @@ abstract class AbstractChoiceListTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
protected $value4;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $key1;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $key2;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $key3;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $key4;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->list = $this->createChoiceList();
|
||||
|
||||
$this->choices = $this->getChoices();
|
||||
$choices = $this->getChoices();
|
||||
|
||||
$this->values = $this->getValues();
|
||||
$this->structuredValues = array_combine(array_keys($choices), $this->values);
|
||||
$this->choices = array_combine($this->values, $choices);
|
||||
$this->keys = array_combine($this->values, array_keys($choices));
|
||||
|
||||
// allow access to the individual entries without relying on their indices
|
||||
reset($this->choices);
|
||||
reset($this->values);
|
||||
reset($this->keys);
|
||||
|
||||
for ($i = 1; $i <= 4; ++$i) {
|
||||
$this->{'choice'.$i} = current($this->choices);
|
||||
$this->{'value'.$i} = current($this->values);
|
||||
$this->{'key'.$i} = current($this->keys);
|
||||
|
||||
next($this->choices);
|
||||
next($this->values);
|
||||
next($this->keys);
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,6 +140,16 @@ abstract class AbstractChoiceListTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame($this->values, $this->list->getValues());
|
||||
}
|
||||
|
||||
public function testGetStructuredValues()
|
||||
{
|
||||
$this->assertSame($this->values, $this->list->getStructuredValues());
|
||||
}
|
||||
|
||||
public function testGetOriginalKeys()
|
||||
{
|
||||
$this->assertSame($this->keys, $this->list->getOriginalKeys());
|
||||
}
|
||||
|
||||
public function testGetChoicesForValues()
|
||||
{
|
||||
$values = array($this->value1, $this->value2);
|
||||
|
@ -29,8 +29,6 @@ class ArrayChoiceListTest extends AbstractChoiceListTest
|
||||
|
||||
protected function createChoiceList()
|
||||
{
|
||||
$i = 0;
|
||||
|
||||
return new ArrayChoiceList($this->getChoices());
|
||||
}
|
||||
|
||||
@ -60,11 +58,31 @@ class ArrayChoiceListTest extends AbstractChoiceListTest
|
||||
|
||||
$choiceList = new ArrayChoiceList(array(2 => 'foo', 7 => 'bar', 10 => 'baz'), $callback);
|
||||
|
||||
$this->assertSame(array(2 => ':foo', 7 => ':bar', 10 => ':baz'), $choiceList->getValues());
|
||||
$this->assertSame(array(':foo', ':bar', ':baz'), $choiceList->getValues());
|
||||
$this->assertSame(array(':foo' => 'foo', ':bar' => 'bar', ':baz' => 'baz'), $choiceList->getChoices());
|
||||
$this->assertSame(array(':foo' => 2, ':bar' => 7, ':baz' => 10), $choiceList->getOriginalKeys());
|
||||
$this->assertSame(array(1 => 'foo', 2 => 'baz'), $choiceList->getChoicesForValues(array(1 => ':foo', 2 => ':baz')));
|
||||
$this->assertSame(array(1 => ':foo', 2 => ':baz'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => 'baz')));
|
||||
}
|
||||
|
||||
public function testCreateChoiceListWithGroupedChoices()
|
||||
{
|
||||
$choiceList = new ArrayChoiceList(array(
|
||||
'Group 1' => array('A' => 'a', 'B' => 'b'),
|
||||
'Group 2' => array('C' => 'c', 'D' => 'd'),
|
||||
));
|
||||
|
||||
$this->assertSame(array('0', '1', '2', '3'), $choiceList->getValues());
|
||||
$this->assertSame(array(
|
||||
'Group 1' => array('A' => '0', 'B' => '1'),
|
||||
'Group 2' => array('C' => '2', 'D' => '3'),
|
||||
), $choiceList->getStructuredValues());
|
||||
$this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd'), $choiceList->getChoices());
|
||||
$this->assertSame(array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D'), $choiceList->getOriginalKeys());
|
||||
$this->assertSame(array(1 => 'a', 2 => 'b'), $choiceList->getChoicesForValues(array(1 => '0', 2 => '1')));
|
||||
$this->assertSame(array(1 => '0', 2 => '1'), $choiceList->getValuesForChoices(array(1 => 'a', 2 => 'b')));
|
||||
}
|
||||
|
||||
public function testCompareChoicesByIdentityByDefault()
|
||||
{
|
||||
$callback = function ($choice) {
|
||||
|
@ -29,7 +29,7 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
||||
|
||||
protected function createChoiceList()
|
||||
{
|
||||
return new ArrayKeyChoiceList($this->getChoices());
|
||||
return new ArrayKeyChoiceList(array_flip($this->getChoices()));
|
||||
}
|
||||
|
||||
protected function getChoices()
|
||||
@ -44,9 +44,11 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
||||
|
||||
public function testUseChoicesAsValuesByDefault()
|
||||
{
|
||||
$list = new ArrayKeyChoiceList(array(1 => '', 3 => 0, 7 => '1', 10 => 1.23));
|
||||
$list = new ArrayKeyChoiceList(array('' => 'Empty', 0 => 'Zero', 1 => 'One', '1.23' => 'Float'));
|
||||
|
||||
$this->assertSame(array(1 => '', 3 => '0', 7 => '1', 10 => '1.23'), $list->getValues());
|
||||
$this->assertSame(array('', '0', '1', '1.23'), $list->getValues());
|
||||
$this->assertSame(array('' => '', 0 => 0, 1 => 1, '1.23' => '1.23'), $list->getChoices());
|
||||
$this->assertSame(array('' => 'Empty', 0 => 'Zero', 1 => 'One', '1.23' => 'Float'), $list->getOriginalKeys());
|
||||
}
|
||||
|
||||
public function testNoChoices()
|
||||
@ -102,33 +104,22 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
||||
public function provideConvertibleChoices()
|
||||
{
|
||||
return array(
|
||||
array(array(0), array(0)),
|
||||
array(array(1), array(1)),
|
||||
array(array('0'), array(0)),
|
||||
array(array('1'), array(1)),
|
||||
array(array('1.23'), array('1.23')),
|
||||
array(array('foobar'), array('foobar')),
|
||||
array(array(0 => 'Label'), array(0 => 0)),
|
||||
array(array(1 => 'Label'), array(1 => 1)),
|
||||
array(array('1.23' => 'Label'), array('1.23' => '1.23')),
|
||||
array(array('foobar' => 'Label'), array('foobar' => 'foobar')),
|
||||
// The default value of choice fields is NULL. It should be treated
|
||||
// like the empty value for this choice list type
|
||||
array(array(null), array('')),
|
||||
array(array(1.23), array('1.23')),
|
||||
array(array(null => 'Label'), array('' => '')),
|
||||
array(array('1.23' => 'Label'), array('1.23' => '1.23')),
|
||||
// Always cast booleans to 0 and 1, because:
|
||||
// array(true => 'Yes', false => 'No') === array(1 => 'Yes', 0 => 'No')
|
||||
// see ChoiceTypeTest::testSetDataSingleNonExpandedAcceptsBoolean
|
||||
array(array(true), array(1)),
|
||||
array(array(false), array(0)),
|
||||
array(array(true => 'Label'), array(1 => 1)),
|
||||
array(array(false => 'Label'), array(0 => 0)),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideInvalidChoices
|
||||
* @expectedException \Symfony\Component\Form\Exception\InvalidArgumentException
|
||||
*/
|
||||
public function testFailIfInvalidChoices(array $choices)
|
||||
{
|
||||
new ArrayKeyChoiceList($choices);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideInvalidChoices
|
||||
* @expectedException \Symfony\Component\Form\Exception\InvalidArgumentException
|
||||
@ -155,7 +146,7 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
||||
return $value;
|
||||
};
|
||||
|
||||
$list = new ArrayKeyChoiceList(array('choice'), $callback);
|
||||
$list = new ArrayKeyChoiceList(array('choice' => 'Label'), $callback);
|
||||
|
||||
$this->assertSame(array($converted), $list->getValues());
|
||||
}
|
||||
@ -169,15 +160,7 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
||||
array('1', '1'),
|
||||
array('1.23', '1.23'),
|
||||
array('foobar', 'foobar'),
|
||||
// The default value of choice fields is NULL. It should be treated
|
||||
// like the empty value for this choice list type
|
||||
array(null, ''),
|
||||
array(1.23, '1.23'),
|
||||
// Always cast booleans to 0 and 1, because:
|
||||
// array(true => 'Yes', false => 'No') === array(1 => 'Yes', 0 => 'No')
|
||||
// see ChoiceTypeTest::testSetDataSingleNonExpandedAcceptsBoolean
|
||||
array(true, '1'),
|
||||
array(false, ''),
|
||||
array('', ''),
|
||||
);
|
||||
}
|
||||
|
||||
@ -187,9 +170,11 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
||||
return ':'.$choice;
|
||||
};
|
||||
|
||||
$choiceList = new ArrayKeyChoiceList(array(2 => 'foo', 7 => 'bar', 10 => 'baz'), $callback);
|
||||
$choiceList = new ArrayKeyChoiceList(array('foo' => 'Foo', 'bar' => 'Bar', 'baz' => 'Baz'), $callback);
|
||||
|
||||
$this->assertSame(array(2 => ':foo', 7 => ':bar', 10 => ':baz'), $choiceList->getValues());
|
||||
$this->assertSame(array(':foo', ':bar', ':baz'), $choiceList->getValues());
|
||||
$this->assertSame(array(':foo' => 'foo', ':bar' => 'bar', ':baz' => 'baz'), $choiceList->getChoices());
|
||||
$this->assertSame(array(':foo' => 'Foo', ':bar' => 'Bar', ':baz' => 'Baz'), $choiceList->getOriginalKeys());
|
||||
$this->assertSame(array(1 => 'foo', 2 => 'baz'), $choiceList->getChoicesForValues(array(1 => ':foo', 2 => ':baz')));
|
||||
$this->assertSame(array(1 => ':foo', 2 => ':baz'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => 'baz')));
|
||||
}
|
||||
|
@ -204,8 +204,8 @@ class CachingFactoryDecoratorTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testCreateFromFlippedChoicesSameChoices($choice1, $choice2)
|
||||
{
|
||||
$choices1 = array($choice1);
|
||||
$choices2 = array($choice2);
|
||||
$choices1 = array($choice1 => 'A');
|
||||
$choices2 = array($choice2 => 'A');
|
||||
$list = new \stdClass();
|
||||
|
||||
$this->decoratedFactory->expects($this->once())
|
||||
@ -222,8 +222,8 @@ class CachingFactoryDecoratorTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testCreateFromFlippedChoicesDifferentChoices($choice1, $choice2)
|
||||
{
|
||||
$choices1 = array($choice1);
|
||||
$choices2 = array($choice2);
|
||||
$choices1 = array($choice1 => 'A');
|
||||
$choices2 = array($choice2 => 'A');
|
||||
$list1 = new \stdClass();
|
||||
$list2 = new \stdClass();
|
||||
|
||||
|
@ -15,6 +15,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\LegacyChoiceListAdapter;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceListView;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
|
||||
@ -199,7 +200,7 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
||||
array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D')
|
||||
);
|
||||
|
||||
$this->assertScalarListWithGeneratedValues($list);
|
||||
$this->assertScalarListWithChoiceValues($list);
|
||||
}
|
||||
|
||||
public function testCreateFromFlippedChoicesFlatTraversable()
|
||||
@ -208,7 +209,7 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
||||
new \ArrayIterator(array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D'))
|
||||
);
|
||||
|
||||
$this->assertScalarListWithGeneratedValues($list);
|
||||
$this->assertScalarListWithChoiceValues($list);
|
||||
}
|
||||
|
||||
public function testCreateFromFlippedChoicesFlatValuesAsCallable()
|
||||
@ -247,7 +248,7 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertScalarListWithGeneratedValues($list);
|
||||
$this->assertScalarListWithChoiceValues($list);
|
||||
}
|
||||
|
||||
public function testCreateFromFlippedChoicesGroupedTraversable()
|
||||
@ -259,7 +260,7 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
||||
))
|
||||
);
|
||||
|
||||
$this->assertScalarListWithGeneratedValues($list);
|
||||
$this->assertScalarListWithChoiceValues($list);
|
||||
}
|
||||
|
||||
public function testCreateFromFlippedChoicesGroupedValuesAsCallable()
|
||||
@ -523,33 +524,16 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertFlatViewWithCustomIndices($view);
|
||||
}
|
||||
|
||||
public function testCreateViewFlatGroupByAsArray()
|
||||
public function testCreateViewFlatGroupByOriginalStructure()
|
||||
{
|
||||
$view = $this->factory->createView(
|
||||
$this->list,
|
||||
array($this->obj2, $this->obj3),
|
||||
null, // label
|
||||
null, // index
|
||||
array(
|
||||
'Group 1' => array('A' => true, 'B' => true),
|
||||
'Group 2' => array('C' => true, 'D' => true),
|
||||
)
|
||||
);
|
||||
$list = new ArrayChoiceList(array(
|
||||
'Group 1' => array('A' => $this->obj1, 'B' => $this->obj2),
|
||||
'Group 2' => array('C' => $this->obj3, 'D' => $this->obj4),
|
||||
));
|
||||
|
||||
$this->assertGroupedView($view);
|
||||
}
|
||||
|
||||
public function testCreateViewFlatGroupByAsTraversable()
|
||||
{
|
||||
$view = $this->factory->createView(
|
||||
$this->list,
|
||||
array($this->obj2, $this->obj3),
|
||||
null, // label
|
||||
null, // index
|
||||
new \ArrayIterator(array(
|
||||
'Group 1' => array('A' => true, 'B' => true),
|
||||
'Group 2' => array('C' => true, 'D' => true),
|
||||
))
|
||||
$list,
|
||||
array($this->obj2, $this->obj3)
|
||||
);
|
||||
|
||||
$this->assertGroupedView($view);
|
||||
@ -592,8 +576,7 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
||||
null, // label
|
||||
null, // index
|
||||
function ($object) use ($obj1, $obj2) {
|
||||
return $obj1 === $object || $obj2 === $object ? 'Group 1'
|
||||
: 'Group 2';
|
||||
return $obj1 === $object || $obj2 === $object ? 'Group 1' : 'Group 2';
|
||||
}
|
||||
);
|
||||
|
||||
@ -749,78 +732,86 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
||||
->method('getRemainingViews')
|
||||
->will($this->returnValue($other));
|
||||
|
||||
$view = $this->factory->createView($list);
|
||||
$view = $this->factory->createView(new LegacyChoiceListAdapter($list));
|
||||
|
||||
$this->assertEquals(array(new ChoiceView('y', 'y', 'Other')), $view->choices);
|
||||
$this->assertEquals(array(new ChoiceView('x', 'x', 'Preferred')), $view->preferredChoices);
|
||||
}
|
||||
|
||||
private function assertScalarListWithGeneratedValues(ChoiceListInterface $list)
|
||||
private function assertScalarListWithChoiceValues(ChoiceListInterface $list)
|
||||
{
|
||||
$this->assertSame(array('a', 'b', 'c', 'd'), $list->getValues());
|
||||
|
||||
$this->assertSame(array(
|
||||
'A' => 'a',
|
||||
'B' => 'b',
|
||||
'C' => 'c',
|
||||
'D' => 'd',
|
||||
'a' => 'a',
|
||||
'b' => 'b',
|
||||
'c' => 'c',
|
||||
'd' => 'd',
|
||||
), $list->getChoices());
|
||||
|
||||
$this->assertSame(array(
|
||||
'A' => 'a',
|
||||
'B' => 'b',
|
||||
'C' => 'c',
|
||||
'D' => 'd',
|
||||
), $list->getValues());
|
||||
'a' => 'A',
|
||||
'b' => 'B',
|
||||
'c' => 'C',
|
||||
'd' => 'D',
|
||||
), $list->getOriginalKeys());
|
||||
}
|
||||
|
||||
private function assertObjectListWithGeneratedValues(ChoiceListInterface $list)
|
||||
{
|
||||
$this->assertSame(array('0', '1', '2', '3'), $list->getValues());
|
||||
|
||||
$this->assertSame(array(
|
||||
'A' => $this->obj1,
|
||||
'B' => $this->obj2,
|
||||
'C' => $this->obj3,
|
||||
'D' => $this->obj4,
|
||||
0 => $this->obj1,
|
||||
1 => $this->obj2,
|
||||
2 => $this->obj3,
|
||||
3 => $this->obj4,
|
||||
), $list->getChoices());
|
||||
|
||||
$this->assertSame(array(
|
||||
'A' => '0',
|
||||
'B' => '1',
|
||||
'C' => '2',
|
||||
'D' => '3',
|
||||
), $list->getValues());
|
||||
0 => 'A',
|
||||
1 => 'B',
|
||||
2 => 'C',
|
||||
3 => 'D',
|
||||
), $list->getOriginalKeys());
|
||||
}
|
||||
|
||||
private function assertScalarListWithCustomValues(ChoiceListInterface $list)
|
||||
{
|
||||
$this->assertSame(array('a', 'b', '1', '2'), $list->getValues());
|
||||
|
||||
$this->assertSame(array(
|
||||
'A' => 'a',
|
||||
'B' => 'b',
|
||||
'C' => 'c',
|
||||
'D' => 'd',
|
||||
'a' => 'a',
|
||||
'b' => 'b',
|
||||
1 => 'c',
|
||||
2 => 'd',
|
||||
), $list->getChoices());
|
||||
|
||||
$this->assertSame(array(
|
||||
'A' => 'a',
|
||||
'B' => 'b',
|
||||
'C' => '1',
|
||||
'D' => '2',
|
||||
), $list->getValues());
|
||||
'a' => 'A',
|
||||
'b' => 'B',
|
||||
1 => 'C',
|
||||
2 => 'D',
|
||||
), $list->getOriginalKeys());
|
||||
}
|
||||
|
||||
private function assertObjectListWithCustomValues(ChoiceListInterface $list)
|
||||
{
|
||||
$this->assertSame(array('a', 'b', '1', '2'), $list->getValues());
|
||||
|
||||
$this->assertSame(array(
|
||||
'A' => $this->obj1,
|
||||
'B' => $this->obj2,
|
||||
'C' => $this->obj3,
|
||||
'D' => $this->obj4,
|
||||
'a' => $this->obj1,
|
||||
'b' => $this->obj2,
|
||||
1 => $this->obj3,
|
||||
2 => $this->obj4,
|
||||
), $list->getChoices());
|
||||
|
||||
$this->assertSame(array(
|
||||
'A' => 'a',
|
||||
'B' => 'b',
|
||||
'C' => '1',
|
||||
'D' => '2',
|
||||
), $list->getValues());
|
||||
'a' => 'A',
|
||||
'b' => 'B',
|
||||
1 => 'C',
|
||||
2 => 'D',
|
||||
), $list->getOriginalKeys());
|
||||
}
|
||||
|
||||
private function assertFlatView($view)
|
||||
|
@ -73,6 +73,36 @@ class LazyChoiceListTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame('RESULT', $this->list->getValues());
|
||||
}
|
||||
|
||||
public function testGetStructuredValuesLoadsInnerListOnFirstCall()
|
||||
{
|
||||
$this->loader->expects($this->once())
|
||||
->method('loadChoiceList')
|
||||
->with($this->value)
|
||||
->will($this->returnValue($this->innerList));
|
||||
|
||||
$this->innerList->expects($this->exactly(2))
|
||||
->method('getStructuredValues')
|
||||
->will($this->returnValue('RESULT'));
|
||||
|
||||
$this->assertSame('RESULT', $this->list->getStructuredValues());
|
||||
$this->assertSame('RESULT', $this->list->getStructuredValues());
|
||||
}
|
||||
|
||||
public function testGetOriginalKeysLoadsInnerListOnFirstCall()
|
||||
{
|
||||
$this->loader->expects($this->once())
|
||||
->method('loadChoiceList')
|
||||
->with($this->value)
|
||||
->will($this->returnValue($this->innerList));
|
||||
|
||||
$this->innerList->expects($this->exactly(2))
|
||||
->method('getOriginalKeys')
|
||||
->will($this->returnValue('RESULT'));
|
||||
|
||||
$this->assertSame('RESULT', $this->list->getOriginalKeys());
|
||||
$this->assertSame('RESULT', $this->list->getOriginalKeys());
|
||||
}
|
||||
|
||||
public function testGetChoicesForValuesForwardsCallIfListNotLoaded()
|
||||
{
|
||||
$this->loader->expects($this->exactly(2))
|
||||
|
@ -0,0 +1,110 @@
|
||||
<?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\Tests\ChoiceList;
|
||||
|
||||
use Symfony\Component\Form\ChoiceList\LegacyChoiceListAdapter;
|
||||
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class LegacyChoiceListAdapterTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var LegacyChoiceListAdapter
|
||||
*/
|
||||
private $list;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject|ChoiceListInterface
|
||||
*/
|
||||
private $adaptedList;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->adaptedList = $this->getMock('Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface');
|
||||
$this->list = new LegacyChoiceListAdapter($this->adaptedList);
|
||||
}
|
||||
|
||||
public function testGetChoices()
|
||||
{
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getChoices')
|
||||
->willReturn(array(1 => 'a', 4 => 'b', 7 => 'c'));
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getValues')
|
||||
->willReturn(array(1 => ':a', 4 => ':b', 7 => ':c'));
|
||||
|
||||
$this->assertSame(array(':a' => 'a', ':b' => 'b', ':c' => 'c'), $this->list->getChoices());
|
||||
}
|
||||
|
||||
public function testGetValues()
|
||||
{
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getChoices')
|
||||
->willReturn(array(1 => 'a', 4 => 'b', 7 => 'c'));
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getValues')
|
||||
->willReturn(array(1 => ':a', 4 => ':b', 7 => ':c'));
|
||||
|
||||
$this->assertSame(array(':a', ':b', ':c'), $this->list->getValues());
|
||||
}
|
||||
|
||||
public function testGetStructuredValues()
|
||||
{
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getChoices')
|
||||
->willReturn(array(1 => 'a', 4 => 'b', 7 => 'c'));
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getValues')
|
||||
->willReturn(array(1 => ':a', 4 => ':b', 7 => ':c'));
|
||||
|
||||
$this->assertSame(array(1 => ':a', 4 => ':b', 7 => ':c'), $this->list->getStructuredValues());
|
||||
}
|
||||
|
||||
public function testGetOriginalKeys()
|
||||
{
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getChoices')
|
||||
->willReturn(array(1 => 'a', 4 => 'b', 7 => 'c'));
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getValues')
|
||||
->willReturn(array(1 => ':a', 4 => ':b', 7 => ':c'));
|
||||
|
||||
$this->assertSame(array(':a' => 1, ':b' => 4, ':c' => 7), $this->list->getOriginalKeys());
|
||||
}
|
||||
|
||||
public function testGetChoicesForValues()
|
||||
{
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getChoicesForValues')
|
||||
->with(array(1 => ':a', 4 => ':b', 7 => ':c'))
|
||||
->willReturn(array(1 => 'a', 4 => 'b', 7 => 'c'));
|
||||
|
||||
$this->assertSame(array(1 => 'a', 4 => 'b', 7 => 'c'), $this->list->getChoicesForValues(array(1 => ':a', 4 => ':b', 7 => ':c')));
|
||||
}
|
||||
|
||||
public function testGetValuesForChoices()
|
||||
{
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getValuesForChoices')
|
||||
->with(array(1 => 'a', 4 => 'b', 7 => 'c'))
|
||||
->willReturn(array(1 => ':a', 4 => ':b', 7 => ':c'));
|
||||
|
||||
$this->assertSame(array(1 => ':a', 4 => ':b', 7 => ':c'), $this->list->getValuesForChoices(array(1 => 'a', 4 => 'b', 7 => 'c')));
|
||||
}
|
||||
|
||||
public function testGetAdaptedList()
|
||||
{
|
||||
$this->assertSame($this->adaptedList, $this->list->getAdaptedList());
|
||||
}
|
||||
}
|
@ -11,9 +11,9 @@
|
||||
|
||||
namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
|
||||
|
||||
use Symfony\Component\Form\ChoiceList\ArrayKeyChoiceList;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\Extension\Core\EventListener\FixRadioInputListener;
|
||||
use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
@ -26,7 +26,7 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->choiceList = new SimpleChoiceList(array('' => 'Empty', 0 => 'A', 1 => 'B'));
|
||||
$this->choiceList = new ArrayKeyChoiceList(array('' => 'Empty', 0 => 'A', 1 => 'B'));
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
@ -45,7 +45,6 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase
|
||||
$listener = new FixRadioInputListener($this->choiceList, true);
|
||||
$listener->preSubmit($event);
|
||||
|
||||
// Indices in SimpleChoiceList are zero-based generated integers
|
||||
$this->assertEquals(array(2 => '1'), $event->getData());
|
||||
}
|
||||
|
||||
@ -58,7 +57,6 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase
|
||||
$listener = new FixRadioInputListener($this->choiceList, true);
|
||||
$listener->preSubmit($event);
|
||||
|
||||
// Indices in SimpleChoiceList are zero-based generated integers
|
||||
$this->assertEquals(array(1 => '0'), $event->getData());
|
||||
}
|
||||
|
||||
@ -71,13 +69,12 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase
|
||||
$listener = new FixRadioInputListener($this->choiceList, true);
|
||||
$listener->preSubmit($event);
|
||||
|
||||
// Indices in SimpleChoiceList are zero-based generated integers
|
||||
$this->assertEquals(array(0 => ''), $event->getData());
|
||||
}
|
||||
|
||||
public function testConvertEmptyStringToPlaceholderIfNotFound()
|
||||
{
|
||||
$list = new SimpleChoiceList(array(0 => 'A', 1 => 'B'));
|
||||
$list = new ArrayKeyChoiceList(array(0 => 'A', 1 => 'B'));
|
||||
|
||||
$data = '';
|
||||
$form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
|
||||
@ -91,7 +88,7 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testDontConvertEmptyStringToPlaceholderIfNoPlaceholderUsed()
|
||||
{
|
||||
$list = new SimpleChoiceList(array(0 => 'A', 1 => 'B'));
|
||||
$list = new ArrayKeyChoiceList(array(0 => 'A', 1 => 'B'));
|
||||
|
||||
$data = '';
|
||||
$form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
|
||||
|
@ -186,6 +186,32 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
|
||||
}
|
||||
}
|
||||
|
||||
public function testExpandedChoicesOptionsAreFlattenedObjectChoices()
|
||||
{
|
||||
$obj1 = (object) array('id' => 1, 'name' => 'Bernhard');
|
||||
$obj2 = (object) array('id' => 2, 'name' => 'Fabien');
|
||||
$obj3 = (object) array('id' => 3, 'name' => 'Kris');
|
||||
$obj4 = (object) array('id' => 4, 'name' => 'Jon');
|
||||
$obj5 = (object) array('id' => 5, 'name' => 'Roman');
|
||||
|
||||
$form = $this->factory->create('choice', null, array(
|
||||
'expanded' => true,
|
||||
'choices' => array(
|
||||
'Symfony' => array($obj1, $obj2, $obj3),
|
||||
'Doctrine' => array($obj4, $obj5),
|
||||
),
|
||||
'choices_as_values' => true,
|
||||
'choice_name' => 'id',
|
||||
));
|
||||
|
||||
$this->assertSame(5, $form->count(), 'Each nested choice should become a new field, not the groups');
|
||||
$this->assertTrue($form->has(1));
|
||||
$this->assertTrue($form->has(2));
|
||||
$this->assertTrue($form->has(3));
|
||||
$this->assertTrue($form->has(4));
|
||||
$this->assertTrue($form->has(5));
|
||||
}
|
||||
|
||||
public function testExpandedCheckboxesAreNeverRequired()
|
||||
{
|
||||
$form = $this->factory->create('choice', null, array(
|
||||
|
Reference in New Issue
Block a user