ArrayKeyChoiceList.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Form\ChoiceList;
  11. @trigger_error('The '.__NAMESPACE__.'\ArrayKeyChoiceList class is deprecated since Symfony 2.8 and will be removed in 3.0. Use '.__NAMESPACE__.'\ArrayChoiceList instead.', E_USER_DEPRECATED);
  12. use Symfony\Component\Form\Exception\InvalidArgumentException;
  13. /**
  14. * A list of choices that can be stored in the keys of a PHP array.
  15. *
  16. * PHP arrays accept only strings and integers as array keys. Other scalar types
  17. * are cast to integers and strings according to the description of
  18. * {@link toArrayKey()}. This implementation applies the same casting rules for
  19. * the choices passed to the constructor and to {@link getValuesForChoices()}.
  20. *
  21. * By default, the choices are cast to strings and used as values. Optionally,
  22. * you may pass custom values. The keys of the value array must match the keys
  23. * of the choice array.
  24. *
  25. * Example:
  26. *
  27. * $choices = array('' => 'Don\'t know', 0 => 'No', 1 => 'Yes');
  28. * $choiceList = new ArrayKeyChoiceList(array_keys($choices));
  29. *
  30. * $values = $choiceList->getValues()
  31. * // => array('', '0', '1')
  32. *
  33. * $selectedValues = $choiceList->getValuesForChoices(array(true));
  34. * // => array('1')
  35. *
  36. * @author Bernhard Schussek <bschussek@gmail.com>
  37. *
  38. * @deprecated since version 2.8, to be removed in 3.0. Use ArrayChoiceList instead.
  39. */
  40. class ArrayKeyChoiceList extends ArrayChoiceList
  41. {
  42. /**
  43. * Whether the choices are used as values.
  44. *
  45. * @var bool
  46. */
  47. private $useChoicesAsValues = false;
  48. /**
  49. * Casts the given choice to an array key.
  50. *
  51. * PHP arrays accept only strings and integers as array keys. Integer
  52. * strings such as "42" are automatically cast to integers. The boolean
  53. * values "true" and "false" are cast to the integers 1 and 0. Every other
  54. * scalar value is cast to a string.
  55. *
  56. * @param mixed $choice The choice
  57. *
  58. * @return int|string The choice as PHP array key
  59. *
  60. * @throws InvalidArgumentException If the choice is not scalar
  61. *
  62. * @internal Must not be used outside this class
  63. */
  64. public static function toArrayKey($choice)
  65. {
  66. if (!is_scalar($choice) && null !== $choice) {
  67. throw new InvalidArgumentException(sprintf('The value of type "%s" cannot be converted to a valid array key.', \gettype($choice)));
  68. }
  69. if (\is_bool($choice) || (string) (int) $choice === (string) $choice) {
  70. return (int) $choice;
  71. }
  72. return (string) $choice;
  73. }
  74. /**
  75. * Creates a list with the given choices and values.
  76. *
  77. * The given choice array must have the same array keys as the value array.
  78. * Each choice must be castable to an integer/string according to the
  79. * casting rules described in {@link toArrayKey()}.
  80. *
  81. * If no values are given, the choices are cast to strings and used as
  82. * values.
  83. *
  84. * @param array|\Traversable $choices The selectable choices
  85. * @param callable $value The callable for creating the value
  86. * for a choice. If `null` is passed, the
  87. * choices are cast to strings and used
  88. * as values
  89. *
  90. * @throws InvalidArgumentException If the keys of the choices don't match
  91. * the keys of the values or if any of the
  92. * choices is not scalar
  93. */
  94. public function __construct($choices, $value = null)
  95. {
  96. // If no values are given, use the choices as values
  97. // Since the choices are stored in the collection keys, i.e. they are
  98. // strings or integers, we are guaranteed to be able to convert them
  99. // to strings
  100. if (null === $value) {
  101. $value = function ($choice) {
  102. return (string) $choice;
  103. };
  104. $this->useChoicesAsValues = true;
  105. }
  106. parent::__construct($choices, $value);
  107. }
  108. /**
  109. * {@inheritdoc}
  110. */
  111. public function getChoicesForValues(array $values)
  112. {
  113. if ($this->useChoicesAsValues) {
  114. $values = array_map('strval', $values);
  115. // If the values are identical to the choices, so we can just return
  116. // them to improve performance a little bit
  117. return array_map(array(__CLASS__, 'toArrayKey'), array_intersect($values, array_keys($this->choices)));
  118. }
  119. return parent::getChoicesForValues($values);
  120. }
  121. /**
  122. * {@inheritdoc}
  123. */
  124. public function getValuesForChoices(array $choices)
  125. {
  126. $choices = array_map(array(__CLASS__, 'toArrayKey'), $choices);
  127. if ($this->useChoicesAsValues) {
  128. // If the choices are identical to the values, we can just return
  129. // them to improve performance a little bit
  130. return array_map('strval', array_intersect($choices, $this->choices));
  131. }
  132. return parent::getValuesForChoices($choices);
  133. }
  134. /**
  135. * Flattens and flips an array into the given output variable.
  136. *
  137. * @param array $choices The array to flatten
  138. * @param callable $value The callable for generating choice values
  139. * @param array $choicesByValues The flattened choices indexed by the
  140. * corresponding values
  141. * @param array $keysByValues The original keys indexed by the
  142. * corresponding values
  143. * @param array $structuredValues The values indexed by the original keys
  144. *
  145. * @internal Must not be used by user-land code
  146. */
  147. protected function flatten(array $choices, $value, &$choicesByValues, &$keysByValues, &$structuredValues)
  148. {
  149. if (null === $choicesByValues) {
  150. $choicesByValues = array();
  151. $keysByValues = array();
  152. $structuredValues = array();
  153. }
  154. foreach ($choices as $choice => $key) {
  155. if (\is_array($key)) {
  156. $this->flatten($key, $value, $choicesByValues, $keysByValues, $structuredValues[$choice]);
  157. continue;
  158. }
  159. $choiceValue = (string) \call_user_func($value, $choice);
  160. $choicesByValues[$choiceValue] = $choice;
  161. $keysByValues[$choiceValue] = $key;
  162. $structuredValues[$key] = $choiceValue;
  163. }
  164. }
  165. }