[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
|
* @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.
|
* 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.
|
* The given choice array must have the same array keys as the value array.
|
||||||
*
|
*
|
||||||
* @param array $choices The selectable choices
|
* @param array|\Traversable $choices The selectable choices
|
||||||
* @param callable|null $value The callable for creating the value for a
|
* @param callable|null $value The callable for creating the value
|
||||||
* choice. If `null` is passed, incrementing
|
* for a choice. If `null` is passed,
|
||||||
* integers are used as values
|
* 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)) {
|
if (null !== $value && !is_callable($value)) {
|
||||||
throw new UnexpectedTypeException($value, 'null or callable');
|
throw new UnexpectedTypeException($value, 'null or callable');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->choices = $choices;
|
if ($choices instanceof \Traversable) {
|
||||||
$this->values = array();
|
$choices = iterator_to_array($choices);
|
||||||
$this->valueCallback = $value;
|
|
||||||
|
|
||||||
if (null === $value) {
|
|
||||||
$i = 0;
|
|
||||||
foreach ($this->choices as $key => $choice) {
|
|
||||||
$this->values[$key] = (string) $i++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
foreach ($choices as $key => $choice) {
|
|
||||||
$this->values[$key] = (string) call_user_func($value, $choice);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (null !== $value) {
|
||||||
|
// If a deterministic value generator was passed, use it later
|
||||||
|
$this->valueCallback = $value;
|
||||||
|
} else {
|
||||||
|
// 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()
|
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();
|
$choices = array();
|
||||||
|
|
||||||
foreach ($values as $i => $givenValue) {
|
foreach ($values as $i => $givenValue) {
|
||||||
foreach ($this->values as $j => $value) {
|
if (isset($this->choices[$givenValue])) {
|
||||||
if ($value !== (string) $givenValue) {
|
$choices[$i] = $this->choices[$givenValue];
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$choices[$i] = $this->choices[$j];
|
|
||||||
unset($values[$i]);
|
|
||||||
|
|
||||||
if (0 === count($values)) {
|
|
||||||
break 2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,28 +155,56 @@ class ArrayChoiceList implements ChoiceListInterface
|
|||||||
$givenValues = array();
|
$givenValues = array();
|
||||||
|
|
||||||
foreach ($choices as $i => $givenChoice) {
|
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
|
// Otherwise compare choices by identity
|
||||||
foreach ($choices as $i => $givenChoice) {
|
foreach ($choices as $i => $givenChoice) {
|
||||||
foreach ($this->choices as $j => $choice) {
|
foreach ($this->choices as $value => $choice) {
|
||||||
if ($choice !== $givenChoice) {
|
if ($choice === $givenChoice) {
|
||||||
continue;
|
$values[$i] = (string) $value;
|
||||||
}
|
break;
|
||||||
|
|
||||||
$values[$i] = $this->values[$j];
|
|
||||||
unset($choices[$i]);
|
|
||||||
|
|
||||||
if (0 === count($choices)) {
|
|
||||||
break 2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $values;
|
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
|
* @return int|string The choice as PHP array key
|
||||||
*
|
*
|
||||||
* @throws InvalidArgumentException If the choice is not scalar
|
* @throws InvalidArgumentException If the choice is not scalar
|
||||||
|
*
|
||||||
|
* @internal Must not be used outside this class
|
||||||
*/
|
*/
|
||||||
public static function toArrayKey($choice)
|
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
|
* If no values are given, the choices are cast to strings and used as
|
||||||
* values.
|
* values.
|
||||||
*
|
*
|
||||||
* @param array $choices The selectable choices
|
* @param array|\Traversable $choices The selectable choices
|
||||||
* @param callable $value The callable for creating the value for a
|
* @param callable $value The callable for creating the value
|
||||||
* choice. If `null` is passed, the choices are
|
* for a choice. If `null` is passed, the
|
||||||
* cast to strings and used as values
|
* choices are cast to strings and used
|
||||||
|
* as values
|
||||||
*
|
*
|
||||||
* @throws InvalidArgumentException If the keys of the choices don't match
|
* @throws InvalidArgumentException If the keys of the choices don't match
|
||||||
* the keys of the values or if any of the
|
* the keys of the values or if any of the
|
||||||
* choices is not scalar
|
* 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) {
|
if (null === $value) {
|
||||||
$value = function ($choice) {
|
$value = function ($choice) {
|
||||||
return (string) $choice;
|
return (string) $choice;
|
||||||
};
|
};
|
||||||
|
|
||||||
$this->useChoicesAsValues = true;
|
$this->useChoicesAsValues = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +128,7 @@ class ArrayKeyChoiceList extends ArrayChoiceList
|
|||||||
|
|
||||||
// If the values are identical to the choices, so we can just return
|
// If the values are identical to the choices, so we can just return
|
||||||
// them to improve performance a little bit
|
// 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);
|
return parent::getChoicesForValues($values);
|
||||||
@ -143,4 +149,38 @@ class ArrayKeyChoiceList extends ArrayChoiceList
|
|||||||
|
|
||||||
return parent::getValuesForChoices($choices);
|
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 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
|
* A choice list assigns unique string values to each of a list of choices.
|
||||||
* string values are displayed in the "value" attributes in HTML and submitted
|
* These string values are displayed in the "value" attributes in HTML and
|
||||||
* back to the server.
|
* submitted back to the server.
|
||||||
*
|
*
|
||||||
* The acceptable data types for the choices depend on the implementation.
|
* The acceptable data types for the choices depend on the implementation.
|
||||||
* Values must always be strings and (within the list) free of duplicates.
|
* 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>
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
*/
|
*/
|
||||||
interface ChoiceListInterface
|
interface ChoiceListInterface
|
||||||
@ -31,23 +28,66 @@ interface ChoiceListInterface
|
|||||||
/**
|
/**
|
||||||
* Returns all selectable choices.
|
* Returns all selectable choices.
|
||||||
*
|
*
|
||||||
* The keys of the choices correspond to the keys of the values returned by
|
* @return array The selectable choices indexed by the corresponding values
|
||||||
* {@link getValues()}.
|
|
||||||
*
|
|
||||||
* @return array The selectable choices
|
|
||||||
*/
|
*/
|
||||||
public function getChoices();
|
public function getChoices();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the values for the choices.
|
* Returns the values for the choices.
|
||||||
*
|
*
|
||||||
* The keys of the values correspond to the keys of the choices returned by
|
* The values are strings that do not contain duplicates.
|
||||||
* {@link getChoices()}.
|
|
||||||
*
|
*
|
||||||
* @return string[] The choice values
|
* @return string[] The choice values
|
||||||
*/
|
*/
|
||||||
public function getValues();
|
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.
|
* Returns the choices corresponding to the given values.
|
||||||
*
|
*
|
||||||
|
@ -65,6 +65,30 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface
|
|||||||
return hash('sha256', $namespace.':'.json_encode($value));
|
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.
|
* Decorates the given factory.
|
||||||
*
|
*
|
||||||
@ -100,7 +124,7 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface
|
|||||||
// We ignore the choice groups for caching. If two choice lists are
|
// We ignore the choice groups for caching. If two choice lists are
|
||||||
// requested with the same choices, but a different grouping, the same
|
// requested with the same choices, but a different grouping, the same
|
||||||
// choice list is returned.
|
// choice list is returned.
|
||||||
DefaultChoiceListFactory::flatten($choices, $flatChoices);
|
self::flatten($choices, $flatChoices);
|
||||||
|
|
||||||
$hash = self::generateHash(array($flatChoices, $value), 'fromChoices');
|
$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
|
// We ignore the choice groups for caching. If two choice lists are
|
||||||
// requested with the same choices, but a different grouping, the same
|
// requested with the same choices, but a different grouping, the same
|
||||||
// choice list is returned.
|
// choice list is returned.
|
||||||
DefaultChoiceListFactory::flattenFlipped($choices, $flatChoices);
|
self::flatten($choices, $flatChoices);
|
||||||
|
|
||||||
$hash = self::generateHash(array($flatChoices, $value), 'fromFlippedChoices');
|
$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
|
// The input is not validated on purpose. This way, the decorated
|
||||||
// factory may decide which input to accept and which not.
|
// factory may decide which input to accept and which not.
|
||||||
|
|
||||||
$hash = self::generateHash(array($list, $preferredChoices, $label, $index, $groupBy, $attr));
|
$hash = self::generateHash(array($list, $preferredChoices, $label, $index, $groupBy, $attr));
|
||||||
|
|
||||||
if (!isset($this->views[$hash])) {
|
if (!isset($this->views[$hash])) {
|
||||||
|
@ -69,7 +69,7 @@ interface ChoiceListFactoryInterface
|
|||||||
* argument.
|
* argument.
|
||||||
*
|
*
|
||||||
* @param ChoiceLoaderInterface $loader The choice loader
|
* @param ChoiceLoaderInterface $loader The choice loader
|
||||||
* @param null|callable $value The callable generating the choice
|
* @param null|callable $value The callable generating the choice
|
||||||
* values
|
* values
|
||||||
*
|
*
|
||||||
* @return ChoiceListInterface The choice list
|
* @return ChoiceListInterface The choice list
|
||||||
@ -98,25 +98,20 @@ interface ChoiceListFactoryInterface
|
|||||||
* The preferred choices can also be passed as array. Each choice that is
|
* The preferred choices can also be passed as array. Each choice that is
|
||||||
* contained in that array will be marked as preferred.
|
* 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
|
* 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
|
* match the keys of the choices. The values should be arrays of HTML
|
||||||
* attributes that should be added to the respective choice.
|
* attributes that should be added to the respective choice.
|
||||||
*
|
*
|
||||||
* @param ChoiceListInterface $list The choice list
|
* @param ChoiceListInterface $list The choice list
|
||||||
* @param null|array|callable $preferredChoices The preferred choices
|
* @param null|array|callable $preferredChoices The preferred choices
|
||||||
* @param null|callable $label The callable generating
|
* @param null|callable $label The callable generating the
|
||||||
* the choice labels
|
* choice labels
|
||||||
* @param null|callable $index The callable generating
|
* @param null|callable $index The callable generating the
|
||||||
* the view indices
|
* view indices
|
||||||
* @param null|array|\Traversable|callable $groupBy The callable generating
|
* @param null|callable $groupBy The callable generating the
|
||||||
* the group names
|
* group names
|
||||||
* @param null|array|callable $attr The callable generating
|
* @param null|array|callable $attr The callable generating the
|
||||||
* the HTML attributes
|
* HTML attributes
|
||||||
*
|
*
|
||||||
* @return ChoiceListView The choice list view
|
* @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\ArrayChoiceList;
|
||||||
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
|
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
|
||||||
use Symfony\Component\Form\ChoiceList\LazyChoiceList;
|
use Symfony\Component\Form\ChoiceList\LazyChoiceList;
|
||||||
|
use Symfony\Component\Form\ChoiceList\LegacyChoiceListAdapter;
|
||||||
use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface;
|
use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface;
|
||||||
use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
|
use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
|
||||||
use Symfony\Component\Form\ChoiceList\View\ChoiceListView;
|
use Symfony\Component\Form\ChoiceList\View\ChoiceListView;
|
||||||
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
|
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;
|
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
|
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}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function createListFromChoices($choices, $value = null)
|
public function createListFromChoices($choices, $value = null)
|
||||||
{
|
{
|
||||||
if ($choices instanceof \Traversable) {
|
return new ArrayChoiceList($choices, $value);
|
||||||
$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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -105,26 +45,7 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
|||||||
*/
|
*/
|
||||||
public function createListFromFlippedChoices($choices, $value = null)
|
public function createListFromFlippedChoices($choices, $value = null)
|
||||||
{
|
{
|
||||||
if ($choices instanceof \Traversable) {
|
return new ArrayKeyChoiceList($choices, $value);
|
||||||
$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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -141,22 +62,24 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
|||||||
public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, $index = null, $groupBy = null, $attr = null)
|
public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, $index = null, $groupBy = null, $attr = null)
|
||||||
{
|
{
|
||||||
// Backwards compatibility
|
// Backwards compatibility
|
||||||
if ($list instanceof LegacyChoiceListInterface && empty($preferredChoices)
|
if ($list instanceof LegacyChoiceListAdapter && empty($preferredChoices)
|
||||||
&& null === $label && null === $index && null === $groupBy && null === $attr) {
|
&& null === $label && null === $index && null === $groupBy && null === $attr) {
|
||||||
$mapToNonLegacyChoiceView = function (LegacyChoiceView $choiceView) {
|
$mapToNonLegacyChoiceView = function (LegacyChoiceView $choiceView) {
|
||||||
return new ChoiceView($choiceView->data, $choiceView->value, $choiceView->label);
|
return new ChoiceView($choiceView->data, $choiceView->value, $choiceView->label);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$adaptedList = $list->getAdaptedList();
|
||||||
|
|
||||||
return new ChoiceListView(
|
return new ChoiceListView(
|
||||||
array_map($mapToNonLegacyChoiceView, $list->getRemainingViews()),
|
array_map($mapToNonLegacyChoiceView, $adaptedList->getRemainingViews()),
|
||||||
array_map($mapToNonLegacyChoiceView, $list->getPreferredViews())
|
array_map($mapToNonLegacyChoiceView, $adaptedList->getPreferredViews())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$preferredViews = array();
|
$preferredViews = array();
|
||||||
$otherViews = array();
|
$otherViews = array();
|
||||||
$choices = $list->getChoices();
|
$choices = $list->getChoices();
|
||||||
$values = $list->getValues();
|
$keys = $list->getOriginalKeys();
|
||||||
|
|
||||||
if (!is_callable($preferredChoices) && !empty($preferredChoices)) {
|
if (!is_callable($preferredChoices) && !empty($preferredChoices)) {
|
||||||
$preferredChoices = function ($choice) use ($preferredChoices) {
|
$preferredChoices = function ($choice) use ($preferredChoices) {
|
||||||
@ -169,36 +92,17 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
|||||||
$index = 0;
|
$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
|
// If $groupBy is a callable, choices are added to the group with the
|
||||||
// name returned by the callable. If the callable returns null, the
|
// name returned by the callable. If the callable returns null, the
|
||||||
// choice is not added to any group
|
// choice is not added to any group
|
||||||
if (is_callable($groupBy)) {
|
if (is_callable($groupBy)) {
|
||||||
foreach ($choices as $key => $choice) {
|
foreach ($choices as $value => $choice) {
|
||||||
self::addChoiceViewGroupedBy(
|
self::addChoiceViewGroupedBy(
|
||||||
$groupBy,
|
$groupBy,
|
||||||
$choice,
|
$choice,
|
||||||
$key,
|
(string) $value,
|
||||||
$label,
|
$label,
|
||||||
$values,
|
$keys,
|
||||||
$index,
|
$index,
|
||||||
$attr,
|
$attr,
|
||||||
$preferredChoices,
|
$preferredChoices,
|
||||||
@ -207,13 +111,12 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If $groupBy is passed as array, use that array as template for
|
// Otherwise use the original structure of the choices
|
||||||
// constructing the groups
|
|
||||||
self::addChoiceViewsGroupedBy(
|
self::addChoiceViewsGroupedBy(
|
||||||
$groupBy,
|
$list->getStructuredValues(),
|
||||||
$label,
|
$label,
|
||||||
$choices,
|
$choices,
|
||||||
$values,
|
$keys,
|
||||||
$index,
|
$index,
|
||||||
$attr,
|
$attr,
|
||||||
$preferredChoices,
|
$preferredChoices,
|
||||||
@ -239,15 +142,17 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
|||||||
return new ChoiceListView($otherViews, $preferredViews);
|
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);
|
$nextIndex = is_int($index) ? $index++ : call_user_func($index, $choice, $key, $value);
|
||||||
|
|
||||||
$view = new ChoiceView(
|
$view = new ChoiceView(
|
||||||
$choice,
|
$choice,
|
||||||
$value,
|
$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),
|
null === $label ? (string) $key : (string) call_user_func($label, $choice, $key, $value),
|
||||||
// The attributes may be a callable or a mapping from choice indices
|
// The attributes may be a callable or a mapping from choice indices
|
||||||
// to nested arrays
|
// 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
|
// Add the contents of groups to new ChoiceGroupView instances
|
||||||
if (is_array($content)) {
|
if (is_array($value)) {
|
||||||
$preferredViewsForGroup = array();
|
$preferredViewsForGroup = array();
|
||||||
$otherViewsForGroup = array();
|
$otherViewsForGroup = array();
|
||||||
|
|
||||||
self::addChoiceViewsGroupedBy(
|
self::addChoiceViewsGroupedBy(
|
||||||
$content,
|
$value,
|
||||||
$label,
|
$label,
|
||||||
$choices,
|
$choices,
|
||||||
$values,
|
$keys,
|
||||||
$index,
|
$index,
|
||||||
$attr,
|
$attr,
|
||||||
$isPreferred,
|
$isPreferred,
|
||||||
@ -295,10 +200,10 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
|||||||
|
|
||||||
// Add ungrouped items directly
|
// Add ungrouped items directly
|
||||||
self::addChoiceView(
|
self::addChoiceView(
|
||||||
$choices[$key],
|
$choices[$value],
|
||||||
$key,
|
$value,
|
||||||
$label,
|
$label,
|
||||||
$values,
|
$keys,
|
||||||
$index,
|
$index,
|
||||||
$attr,
|
$attr,
|
||||||
$isPreferred,
|
$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 (null === $groupLabel) {
|
||||||
// If the callable returns null, don't group the choice
|
// If the callable returns null, don't group the choice
|
||||||
self::addChoiceView(
|
self::addChoiceView(
|
||||||
$choice,
|
$choice,
|
||||||
$key,
|
$value,
|
||||||
$label,
|
$label,
|
||||||
$values,
|
$keys,
|
||||||
$index,
|
$index,
|
||||||
$attr,
|
$attr,
|
||||||
$isPreferred,
|
$isPreferred,
|
||||||
@ -338,9 +243,9 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
|||||||
|
|
||||||
self::addChoiceView(
|
self::addChoiceView(
|
||||||
$choice,
|
$choice,
|
||||||
$key,
|
$value,
|
||||||
$label,
|
$label,
|
||||||
$values,
|
$keys,
|
||||||
$index,
|
$index,
|
||||||
$attr,
|
$attr,
|
||||||
$isPreferred,
|
$isPreferred,
|
||||||
|
@ -54,8 +54,8 @@ class PropertyAccessDecorator implements ChoiceListFactoryInterface
|
|||||||
/**
|
/**
|
||||||
* Decorates the given factory.
|
* Decorates the given factory.
|
||||||
*
|
*
|
||||||
* @param ChoiceListFactoryInterface $decoratedFactory The decorated factory
|
* @param ChoiceListFactoryInterface $decoratedFactory The decorated factory
|
||||||
* @param null|PropertyAccessorInterface $propertyAccessor The used property accessor
|
* @param null|PropertyAccessorInterface $propertyAccessor The used property accessor
|
||||||
*/
|
*/
|
||||||
public function __construct(ChoiceListFactoryInterface $decoratedFactory, PropertyAccessorInterface $propertyAccessor = null)
|
public function __construct(ChoiceListFactoryInterface $decoratedFactory, PropertyAccessorInterface $propertyAccessor = null)
|
||||||
{
|
{
|
||||||
@ -98,8 +98,6 @@ class PropertyAccessDecorator implements ChoiceListFactoryInterface
|
|||||||
if (is_object($choice) || is_array($choice)) {
|
if (is_object($choice) || is_array($choice)) {
|
||||||
return $accessor->getValue($choice, $value);
|
return $accessor->getValue($choice, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,9 +126,9 @@ class PropertyAccessDecorator implements ChoiceListFactoryInterface
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*
|
*
|
||||||
* @param ChoiceLoaderInterface $loader The choice loader
|
* @param ChoiceLoaderInterface $loader The choice loader
|
||||||
* @param null|callable|string|PropertyPath $value The callable or path for
|
* @param null|callable|string|PropertyPath $value The callable or path for
|
||||||
* generating the choice values
|
* generating the choice values
|
||||||
*
|
*
|
||||||
* @return ChoiceListInterface The choice list
|
* @return ChoiceListInterface The choice list
|
||||||
*/
|
*/
|
||||||
|
@ -43,13 +43,6 @@ class LazyChoiceList implements ChoiceListInterface
|
|||||||
*/
|
*/
|
||||||
private $value;
|
private $value;
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to use the value callback to compare choices.
|
|
||||||
*
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
private $compareByValue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var ChoiceListInterface|null
|
* @var ChoiceListInterface|null
|
||||||
*/
|
*/
|
||||||
@ -66,11 +59,10 @@ class LazyChoiceList implements ChoiceListInterface
|
|||||||
* @param null|callable $value The callable generating the choice
|
* @param null|callable $value The callable generating the choice
|
||||||
* values
|
* values
|
||||||
*/
|
*/
|
||||||
public function __construct(ChoiceLoaderInterface $loader, $value = null, $compareByValue = false)
|
public function __construct(ChoiceLoaderInterface $loader, $value = null)
|
||||||
{
|
{
|
||||||
$this->loader = $loader;
|
$this->loader = $loader;
|
||||||
$this->value = $value;
|
$this->value = $value;
|
||||||
$this->compareByValue = $compareByValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,6 +89,30 @@ class LazyChoiceList implements ChoiceListInterface
|
|||||||
return $this->loadedList->getValues();
|
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}
|
* {@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;
|
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.
|
* 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>
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
*
|
*
|
||||||
* @deprecated since version 2.7, to be removed in 3.0.
|
* @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
|
* Returns the choice views of the preferred choices as nested array with
|
||||||
* the choice groups as top-level keys.
|
* the choice groups as top-level keys.
|
||||||
@ -84,6 +95,37 @@ interface ChoiceListInterface extends BaseChoiceListInterface
|
|||||||
*/
|
*/
|
||||||
public function getRemainingViews();
|
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.
|
* 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\AbstractType;
|
||||||
use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator;
|
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\View\ChoiceGroupView;
|
||||||
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
|
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
|
||||||
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
|
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\FormEvents;
|
||||||
use Symfony\Component\Form\FormInterface;
|
use Symfony\Component\Form\FormInterface;
|
||||||
use Symfony\Component\Form\FormView;
|
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\EventListener\MergeCollectionListener;
|
||||||
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer;
|
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer;
|
||||||
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer;
|
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer;
|
||||||
@ -259,6 +261,10 @@ class ChoiceType extends AbstractType
|
|||||||
if ($choiceList) {
|
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);
|
@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;
|
return $choiceList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,7 +344,7 @@ class ChoiceType extends AbstractType
|
|||||||
$resolver->setNormalizer('placeholder', $placeholderNormalizer);
|
$resolver->setNormalizer('placeholder', $placeholderNormalizer);
|
||||||
$resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer);
|
$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('choices', array('null', 'array', '\Traversable'));
|
||||||
$resolver->setAllowedTypes('choice_translation_domain', array('null', 'bool', 'string'));
|
$resolver->setAllowedTypes('choice_translation_domain', array('null', 'bool', 'string'));
|
||||||
$resolver->setAllowedTypes('choices_as_values', 'bool');
|
$resolver->setAllowedTypes('choices_as_values', 'bool');
|
||||||
|
@ -31,6 +31,16 @@ abstract class AbstractChoiceListTest extends \PHPUnit_Framework_TestCase
|
|||||||
*/
|
*/
|
||||||
protected $values;
|
protected $values;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $structuredValues;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $keys;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var mixed
|
* @var mixed
|
||||||
*/
|
*/
|
||||||
@ -71,25 +81,52 @@ abstract class AbstractChoiceListTest extends \PHPUnit_Framework_TestCase
|
|||||||
*/
|
*/
|
||||||
protected $value4;
|
protected $value4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $key1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $key2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $key3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $key4;
|
||||||
|
|
||||||
protected function setUp()
|
protected function setUp()
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
$this->list = $this->createChoiceList();
|
$this->list = $this->createChoiceList();
|
||||||
|
|
||||||
$this->choices = $this->getChoices();
|
$choices = $this->getChoices();
|
||||||
|
|
||||||
$this->values = $this->getValues();
|
$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
|
// allow access to the individual entries without relying on their indices
|
||||||
reset($this->choices);
|
reset($this->choices);
|
||||||
reset($this->values);
|
reset($this->values);
|
||||||
|
reset($this->keys);
|
||||||
|
|
||||||
for ($i = 1; $i <= 4; ++$i) {
|
for ($i = 1; $i <= 4; ++$i) {
|
||||||
$this->{'choice'.$i} = current($this->choices);
|
$this->{'choice'.$i} = current($this->choices);
|
||||||
$this->{'value'.$i} = current($this->values);
|
$this->{'value'.$i} = current($this->values);
|
||||||
|
$this->{'key'.$i} = current($this->keys);
|
||||||
|
|
||||||
next($this->choices);
|
next($this->choices);
|
||||||
next($this->values);
|
next($this->values);
|
||||||
|
next($this->keys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,6 +140,16 @@ abstract class AbstractChoiceListTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertSame($this->values, $this->list->getValues());
|
$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()
|
public function testGetChoicesForValues()
|
||||||
{
|
{
|
||||||
$values = array($this->value1, $this->value2);
|
$values = array($this->value1, $this->value2);
|
||||||
|
@ -29,8 +29,6 @@ class ArrayChoiceListTest extends AbstractChoiceListTest
|
|||||||
|
|
||||||
protected function createChoiceList()
|
protected function createChoiceList()
|
||||||
{
|
{
|
||||||
$i = 0;
|
|
||||||
|
|
||||||
return new ArrayChoiceList($this->getChoices());
|
return new ArrayChoiceList($this->getChoices());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,11 +58,31 @@ class ArrayChoiceListTest extends AbstractChoiceListTest
|
|||||||
|
|
||||||
$choiceList = new ArrayChoiceList(array(2 => 'foo', 7 => 'bar', 10 => 'baz'), $callback);
|
$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->getChoicesForValues(array(1 => ':foo', 2 => ':baz')));
|
||||||
$this->assertSame(array(1 => ':foo', 2 => ':baz'), $choiceList->getValuesForChoices(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()
|
public function testCompareChoicesByIdentityByDefault()
|
||||||
{
|
{
|
||||||
$callback = function ($choice) {
|
$callback = function ($choice) {
|
||||||
|
@ -29,7 +29,7 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
|||||||
|
|
||||||
protected function createChoiceList()
|
protected function createChoiceList()
|
||||||
{
|
{
|
||||||
return new ArrayKeyChoiceList($this->getChoices());
|
return new ArrayKeyChoiceList(array_flip($this->getChoices()));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getChoices()
|
protected function getChoices()
|
||||||
@ -44,9 +44,11 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
|||||||
|
|
||||||
public function testUseChoicesAsValuesByDefault()
|
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()
|
public function testNoChoices()
|
||||||
@ -102,33 +104,22 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
|||||||
public function provideConvertibleChoices()
|
public function provideConvertibleChoices()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array(array(0), array(0)),
|
array(array(0 => 'Label'), array(0 => 0)),
|
||||||
array(array(1), array(1)),
|
array(array(1 => 'Label'), array(1 => 1)),
|
||||||
array(array('0'), array(0)),
|
array(array('1.23' => 'Label'), array('1.23' => '1.23')),
|
||||||
array(array('1'), array(1)),
|
array(array('foobar' => 'Label'), array('foobar' => 'foobar')),
|
||||||
array(array('1.23'), array('1.23')),
|
|
||||||
array(array('foobar'), array('foobar')),
|
|
||||||
// The default value of choice fields is NULL. It should be treated
|
// The default value of choice fields is NULL. It should be treated
|
||||||
// like the empty value for this choice list type
|
// like the empty value for this choice list type
|
||||||
array(array(null), array('')),
|
array(array(null => 'Label'), array('' => '')),
|
||||||
array(array(1.23), array('1.23')),
|
array(array('1.23' => 'Label'), array('1.23' => '1.23')),
|
||||||
// Always cast booleans to 0 and 1, because:
|
// Always cast booleans to 0 and 1, because:
|
||||||
// array(true => 'Yes', false => 'No') === array(1 => 'Yes', 0 => 'No')
|
// array(true => 'Yes', false => 'No') === array(1 => 'Yes', 0 => 'No')
|
||||||
// see ChoiceTypeTest::testSetDataSingleNonExpandedAcceptsBoolean
|
// see ChoiceTypeTest::testSetDataSingleNonExpandedAcceptsBoolean
|
||||||
array(array(true), array(1)),
|
array(array(true => 'Label'), array(1 => 1)),
|
||||||
array(array(false), array(0)),
|
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
|
* @dataProvider provideInvalidChoices
|
||||||
* @expectedException \Symfony\Component\Form\Exception\InvalidArgumentException
|
* @expectedException \Symfony\Component\Form\Exception\InvalidArgumentException
|
||||||
@ -155,7 +146,7 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
|||||||
return $value;
|
return $value;
|
||||||
};
|
};
|
||||||
|
|
||||||
$list = new ArrayKeyChoiceList(array('choice'), $callback);
|
$list = new ArrayKeyChoiceList(array('choice' => 'Label'), $callback);
|
||||||
|
|
||||||
$this->assertSame(array($converted), $list->getValues());
|
$this->assertSame(array($converted), $list->getValues());
|
||||||
}
|
}
|
||||||
@ -169,15 +160,7 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
|||||||
array('1', '1'),
|
array('1', '1'),
|
||||||
array('1.23', '1.23'),
|
array('1.23', '1.23'),
|
||||||
array('foobar', 'foobar'),
|
array('foobar', 'foobar'),
|
||||||
// The default value of choice fields is NULL. It should be treated
|
array('', ''),
|
||||||
// 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, ''),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,9 +170,11 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
|||||||
return ':'.$choice;
|
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->getChoicesForValues(array(1 => ':foo', 2 => ':baz')));
|
||||||
$this->assertSame(array(1 => ':foo', 2 => ':baz'), $choiceList->getValuesForChoices(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)
|
public function testCreateFromFlippedChoicesSameChoices($choice1, $choice2)
|
||||||
{
|
{
|
||||||
$choices1 = array($choice1);
|
$choices1 = array($choice1 => 'A');
|
||||||
$choices2 = array($choice2);
|
$choices2 = array($choice2 => 'A');
|
||||||
$list = new \stdClass();
|
$list = new \stdClass();
|
||||||
|
|
||||||
$this->decoratedFactory->expects($this->once())
|
$this->decoratedFactory->expects($this->once())
|
||||||
@ -222,8 +222,8 @@ class CachingFactoryDecoratorTest extends \PHPUnit_Framework_TestCase
|
|||||||
*/
|
*/
|
||||||
public function testCreateFromFlippedChoicesDifferentChoices($choice1, $choice2)
|
public function testCreateFromFlippedChoicesDifferentChoices($choice1, $choice2)
|
||||||
{
|
{
|
||||||
$choices1 = array($choice1);
|
$choices1 = array($choice1 => 'A');
|
||||||
$choices2 = array($choice2);
|
$choices2 = array($choice2 => 'A');
|
||||||
$list1 = new \stdClass();
|
$list1 = new \stdClass();
|
||||||
$list2 = 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\ChoiceListInterface;
|
||||||
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
|
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
|
||||||
use Symfony\Component\Form\ChoiceList\LazyChoiceList;
|
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\ChoiceGroupView;
|
||||||
use Symfony\Component\Form\ChoiceList\View\ChoiceListView;
|
use Symfony\Component\Form\ChoiceList\View\ChoiceListView;
|
||||||
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
|
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')
|
array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D')
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertScalarListWithGeneratedValues($list);
|
$this->assertScalarListWithChoiceValues($list);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateFromFlippedChoicesFlatTraversable()
|
public function testCreateFromFlippedChoicesFlatTraversable()
|
||||||
@ -208,7 +209,7 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
new \ArrayIterator(array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D'))
|
new \ArrayIterator(array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D'))
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertScalarListWithGeneratedValues($list);
|
$this->assertScalarListWithChoiceValues($list);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateFromFlippedChoicesFlatValuesAsCallable()
|
public function testCreateFromFlippedChoicesFlatValuesAsCallable()
|
||||||
@ -247,7 +248,7 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertScalarListWithGeneratedValues($list);
|
$this->assertScalarListWithChoiceValues($list);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateFromFlippedChoicesGroupedTraversable()
|
public function testCreateFromFlippedChoicesGroupedTraversable()
|
||||||
@ -259,7 +260,7 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertScalarListWithGeneratedValues($list);
|
$this->assertScalarListWithChoiceValues($list);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateFromFlippedChoicesGroupedValuesAsCallable()
|
public function testCreateFromFlippedChoicesGroupedValuesAsCallable()
|
||||||
@ -523,33 +524,16 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertFlatViewWithCustomIndices($view);
|
$this->assertFlatViewWithCustomIndices($view);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateViewFlatGroupByAsArray()
|
public function testCreateViewFlatGroupByOriginalStructure()
|
||||||
{
|
{
|
||||||
$view = $this->factory->createView(
|
$list = new ArrayChoiceList(array(
|
||||||
$this->list,
|
'Group 1' => array('A' => $this->obj1, 'B' => $this->obj2),
|
||||||
array($this->obj2, $this->obj3),
|
'Group 2' => array('C' => $this->obj3, 'D' => $this->obj4),
|
||||||
null, // label
|
));
|
||||||
null, // index
|
|
||||||
array(
|
|
||||||
'Group 1' => array('A' => true, 'B' => true),
|
|
||||||
'Group 2' => array('C' => true, 'D' => true),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertGroupedView($view);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCreateViewFlatGroupByAsTraversable()
|
|
||||||
{
|
|
||||||
$view = $this->factory->createView(
|
$view = $this->factory->createView(
|
||||||
$this->list,
|
$list,
|
||||||
array($this->obj2, $this->obj3),
|
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),
|
|
||||||
))
|
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertGroupedView($view);
|
$this->assertGroupedView($view);
|
||||||
@ -592,8 +576,7 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
null, // label
|
null, // label
|
||||||
null, // index
|
null, // index
|
||||||
function ($object) use ($obj1, $obj2) {
|
function ($object) use ($obj1, $obj2) {
|
||||||
return $obj1 === $object || $obj2 === $object ? 'Group 1'
|
return $obj1 === $object || $obj2 === $object ? 'Group 1' : 'Group 2';
|
||||||
: 'Group 2';
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -749,78 +732,86 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
->method('getRemainingViews')
|
->method('getRemainingViews')
|
||||||
->will($this->returnValue($other));
|
->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('y', 'y', 'Other')), $view->choices);
|
||||||
$this->assertEquals(array(new ChoiceView('x', 'x', 'Preferred')), $view->preferredChoices);
|
$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(
|
$this->assertSame(array(
|
||||||
'A' => 'a',
|
'a' => 'a',
|
||||||
'B' => 'b',
|
'b' => 'b',
|
||||||
'C' => 'c',
|
'c' => 'c',
|
||||||
'D' => 'd',
|
'd' => 'd',
|
||||||
), $list->getChoices());
|
), $list->getChoices());
|
||||||
|
|
||||||
$this->assertSame(array(
|
$this->assertSame(array(
|
||||||
'A' => 'a',
|
'a' => 'A',
|
||||||
'B' => 'b',
|
'b' => 'B',
|
||||||
'C' => 'c',
|
'c' => 'C',
|
||||||
'D' => 'd',
|
'd' => 'D',
|
||||||
), $list->getValues());
|
), $list->getOriginalKeys());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function assertObjectListWithGeneratedValues(ChoiceListInterface $list)
|
private function assertObjectListWithGeneratedValues(ChoiceListInterface $list)
|
||||||
{
|
{
|
||||||
|
$this->assertSame(array('0', '1', '2', '3'), $list->getValues());
|
||||||
|
|
||||||
$this->assertSame(array(
|
$this->assertSame(array(
|
||||||
'A' => $this->obj1,
|
0 => $this->obj1,
|
||||||
'B' => $this->obj2,
|
1 => $this->obj2,
|
||||||
'C' => $this->obj3,
|
2 => $this->obj3,
|
||||||
'D' => $this->obj4,
|
3 => $this->obj4,
|
||||||
), $list->getChoices());
|
), $list->getChoices());
|
||||||
|
|
||||||
$this->assertSame(array(
|
$this->assertSame(array(
|
||||||
'A' => '0',
|
0 => 'A',
|
||||||
'B' => '1',
|
1 => 'B',
|
||||||
'C' => '2',
|
2 => 'C',
|
||||||
'D' => '3',
|
3 => 'D',
|
||||||
), $list->getValues());
|
), $list->getOriginalKeys());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function assertScalarListWithCustomValues(ChoiceListInterface $list)
|
private function assertScalarListWithCustomValues(ChoiceListInterface $list)
|
||||||
{
|
{
|
||||||
|
$this->assertSame(array('a', 'b', '1', '2'), $list->getValues());
|
||||||
|
|
||||||
$this->assertSame(array(
|
$this->assertSame(array(
|
||||||
'A' => 'a',
|
'a' => 'a',
|
||||||
'B' => 'b',
|
'b' => 'b',
|
||||||
'C' => 'c',
|
1 => 'c',
|
||||||
'D' => 'd',
|
2 => 'd',
|
||||||
), $list->getChoices());
|
), $list->getChoices());
|
||||||
|
|
||||||
$this->assertSame(array(
|
$this->assertSame(array(
|
||||||
'A' => 'a',
|
'a' => 'A',
|
||||||
'B' => 'b',
|
'b' => 'B',
|
||||||
'C' => '1',
|
1 => 'C',
|
||||||
'D' => '2',
|
2 => 'D',
|
||||||
), $list->getValues());
|
), $list->getOriginalKeys());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function assertObjectListWithCustomValues(ChoiceListInterface $list)
|
private function assertObjectListWithCustomValues(ChoiceListInterface $list)
|
||||||
{
|
{
|
||||||
|
$this->assertSame(array('a', 'b', '1', '2'), $list->getValues());
|
||||||
|
|
||||||
$this->assertSame(array(
|
$this->assertSame(array(
|
||||||
'A' => $this->obj1,
|
'a' => $this->obj1,
|
||||||
'B' => $this->obj2,
|
'b' => $this->obj2,
|
||||||
'C' => $this->obj3,
|
1 => $this->obj3,
|
||||||
'D' => $this->obj4,
|
2 => $this->obj4,
|
||||||
), $list->getChoices());
|
), $list->getChoices());
|
||||||
|
|
||||||
$this->assertSame(array(
|
$this->assertSame(array(
|
||||||
'A' => 'a',
|
'a' => 'A',
|
||||||
'B' => 'b',
|
'b' => 'B',
|
||||||
'C' => '1',
|
1 => 'C',
|
||||||
'D' => '2',
|
2 => 'D',
|
||||||
), $list->getValues());
|
), $list->getOriginalKeys());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function assertFlatView($view)
|
private function assertFlatView($view)
|
||||||
|
@ -73,6 +73,36 @@ class LazyChoiceListTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertSame('RESULT', $this->list->getValues());
|
$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()
|
public function testGetChoicesForValuesForwardsCallIfListNotLoaded()
|
||||||
{
|
{
|
||||||
$this->loader->expects($this->exactly(2))
|
$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;
|
namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\ChoiceList\ArrayKeyChoiceList;
|
||||||
use Symfony\Component\Form\FormEvent;
|
use Symfony\Component\Form\FormEvent;
|
||||||
use Symfony\Component\Form\Extension\Core\EventListener\FixRadioInputListener;
|
use Symfony\Component\Form\Extension\Core\EventListener\FixRadioInputListener;
|
||||||
use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @group legacy
|
* @group legacy
|
||||||
@ -26,7 +26,7 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase
|
|||||||
{
|
{
|
||||||
parent::setUp();
|
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()
|
protected function tearDown()
|
||||||
@ -45,7 +45,6 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$listener = new FixRadioInputListener($this->choiceList, true);
|
$listener = new FixRadioInputListener($this->choiceList, true);
|
||||||
$listener->preSubmit($event);
|
$listener->preSubmit($event);
|
||||||
|
|
||||||
// Indices in SimpleChoiceList are zero-based generated integers
|
|
||||||
$this->assertEquals(array(2 => '1'), $event->getData());
|
$this->assertEquals(array(2 => '1'), $event->getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +57,6 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$listener = new FixRadioInputListener($this->choiceList, true);
|
$listener = new FixRadioInputListener($this->choiceList, true);
|
||||||
$listener->preSubmit($event);
|
$listener->preSubmit($event);
|
||||||
|
|
||||||
// Indices in SimpleChoiceList are zero-based generated integers
|
|
||||||
$this->assertEquals(array(1 => '0'), $event->getData());
|
$this->assertEquals(array(1 => '0'), $event->getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,13 +69,12 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$listener = new FixRadioInputListener($this->choiceList, true);
|
$listener = new FixRadioInputListener($this->choiceList, true);
|
||||||
$listener->preSubmit($event);
|
$listener->preSubmit($event);
|
||||||
|
|
||||||
// Indices in SimpleChoiceList are zero-based generated integers
|
|
||||||
$this->assertEquals(array(0 => ''), $event->getData());
|
$this->assertEquals(array(0 => ''), $event->getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testConvertEmptyStringToPlaceholderIfNotFound()
|
public function testConvertEmptyStringToPlaceholderIfNotFound()
|
||||||
{
|
{
|
||||||
$list = new SimpleChoiceList(array(0 => 'A', 1 => 'B'));
|
$list = new ArrayKeyChoiceList(array(0 => 'A', 1 => 'B'));
|
||||||
|
|
||||||
$data = '';
|
$data = '';
|
||||||
$form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
|
$form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
|
||||||
@ -91,7 +88,7 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
public function testDontConvertEmptyStringToPlaceholderIfNoPlaceholderUsed()
|
public function testDontConvertEmptyStringToPlaceholderIfNoPlaceholderUsed()
|
||||||
{
|
{
|
||||||
$list = new SimpleChoiceList(array(0 => 'A', 1 => 'B'));
|
$list = new ArrayKeyChoiceList(array(0 => 'A', 1 => 'B'));
|
||||||
|
|
||||||
$data = '';
|
$data = '';
|
||||||
$form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
|
$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()
|
public function testExpandedCheckboxesAreNeverRequired()
|
||||||
{
|
{
|
||||||
$form = $this->factory->create('choice', null, array(
|
$form = $this->factory->create('choice', null, array(
|
||||||
|
Reference in New Issue
Block a user