aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ObjectChoiceList.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ObjectChoiceList.php')
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ObjectChoiceList.php184
1 files changed, 184 insertions, 0 deletions
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ObjectChoiceList.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ObjectChoiceList.php
new file mode 100644
index 00000000..0a153883
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ObjectChoiceList.php
@@ -0,0 +1,184 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5*
6* (c) Fabien Potencier <fabien@symfony.com>
7*
8* For the full copyright and license information, please view the LICENSE
9* file that was distributed with this source code.
10*/
11
12namespace Symfony\Component\Form\Extension\Core\ChoiceList;
13
14use Symfony\Component\Form\Exception\StringCastException;
15use Symfony\Component\Form\Exception\InvalidArgumentException;
16use Symfony\Component\PropertyAccess\PropertyPath;
17use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
18use Symfony\Component\PropertyAccess\PropertyAccess;
19use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
20
21/**
22 * A choice list for object choices.
23 *
24 * Supports generation of choice labels, choice groups and choice values
25 * by calling getters of the object (or associated objects).
26 *
27 * <code>
28 * $choices = array($user1, $user2);
29 *
30 * // call getName() to determine the choice labels
31 * $choiceList = new ObjectChoiceList($choices, 'name');
32 * </code>
33 *
34 * @author Bernhard Schussek <bschussek@gmail.com>
35 */
36class ObjectChoiceList extends ChoiceList
37{
38 /**
39 * @var PropertyAccessorInterface
40 */
41 private $propertyAccessor;
42
43 /**
44 * The property path used to obtain the choice label.
45 *
46 * @var PropertyPath
47 */
48 private $labelPath;
49
50 /**
51 * The property path used for object grouping.
52 *
53 * @var PropertyPath
54 */
55 private $groupPath;
56
57 /**
58 * The property path used to obtain the choice value.
59 *
60 * @var PropertyPath
61 */
62 private $valuePath;
63
64 /**
65 * Creates a new object choice list.
66 *
67 * @param array|\Traversable $choices The array of choices. Choices may also be given
68 * as hierarchy of unlimited depth by creating nested
69 * arrays. The title of the sub-hierarchy can be
70 * stored in the array key pointing to the nested
71 * array. The topmost level of the hierarchy may also
72 * be a \Traversable.
73 * @param string $labelPath A property path pointing to the property used
74 * for the choice labels. The value is obtained
75 * by calling the getter on the object. If the
76 * path is NULL, the object's __toString() method
77 * is used instead.
78 * @param array $preferredChoices A flat array of choices that should be
79 * presented to the user with priority.
80 * @param string $groupPath A property path pointing to the property used
81 * to group the choices. Only allowed if
82 * the choices are given as flat array.
83 * @param string $valuePath A property path pointing to the property used
84 * for the choice values. If not given, integers
85 * are generated instead.
86 * @param PropertyAccessorInterface $propertyAccessor The reflection graph for reading property paths.
87 */
88 public function __construct($choices, $labelPath = null, array $preferredChoices = array(), $groupPath = null, $valuePath = null, PropertyAccessorInterface $propertyAccessor = null)
89 {
90 $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::getPropertyAccessor();
91 $this->labelPath = null !== $labelPath ? new PropertyPath($labelPath) : null;
92 $this->groupPath = null !== $groupPath ? new PropertyPath($groupPath) : null;
93 $this->valuePath = null !== $valuePath ? new PropertyPath($valuePath) : null;
94
95 parent::__construct($choices, array(), $preferredChoices);
96 }
97
98 /**
99 * Initializes the list with choices.
100 *
101 * Safe to be called multiple times. The list is cleared on every call.
102 *
103 * @param array|\Traversable $choices The choices to write into the list.
104 * @param array $labels Ignored.
105 * @param array $preferredChoices The choices to display with priority.
106 *
107 * @throws InvalidArgumentException When passing a hierarchy of choices and using
108 * the "groupPath" option at the same time.
109 */
110 protected function initialize($choices, array $labels, array $preferredChoices)
111 {
112 if (null !== $this->groupPath) {
113 $groupedChoices = array();
114
115 foreach ($choices as $i => $choice) {
116 if (is_array($choice)) {
117 throw new InvalidArgumentException('You should pass a plain object array (without groups) when using the "groupPath" option.');
118 }
119
120 try {
121 $group = $this->propertyAccessor->getValue($choice, $this->groupPath);
122 } catch (NoSuchPropertyException $e) {
123 // Don't group items whose group property does not exist
124 // see https://github.com/symfony/symfony/commit/d9b7abb7c7a0f28e0ce970afc5e305dce5dccddf
125 $group = null;
126 }
127
128 if (null === $group) {
129 $groupedChoices[$i] = $choice;
130 } else {
131 if (!isset($groupedChoices[$group])) {
132 $groupedChoices[$group] = array();
133 }
134
135 $groupedChoices[$group][$i] = $choice;
136 }
137 }
138
139 $choices = $groupedChoices;
140 }
141
142 $labels = array();
143
144 $this->extractLabels($choices, $labels);
145
146 parent::initialize($choices, $labels, $preferredChoices);
147 }
148
149 /**
150 * Creates a new unique value for this choice.
151 *
152 * If a property path for the value was given at object creation,
153 * the getter behind that path is now called to obtain a new value.
154 * Otherwise a new integer is generated.
155 *
156 * @param mixed $choice The choice to create a value for
157 *
158 * @return integer|string A unique value without character limitations.
159 */
160 protected function createValue($choice)
161 {
162 if ($this->valuePath) {
163 return (string) $this->propertyAccessor->getValue($choice, $this->valuePath);
164 }
165
166 return parent::createValue($choice);
167 }
168
169 private function extractLabels($choices, array &$labels)
170 {
171 foreach ($choices as $i => $choice) {
172 if (is_array($choice)) {
173 $labels[$i] = array();
174 $this->extractLabels($choice, $labels[$i]);
175 } elseif ($this->labelPath) {
176 $labels[$i] = $this->propertyAccessor->getValue($choice, $this->labelPath);
177 } elseif (method_exists($choice, '__toString')) {
178 $labels[$i] = (string) $choice;
179 } else {
180 throw new StringCastException(sprintf('A "__toString()" method was not found on the objects of type "%s" passed to the choice field. To read a custom getter instead, set the argument $labelPath to the desired property path.', get_class($choice)));
181 }
182 }
183 }
184}