aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/symfony/form/Symfony/Component/Form/Extension
diff options
context:
space:
mode:
authorNicolas LÅ“uillet <nicolas.loeuillet@gmail.com>2013-08-03 19:26:54 +0200
committerNicolas LÅ“uillet <nicolas.loeuillet@gmail.com>2013-08-03 19:26:54 +0200
commit4f5b44bd3bd490309eb2ba7b44df4769816ba729 (patch)
tree6cefe170dfe0a5a361cb1e2d1fc4d580a3316d02 /vendor/symfony/form/Symfony/Component/Form/Extension
parent2b840e0cfb63a453bea67a98541f3df9c273c5f5 (diff)
downloadwallabag-4f5b44bd3bd490309eb2ba7b44df4769816ba729.tar.gz
wallabag-4f5b44bd3bd490309eb2ba7b44df4769816ba729.tar.zst
wallabag-4f5b44bd3bd490309eb2ba7b44df4769816ba729.zip
twig implementation
Diffstat (limited to 'vendor/symfony/form/Symfony/Component/Form/Extension')
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceList.php510
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceListInterface.php149
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/LazyChoiceList.php149
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ObjectChoiceList.php184
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/SimpleChoiceList.php164
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/CoreExtension.php59
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataMapper/PropertyPathMapper.php92
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ArrayToPartsTransformer.php86
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/BaseDateTimeTransformer.php52
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/BooleanToStringTransformer.php85
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToBooleanArrayTransformer.php118
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php62
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToBooleanArrayTransformer.php117
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php83
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DataTransformerChain.php86
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php184
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php169
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php82
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php231
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToTimestampTransformer.php89
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php53
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php90
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php184
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php149
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php91
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixCheckboxInputListener.php62
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixRadioInputListener.php66
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php56
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/MergeCollectionListener.php137
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php173
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/TrimListener.php55
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/BaseType.php121
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/BirthdayType.php44
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ButtonType.php38
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CheckboxType.php67
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php274
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CollectionType.php103
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CountryType.php45
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php45
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php281
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/DateType.php309
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/EmailType.php33
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/FileType.php61
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/FormType.php214
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/HiddenType.php40
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/IntegerType.php68
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/LanguageType.php45
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/LocaleType.php46
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/MoneyType.php111
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/NumberType.php66
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/PasswordType.php57
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/PercentType.php55
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/RadioType.php33
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/RepeatedType.php67
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ResetType.php39
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/SearchType.php33
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/SubmitType.php46
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TextType.php36
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TextareaType.php43
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TimeType.php225
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php86
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/UrlType.php54
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/View/ChoiceView.php55
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php64
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/CsrfProviderInterface.php49
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php78
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProvider.php57
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php115
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php129
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/DependencyInjection/DependencyInjectionExtension.php101
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/EventListener/BindRequestListener.php91
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationExtension.php29
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php79
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php56
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Templating/TemplatingExtension.php33
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Templating/TemplatingRendererEngine.php125
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/Form.php33
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php236
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php68
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/BaseValidatorExtension.php56
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php84
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/RepeatedTypeValidatorExtension.php45
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/SubmitTypeValidatorExtension.php28
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Util/ServerParams.php64
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php57
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php286
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php106
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/RelativePath.php45
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php299
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapperInterface.php33
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPath.php250
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPathIterator.php30
92 files changed, 9433 insertions, 0 deletions
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceList.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceList.php
new file mode 100644
index 00000000..f9d381cd
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceList.php
@@ -0,0 +1,510 @@
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\FormConfigBuilder;
15use Symfony\Component\Form\Exception\UnexpectedTypeException;
16use Symfony\Component\Form\Exception\InvalidConfigurationException;
17use Symfony\Component\Form\Exception\InvalidArgumentException;
18use Symfony\Component\Form\Extension\Core\View\ChoiceView;
19
20/**
21 * A choice list for choices of arbitrary data types.
22 *
23 * Choices and labels are passed in two arrays. The indices of the choices
24 * and the labels should match. Choices may also be given as hierarchy of
25 * unlimited depth by creating nested arrays. The title of the sub-hierarchy
26 * can be stored in the array key pointing to the nested array. The topmost
27 * level of the hierarchy may also be a \Traversable.
28 *
29 * <code>
30 * $choices = array(true, false);
31 * $labels = array('Agree', 'Disagree');
32 * $choiceList = new ChoiceList($choices, $labels);
33 * </code>
34 *
35 * @author Bernhard Schussek <bschussek@gmail.com>
36 */
37class ChoiceList implements ChoiceListInterface
38{
39 /**
40 * The choices with their indices as keys.
41 *
42 * @var array
43 */
44 private $choices = array();
45
46 /**
47 * The choice values with the indices of the matching choices as keys.
48 *
49 * @var array
50 */
51 private $values = array();
52
53 /**
54 * The preferred view objects as hierarchy containing also the choice groups
55 * with the indices of the matching choices as bottom-level keys.
56 *
57 * @var array
58 */
59 private $preferredViews = array();
60
61 /**
62 * The non-preferred view objects as hierarchy containing also the choice
63 * groups with the indices of the matching choices as bottom-level keys.
64 *
65 * @var array
66 */
67 private $remainingViews = array();
68
69 /**
70 * Creates a new choice list.
71 *
72 * @param array|\Traversable $choices The array of choices. Choices may also be given
73 * as hierarchy of unlimited depth. Hierarchies are
74 * created by creating nested arrays. The title of
75 * the sub-hierarchy can be stored in the array
76 * key pointing to the nested array. The topmost
77 * level of the hierarchy may also be a \Traversable.
78 * @param array $labels The array of labels. The structure of this array
79 * should match the structure of $choices.
80 * @param array $preferredChoices A flat array of choices that should be
81 * presented to the user with priority.
82 *
83 * @throws UnexpectedTypeException If the choices are not an array or \Traversable.
84 */
85 public function __construct($choices, array $labels, array $preferredChoices = array())
86 {
87 if (!is_array($choices) && !$choices instanceof \Traversable) {
88 throw new UnexpectedTypeException($choices, 'array or \Traversable');
89 }
90
91 $this->initialize($choices, $labels, $preferredChoices);
92 }
93
94 /**
95 * Initializes the list with choices.
96 *
97 * Safe to be called multiple times. The list is cleared on every call.
98 *
99 * @param array|\Traversable $choices The choices to write into the list.
100 * @param array $labels The labels belonging to the choices.
101 * @param array $preferredChoices The choices to display with priority.
102 */
103 protected function initialize($choices, array $labels, array $preferredChoices)
104 {
105 $this->choices = array();
106 $this->values = array();
107 $this->preferredViews = array();
108 $this->remainingViews = array();
109
110 $this->addChoices(
111 $this->preferredViews,
112 $this->remainingViews,
113 $choices,
114 $labels,
115 $preferredChoices
116 );
117 }
118
119 /**
120 * {@inheritdoc}
121 */
122 public function getChoices()
123 {
124 return $this->choices;
125 }
126
127 /**
128 * {@inheritdoc}
129 */
130 public function getValues()
131 {
132 return $this->values;
133 }
134
135 /**
136 * {@inheritdoc}
137 */
138 public function getPreferredViews()
139 {
140 return $this->preferredViews;
141 }
142
143 /**
144 * {@inheritdoc}
145 */
146 public function getRemainingViews()
147 {
148 return $this->remainingViews;
149 }
150
151 /**
152 * {@inheritdoc}
153 */
154 public function getChoicesForValues(array $values)
155 {
156 $values = $this->fixValues($values);
157 $choices = array();
158
159 foreach ($values as $j => $givenValue) {
160 foreach ($this->values as $i => $value) {
161 if ($value === $givenValue) {
162 $choices[] = $this->choices[$i];
163 unset($values[$j]);
164
165 if (0 === count($values)) {
166 break 2;
167 }
168 }
169 }
170 }
171
172 return $choices;
173 }
174
175 /**
176 * {@inheritdoc}
177 */
178 public function getValuesForChoices(array $choices)
179 {
180 $choices = $this->fixChoices($choices);
181 $values = array();
182
183 foreach ($this->choices as $i => $choice) {
184 foreach ($choices as $j => $givenChoice) {
185 if ($choice === $givenChoice) {
186 $values[] = $this->values[$i];
187 unset($choices[$j]);
188
189 if (0 === count($choices)) {
190 break 2;
191 }
192 }
193 }
194 }
195
196 return $values;
197 }
198
199 /**
200 * {@inheritdoc}
201 */
202 public function getIndicesForChoices(array $choices)
203 {
204 $choices = $this->fixChoices($choices);
205 $indices = array();
206
207 foreach ($this->choices as $i => $choice) {
208 foreach ($choices as $j => $givenChoice) {
209 if ($choice === $givenChoice) {
210 $indices[] = $i;
211 unset($choices[$j]);
212
213 if (0 === count($choices)) {
214 break 2;
215 }
216 }
217 }
218 }
219
220 return $indices;
221 }
222
223 /**
224 * {@inheritdoc}
225 */
226 public function getIndicesForValues(array $values)
227 {
228 $values = $this->fixValues($values);
229 $indices = array();
230
231 foreach ($this->values as $i => $value) {
232 foreach ($values as $j => $givenValue) {
233 if ($value === $givenValue) {
234 $indices[] = $i;
235 unset($values[$j]);
236
237 if (0 === count($values)) {
238 break 2;
239 }
240 }
241 }
242 }
243
244 return $indices;
245 }
246
247 /**
248 * Recursively adds the given choices to the list.
249 *
250 * @param array $bucketForPreferred The bucket where to store the preferred
251 * view objects.
252 * @param array $bucketForRemaining The bucket where to store the
253 * non-preferred view objects.
254 * @param array|\Traversable $choices The list of choices.
255 * @param array $labels The labels corresponding to the choices.
256 * @param array $preferredChoices The preferred choices.
257 *
258 * @throws InvalidArgumentException If the structures of the choices and labels array do not match.
259 * @throws InvalidConfigurationException If no valid value or index could be created for a choice.
260 */
261 protected function addChoices(array &$bucketForPreferred, array &$bucketForRemaining, $choices, array $labels, array $preferredChoices)
262 {
263 // Add choices to the nested buckets
264 foreach ($choices as $group => $choice) {
265 if (!array_key_exists($group, $labels)) {
266 throw new InvalidArgumentException('The structures of the choices and labels array do not match.');
267 }
268
269 if (is_array($choice)) {
270 // Don't do the work if the array is empty
271 if (count($choice) > 0) {
272 $this->addChoiceGroup(
273 $group,
274 $bucketForPreferred,
275 $bucketForRemaining,
276 $choice,
277 $labels[$group],
278 $preferredChoices
279 );
280 }
281 } else {
282 $this->addChoice(
283 $bucketForPreferred,
284 $bucketForRemaining,
285 $choice,
286 $labels[$group],
287 $preferredChoices
288 );
289 }
290 }
291 }
292
293 /**
294 * Recursively adds a choice group.
295 *
296 * @param string $group The name of the group.
297 * @param array $bucketForPreferred The bucket where to store the preferred
298 * view objects.
299 * @param array $bucketForRemaining The bucket where to store the
300 * non-preferred view objects.
301 * @param array $choices The list of choices in the group.
302 * @param array $labels The labels corresponding to the choices in the group.
303 * @param array $preferredChoices The preferred choices.
304 *
305 * @throws InvalidConfigurationException If no valid value or index could be created for a choice.
306 */
307 protected function addChoiceGroup($group, array &$bucketForPreferred, array &$bucketForRemaining, array $choices, array $labels, array $preferredChoices)
308 {
309 // If this is a choice group, create a new level in the choice
310 // key hierarchy
311 $bucketForPreferred[$group] = array();
312 $bucketForRemaining[$group] = array();
313
314 $this->addChoices(
315 $bucketForPreferred[$group],
316 $bucketForRemaining[$group],
317 $choices,
318 $labels,
319 $preferredChoices
320 );
321
322 // Remove child levels if empty
323 if (empty($bucketForPreferred[$group])) {
324 unset($bucketForPreferred[$group]);
325 }
326 if (empty($bucketForRemaining[$group])) {
327 unset($bucketForRemaining[$group]);
328 }
329 }
330
331 /**
332 * Adds a new choice.
333 *
334 * @param array $bucketForPreferred The bucket where to store the preferred
335 * view objects.
336 * @param array $bucketForRemaining The bucket where to store the
337 * non-preferred view objects.
338 * @param mixed $choice The choice to add.
339 * @param string $label The label for the choice.
340 * @param array $preferredChoices The preferred choices.
341 *
342 * @throws InvalidConfigurationException If no valid value or index could be created.
343 */
344 protected function addChoice(array &$bucketForPreferred, array &$bucketForRemaining, $choice, $label, array $preferredChoices)
345 {
346 $index = $this->createIndex($choice);
347
348 if ('' === $index || null === $index || !FormConfigBuilder::isValidName((string) $index)) {
349 throw new InvalidConfigurationException(sprintf('The index "%s" created by the choice list is invalid. It should be a valid, non-empty Form name.', $index));
350 }
351
352 $value = $this->createValue($choice);
353
354 if (!is_string($value)) {
355 throw new InvalidConfigurationException(sprintf('The value created by the choice list is of type "%s", but should be a string.', gettype($value)));
356 }
357
358 $view = new ChoiceView($choice, $value, $label);
359
360 $this->choices[$index] = $this->fixChoice($choice);
361 $this->values[$index] = $value;
362
363 if ($this->isPreferred($choice, $preferredChoices)) {
364 $bucketForPreferred[$index] = $view;
365 } else {
366 $bucketForRemaining[$index] = $view;
367 }
368 }
369
370 /**
371 * Returns whether the given choice should be preferred judging by the
372 * given array of preferred choices.
373 *
374 * Extension point to optimize performance by changing the structure of the
375 * $preferredChoices array.
376 *
377 * @param mixed $choice The choice to test.
378 * @param array $preferredChoices An array of preferred choices.
379 *
380 * @return Boolean Whether the choice is preferred.
381 */
382 protected function isPreferred($choice, array $preferredChoices)
383 {
384 return false !== array_search($choice, $preferredChoices, true);
385 }
386
387 /**
388 * Creates a new unique index for this choice.
389 *
390 * Extension point to change the indexing strategy.
391 *
392 * @param mixed $choice The choice to create an index for
393 *
394 * @return integer|string A unique index containing only ASCII letters,
395 * digits and underscores.
396 */
397 protected function createIndex($choice)
398 {
399 return count($this->choices);
400 }
401
402 /**
403 * Creates a new unique value for this choice.
404 *
405 * By default, an integer is generated since it cannot be guaranteed that
406 * all values in the list are convertible to (unique) strings. Subclasses
407 * can override this behaviour if they can guarantee this property.
408 *
409 * @param mixed $choice The choice to create a value for
410 *
411 * @return string A unique string.
412 */
413 protected function createValue($choice)
414 {
415 return (string) count($this->values);
416 }
417
418 /**
419 * Fixes the data type of the given choice value to avoid comparison
420 * problems.
421 *
422 * @param mixed $value The choice value.
423 *
424 * @return string The value as string.
425 */
426 protected function fixValue($value)
427 {
428 return (string) $value;
429 }
430
431 /**
432 * Fixes the data types of the given choice values to avoid comparison
433 * problems.
434 *
435 * @param array $values The choice values.
436 *
437 * @return array The values as strings.
438 */
439 protected function fixValues(array $values)
440 {
441 foreach ($values as $i => $value) {
442 $values[$i] = $this->fixValue($value);
443 }
444
445 return $values;
446 }
447
448 /**
449 * Fixes the data type of the given choice index to avoid comparison
450 * problems.
451 *
452 * @param mixed $index The choice index.
453 *
454 * @return integer|string The index as PHP array key.
455 */
456 protected function fixIndex($index)
457 {
458 if (is_bool($index) || (string) (int) $index === (string) $index) {
459 return (int) $index;
460 }
461
462 return (string) $index;
463 }
464
465 /**
466 * Fixes the data types of the given choice indices to avoid comparison
467 * problems.
468 *
469 * @param array $indices The choice indices.
470 *
471 * @return array The indices as strings.
472 */
473 protected function fixIndices(array $indices)
474 {
475 foreach ($indices as $i => $index) {
476 $indices[$i] = $this->fixIndex($index);
477 }
478
479 return $indices;
480 }
481
482 /**
483 * Fixes the data type of the given choice to avoid comparison problems.
484 *
485 * Extension point. In this implementation, choices are guaranteed to
486 * always maintain their type and thus can be typesafely compared.
487 *
488 * @param mixed $choice The choice.
489 *
490 * @return mixed The fixed choice.
491 */
492 protected function fixChoice($choice)
493 {
494 return $choice;
495 }
496
497 /**
498 * Fixes the data type of the given choices to avoid comparison problems.
499 *
500 * @param array $choices The choices.
501 *
502 * @return array The fixed choices.
503 *
504 * @see fixChoice
505 */
506 protected function fixChoices(array $choices)
507 {
508 return $choices;
509 }
510}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceListInterface.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceListInterface.php
new file mode 100644
index 00000000..099ace82
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceListInterface.php
@@ -0,0 +1,149 @@
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
14/**
15 * Contains choices that can be selected in a form field.
16 *
17 * Each choice has three different properties:
18 *
19 * - Choice: The choice that should be returned to the application by the
20 * choice field. Can be any scalar value or an object, but no
21 * array.
22 * - Label: A text representing the choice that is displayed to the user.
23 * - Value: A uniquely identifying value that can contain arbitrary
24 * characters, but no arrays or objects. This value is displayed
25 * in the HTML "value" attribute.
26 *
27 * @author Bernhard Schussek <bschussek@gmail.com>
28 */
29interface ChoiceListInterface
30{
31 /**
32 * Returns the list of choices
33 *
34 * @return array The choices with their indices as keys
35 */
36 public function getChoices();
37
38 /**
39 * Returns the values for the choices
40 *
41 * @return array The values with the corresponding choice indices as keys
42 */
43 public function getValues();
44
45 /**
46 * Returns the choice views of the preferred choices as nested array with
47 * the choice groups as top-level keys.
48 *
49 * Example:
50 *
51 * <source>
52 * array(
53 * 'Group 1' => array(
54 * 10 => ChoiceView object,
55 * 20 => ChoiceView object,
56 * ),
57 * 'Group 2' => array(
58 * 30 => ChoiceView object,
59 * ),
60 * )
61 * </source>
62 *
63 * @return array A nested array containing the views with the corresponding
64 * choice indices as keys on the lowest levels and the choice
65 * group names in the keys of the higher levels
66 */
67 public function getPreferredViews();
68
69 /**
70 * Returns the choice views of the choices that are not preferred as nested
71 * array with the choice groups as top-level keys.
72 *
73 * Example:
74 *
75 * <source>
76 * array(
77 * 'Group 1' => array(
78 * 10 => ChoiceView object,
79 * 20 => ChoiceView object,
80 * ),
81 * 'Group 2' => array(
82 * 30 => ChoiceView object,
83 * ),
84 * )
85 * </source>
86 *
87 * @return array A nested array containing the views with the corresponding
88 * choice indices as keys on the lowest levels and the choice
89 * group names in the keys of the higher levels
90 *
91 * @see getPreferredValues
92 */
93 public function getRemainingViews();
94
95 /**
96 * Returns the choices corresponding to the given values.
97 *
98 * The choices can have any data type.
99 *
100 * @param array $values An array of choice values. Not existing values in
101 * this array are ignored
102 *
103 * @return array An array of choices with ascending, 0-based numeric keys
104 */
105 public function getChoicesForValues(array $values);
106
107 /**
108 * Returns the values corresponding to the given choices.
109 *
110 * The values must be strings.
111 *
112 * @param array $choices An array of choices. Not existing choices in this
113 * array are ignored
114 *
115 * @return array An array of choice values with ascending, 0-based numeric
116 * keys
117 */
118 public function getValuesForChoices(array $choices);
119
120 /**
121 * Returns the indices corresponding to the given choices.
122 *
123 * The indices must be positive integers or strings accepted by
124 * {@link FormConfigBuilder::validateName()}.
125 *
126 * The index "placeholder" is internally reserved.
127 *
128 * @param array $choices An array of choices. Not existing choices in this
129 * array are ignored
130 *
131 * @return array An array of indices with ascending, 0-based numeric keys
132 */
133 public function getIndicesForChoices(array $choices);
134
135 /**
136 * Returns the indices corresponding to the given values.
137 *
138 * The indices must be positive integers or strings accepted by
139 * {@link FormConfigBuilder::validateName()}.
140 *
141 * The index "placeholder" is internally reserved.
142 *
143 * @param array $values An array of choice values. Not existing values in
144 * this array are ignored
145 *
146 * @return array An array of indices with ascending, 0-based numeric keys
147 */
148 public function getIndicesForValues(array $values);
149}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/LazyChoiceList.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/LazyChoiceList.php
new file mode 100644
index 00000000..996f900c
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/LazyChoiceList.php
@@ -0,0 +1,149 @@
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\InvalidArgumentException;
15
16/**
17 * A choice list that is loaded lazily
18 *
19 * This list loads itself as soon as any of the getters is accessed for the
20 * first time. You should implement loadChoiceList() in your child classes,
21 * which should return a ChoiceListInterface instance.
22 *
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25abstract class LazyChoiceList implements ChoiceListInterface
26{
27 /**
28 * The loaded choice list
29 *
30 * @var ChoiceListInterface
31 */
32 private $choiceList;
33
34 /**
35 * {@inheritdoc}
36 */
37 public function getChoices()
38 {
39 if (!$this->choiceList) {
40 $this->load();
41 }
42
43 return $this->choiceList->getChoices();
44 }
45
46 /**
47 * {@inheritdoc}
48 */
49 public function getValues()
50 {
51 if (!$this->choiceList) {
52 $this->load();
53 }
54
55 return $this->choiceList->getValues();
56 }
57
58 /**
59 * {@inheritdoc}
60 */
61 public function getPreferredViews()
62 {
63 if (!$this->choiceList) {
64 $this->load();
65 }
66
67 return $this->choiceList->getPreferredViews();
68 }
69
70 /**
71 * {@inheritdoc}
72 */
73 public function getRemainingViews()
74 {
75 if (!$this->choiceList) {
76 $this->load();
77 }
78
79 return $this->choiceList->getRemainingViews();
80 }
81
82 /**
83 * {@inheritdoc}
84 */
85 public function getChoicesForValues(array $values)
86 {
87 if (!$this->choiceList) {
88 $this->load();
89 }
90
91 return $this->choiceList->getChoicesForValues($values);
92 }
93
94 /**
95 * {@inheritdoc}
96 */
97 public function getValuesForChoices(array $choices)
98 {
99 if (!$this->choiceList) {
100 $this->load();
101 }
102
103 return $this->choiceList->getValuesForChoices($choices);
104 }
105
106 /**
107 * {@inheritdoc}
108 */
109 public function getIndicesForChoices(array $choices)
110 {
111 if (!$this->choiceList) {
112 $this->load();
113 }
114
115 return $this->choiceList->getIndicesForChoices($choices);
116 }
117
118 /**
119 * {@inheritdoc}
120 */
121 public function getIndicesForValues(array $values)
122 {
123 if (!$this->choiceList) {
124 $this->load();
125 }
126
127 return $this->choiceList->getIndicesForValues($values);
128 }
129
130 /**
131 * Loads the choice list
132 *
133 * Should be implemented by child classes.
134 *
135 * @return ChoiceListInterface The loaded choice list
136 */
137 abstract protected function loadChoiceList();
138
139 private function load()
140 {
141 $choiceList = $this->loadChoiceList();
142
143 if (!$choiceList instanceof ChoiceListInterface) {
144 throw new InvalidArgumentException(sprintf('loadChoiceList() should return a ChoiceListInterface instance. Got %s', gettype($choiceList)));
145 }
146
147 $this->choiceList = $choiceList;
148 }
149}
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}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/SimpleChoiceList.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/SimpleChoiceList.php
new file mode 100644
index 00000000..914dbe5f
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/SimpleChoiceList.php
@@ -0,0 +1,164 @@
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
14/**
15 * A choice list for choices of type string or integer.
16 *
17 * Choices and their associated labels can be passed in a single array. Since
18 * choices are passed as array keys, only strings or integer choices are
19 * allowed. Choices may also be given as hierarchy of unlimited depth by
20 * creating nested arrays. The title of the sub-hierarchy can be stored in the
21 * array key pointing to the nested array.
22 *
23 * <code>
24 * $choiceList = new SimpleChoiceList(array(
25 * 'creditcard' => 'Credit card payment',
26 * 'cash' => 'Cash payment',
27 * ));
28 * </code>
29 *
30 * @author Bernhard Schussek <bschussek@gmail.com>
31 */
32class SimpleChoiceList extends ChoiceList
33{
34 /**
35 * Creates a new simple choice list.
36 *
37 * @param array $choices The array of choices with the choices as keys and
38 * the labels as values. Choices may also be given
39 * as hierarchy of unlimited depth by creating nested
40 * arrays. The title of the sub-hierarchy is stored
41 * in the array key pointing to the nested array.
42 * @param array $preferredChoices A flat array of choices that should be
43 * presented to the user with priority.
44 */
45 public function __construct(array $choices, array $preferredChoices = array())
46 {
47 // Flip preferred choices to speed up lookup
48 parent::__construct($choices, $choices, array_flip($preferredChoices));
49 }
50
51 /**
52 * {@inheritdoc}
53 */
54 public function getChoicesForValues(array $values)
55 {
56 $values = $this->fixValues($values);
57
58 // The values are identical to the choices, so we can just return them
59 // to improve performance a little bit
60 return $this->fixChoices(array_intersect($values, $this->getValues()));
61 }
62
63 /**
64 * {@inheritdoc}
65 */
66 public function getValuesForChoices(array $choices)
67 {
68 $choices = $this->fixChoices($choices);
69
70 // The choices are identical to the values, so we can just return them
71 // to improve performance a little bit
72 return $this->fixValues(array_intersect($choices, $this->getValues()));
73 }
74
75 /**
76 * Recursively adds the given choices to the list.
77 *
78 * Takes care of splitting the single $choices array passed in the
79 * constructor into choices and labels.
80 *
81 * @param array $bucketForPreferred The bucket where to store the preferred
82 * view objects.
83 * @param array $bucketForRemaining The bucket where to store the
84 * non-preferred view objects.
85 * @param array|\Traversable $choices The list of choices.
86 * @param array $labels Ignored.
87 * @param array $preferredChoices The preferred choices.
88 */
89 protected function addChoices(array &$bucketForPreferred, array &$bucketForRemaining, $choices, array $labels, array $preferredChoices)
90 {
91 // Add choices to the nested buckets
92 foreach ($choices as $choice => $label) {
93 if (is_array($label)) {
94 // Don't do the work if the array is empty
95 if (count($label) > 0) {
96 $this->addChoiceGroup(
97 $choice,
98 $bucketForPreferred,
99 $bucketForRemaining,
100 $label,
101 $label,
102 $preferredChoices
103 );
104 }
105 } else {
106 $this->addChoice(
107 $bucketForPreferred,
108 $bucketForRemaining,
109 $choice,
110 $label,
111 $preferredChoices
112 );
113 }
114 }
115 }
116
117 /**
118 * Returns whether the given choice should be preferred judging by the
119 * given array of preferred choices.
120 *
121 * Optimized for performance by treating the preferred choices as array
122 * where choices are stored in the keys.
123 *
124 * @param mixed $choice The choice to test.
125 * @param array $preferredChoices An array of preferred choices.
126 *
127 * @return Boolean Whether the choice is preferred.
128 */
129 protected function isPreferred($choice, array $preferredChoices)
130 {
131 // Optimize performance over the default implementation
132 return isset($preferredChoices[$choice]);
133 }
134
135 /**
136 * Converts the choice to a valid PHP array key.
137 *
138 * @param mixed $choice The choice.
139 *
140 * @return string|integer A valid PHP array key.
141 */
142 protected function fixChoice($choice)
143 {
144 return $this->fixIndex($choice);
145 }
146
147 /**
148 * {@inheritdoc}
149 */
150 protected function fixChoices(array $choices)
151 {
152 return $this->fixIndices($choices);
153 }
154
155 /**
156 * {@inheritdoc}
157 */
158 protected function createValue($choice)
159 {
160 // Choices are guaranteed to be unique and scalar, so we can simply
161 // convert them to strings
162 return (string) $choice;
163 }
164}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/CoreExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/CoreExtension.php
new file mode 100644
index 00000000..bbcac4ba
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/CoreExtension.php
@@ -0,0 +1,59 @@
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;
13
14use Symfony\Component\Form\AbstractExtension;
15use Symfony\Component\PropertyAccess\PropertyAccess;
16
17/**
18 * Represents the main form extension, which loads the core functionality.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class CoreExtension extends AbstractExtension
23{
24 protected function loadTypes()
25 {
26 return array(
27 new Type\FormType(PropertyAccess::getPropertyAccessor()),
28 new Type\BirthdayType(),
29 new Type\CheckboxType(),
30 new Type\ChoiceType(),
31 new Type\CollectionType(),
32 new Type\CountryType(),
33 new Type\DateType(),
34 new Type\DateTimeType(),
35 new Type\EmailType(),
36 new Type\HiddenType(),
37 new Type\IntegerType(),
38 new Type\LanguageType(),
39 new Type\LocaleType(),
40 new Type\MoneyType(),
41 new Type\NumberType(),
42 new Type\PasswordType(),
43 new Type\PercentType(),
44 new Type\RadioType(),
45 new Type\RepeatedType(),
46 new Type\SearchType(),
47 new Type\TextareaType(),
48 new Type\TextType(),
49 new Type\TimeType(),
50 new Type\TimezoneType(),
51 new Type\UrlType(),
52 new Type\FileType(),
53 new Type\ButtonType(),
54 new Type\SubmitType(),
55 new Type\ResetType(),
56 new Type\CurrencyType(),
57 );
58 }
59}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataMapper/PropertyPathMapper.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataMapper/PropertyPathMapper.php
new file mode 100644
index 00000000..d8bd9c71
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataMapper/PropertyPathMapper.php
@@ -0,0 +1,92 @@
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\DataMapper;
13
14use Symfony\Component\Form\DataMapperInterface;
15use Symfony\Component\Form\Exception\UnexpectedTypeException;
16use Symfony\Component\PropertyAccess\PropertyAccess;
17use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
18
19/**
20 * A data mapper using property paths to read/write data.
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class PropertyPathMapper implements DataMapperInterface
25{
26 /**
27 * @var PropertyAccessorInterface
28 */
29 private $propertyAccessor;
30
31 /**
32 * Creates a new property path mapper.
33 *
34 * @param PropertyAccessorInterface $propertyAccessor
35 */
36 public function __construct(PropertyAccessorInterface $propertyAccessor = null)
37 {
38 $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::getPropertyAccessor();
39 }
40
41 /**
42 * {@inheritdoc}
43 */
44 public function mapDataToForms($data, $forms)
45 {
46 if (null === $data || array() === $data) {
47 return;
48 }
49
50 if (!is_array($data) && !is_object($data)) {
51 throw new UnexpectedTypeException($data, 'object, array or empty');
52 }
53
54 foreach ($forms as $form) {
55 $propertyPath = $form->getPropertyPath();
56 $config = $form->getConfig();
57
58 if (null !== $propertyPath && $config->getMapped()) {
59 $form->setData($this->propertyAccessor->getValue($data, $propertyPath));
60 }
61 }
62 }
63
64 /**
65 * {@inheritdoc}
66 */
67 public function mapFormsToData($forms, &$data)
68 {
69 if (null === $data) {
70 return;
71 }
72
73 if (!is_array($data) && !is_object($data)) {
74 throw new UnexpectedTypeException($data, 'object, array or empty');
75 }
76
77 foreach ($forms as $form) {
78 $propertyPath = $form->getPropertyPath();
79 $config = $form->getConfig();
80
81 // Write-back is disabled if the form is not synchronized (transformation failed)
82 // and if the form is disabled (modification not allowed)
83 if (null !== $propertyPath && $config->getMapped() && $form->isSynchronized() && !$form->isDisabled()) {
84 // If the data is identical to the value in $data, we are
85 // dealing with a reference
86 if (!is_object($data) || !$config->getByReference() || $form->getData() !== $this->propertyAccessor->getValue($data, $propertyPath)) {
87 $this->propertyAccessor->setValue($data, $propertyPath, $form->getData());
88 }
89 }
90 }
91 }
92}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ArrayToPartsTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ArrayToPartsTransformer.php
new file mode 100644
index 00000000..fc080f25
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ArrayToPartsTransformer.php
@@ -0,0 +1,86 @@
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\DataTransformer;
13
14use Symfony\Component\Form\DataTransformerInterface;
15use Symfony\Component\Form\Exception\TransformationFailedException;
16
17/**
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20class ArrayToPartsTransformer implements DataTransformerInterface
21{
22 private $partMapping;
23
24 public function __construct(array $partMapping)
25 {
26 $this->partMapping = $partMapping;
27 }
28
29 public function transform($array)
30 {
31 if (null === $array) {
32 $array = array();
33 }
34
35 if (!is_array($array) ) {
36 throw new TransformationFailedException('Expected an array.');
37 }
38
39 $result = array();
40
41 foreach ($this->partMapping as $partKey => $originalKeys) {
42 if (empty($array)) {
43 $result[$partKey] = null;
44 } else {
45 $result[$partKey] = array_intersect_key($array, array_flip($originalKeys));
46 }
47 }
48
49 return $result;
50 }
51
52 public function reverseTransform($array)
53 {
54 if (!is_array($array) ) {
55 throw new TransformationFailedException('Expected an array.');
56 }
57
58 $result = array();
59 $emptyKeys = array();
60
61 foreach ($this->partMapping as $partKey => $originalKeys) {
62 if (!empty($array[$partKey])) {
63 foreach ($originalKeys as $originalKey) {
64 if (isset($array[$partKey][$originalKey])) {
65 $result[$originalKey] = $array[$partKey][$originalKey];
66 }
67 }
68 } else {
69 $emptyKeys[] = $partKey;
70 }
71 }
72
73 if (count($emptyKeys) > 0) {
74 if (count($emptyKeys) === count($this->partMapping)) {
75 // All parts empty
76 return null;
77 }
78
79 throw new TransformationFailedException(
80 sprintf('The keys "%s" should not be empty', implode('", "', $emptyKeys)
81 ));
82 }
83
84 return $result;
85 }
86}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/BaseDateTimeTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/BaseDateTimeTransformer.php
new file mode 100644
index 00000000..e4e8932e
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/BaseDateTimeTransformer.php
@@ -0,0 +1,52 @@
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\DataTransformer;
13
14use Symfony\Component\Form\DataTransformerInterface;
15use Symfony\Component\Form\Exception\UnexpectedTypeException;
16
17abstract class BaseDateTimeTransformer implements DataTransformerInterface
18{
19 protected static $formats = array(
20 \IntlDateFormatter::NONE,
21 \IntlDateFormatter::FULL,
22 \IntlDateFormatter::LONG,
23 \IntlDateFormatter::MEDIUM,
24 \IntlDateFormatter::SHORT,
25 );
26
27 protected $inputTimezone;
28
29 protected $outputTimezone;
30
31 /**
32 * Constructor.
33 *
34 * @param string $inputTimezone The name of the input timezone
35 * @param string $outputTimezone The name of the output timezone
36 *
37 * @throws UnexpectedTypeException if a timezone is not a string
38 */
39 public function __construct($inputTimezone = null, $outputTimezone = null)
40 {
41 if (!is_string($inputTimezone) && null !== $inputTimezone) {
42 throw new UnexpectedTypeException($inputTimezone, 'string');
43 }
44
45 if (!is_string($outputTimezone) && null !== $outputTimezone) {
46 throw new UnexpectedTypeException($outputTimezone, 'string');
47 }
48
49 $this->inputTimezone = $inputTimezone ?: date_default_timezone_get();
50 $this->outputTimezone = $outputTimezone ?: date_default_timezone_get();
51 }
52}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/BooleanToStringTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/BooleanToStringTransformer.php
new file mode 100644
index 00000000..95e7332d
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/BooleanToStringTransformer.php
@@ -0,0 +1,85 @@
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\DataTransformer;
13
14use Symfony\Component\Form\DataTransformerInterface;
15use Symfony\Component\Form\Exception\TransformationFailedException;
16
17/**
18 * Transforms between a Boolean and a string.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 * @author Florian Eckerstorfer <florian@eckerstorfer.org>
22 */
23class BooleanToStringTransformer implements DataTransformerInterface
24{
25 /**
26 * The value emitted upon transform if the input is true
27 * @var string
28 */
29 private $trueValue;
30
31 /**
32 * Sets the value emitted upon transform if the input is true.
33 *
34 * @param string $trueValue
35 */
36 public function __construct($trueValue)
37 {
38 $this->trueValue = $trueValue;
39 }
40
41 /**
42 * Transforms a Boolean into a string.
43 *
44 * @param Boolean $value Boolean value.
45 *
46 * @return string String value.
47 *
48 * @throws TransformationFailedException If the given value is not a Boolean.
49 */
50 public function transform($value)
51 {
52 if (null === $value) {
53 return null;
54 }
55
56 if (!is_bool($value)) {
57 throw new TransformationFailedException('Expected a Boolean.');
58 }
59
60 return true === $value ? $this->trueValue : null;
61 }
62
63 /**
64 * Transforms a string into a Boolean.
65 *
66 * @param string $value String value.
67 *
68 * @return Boolean Boolean value.
69 *
70 * @throws TransformationFailedException If the given value is not a string.
71 */
72 public function reverseTransform($value)
73 {
74 if (null === $value) {
75 return false;
76 }
77
78 if (!is_string($value)) {
79 throw new TransformationFailedException('Expected a string.');
80 }
81
82 return true;
83 }
84
85}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToBooleanArrayTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToBooleanArrayTransformer.php
new file mode 100644
index 00000000..79b3f7ac
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToBooleanArrayTransformer.php
@@ -0,0 +1,118 @@
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\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
15use Symfony\Component\Form\DataTransformerInterface;
16use Symfony\Component\Form\Exception\TransformationFailedException;
17
18/**
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class ChoiceToBooleanArrayTransformer implements DataTransformerInterface
22{
23 private $choiceList;
24
25 private $placeholderPresent;
26
27 /**
28 * Constructor.
29 *
30 * @param ChoiceListInterface $choiceList
31 * @param Boolean $placeholderPresent
32 */
33 public function __construct(ChoiceListInterface $choiceList, $placeholderPresent)
34 {
35 $this->choiceList = $choiceList;
36 $this->placeholderPresent = $placeholderPresent;
37 }
38
39 /**
40 * Transforms a single choice to a format appropriate for the nested
41 * checkboxes/radio buttons.
42 *
43 * The result is an array with the options as keys and true/false as values,
44 * depending on whether a given option is selected. If this field is rendered
45 * as select tag, the value is not modified.
46 *
47 * @param mixed $choice An array if "multiple" is set to true, a scalar
48 * value otherwise.
49 *
50 * @return mixed An array
51 *
52 * @throws TransformationFailedException If the given value is not scalar or
53 * if the choices can not be retrieved.
54 */
55 public function transform($choice)
56 {
57 try {
58 $values = $this->choiceList->getValues();
59 } catch (\Exception $e) {
60 throw new TransformationFailedException('Can not get the choice list', $e->getCode(), $e);
61 }
62
63 $index = current($this->choiceList->getIndicesForChoices(array($choice)));
64
65 foreach ($values as $i => $value) {
66 $values[$i] = $i === $index;
67 }
68
69 if ($this->placeholderPresent) {
70 $values['placeholder'] = false === $index;
71 }
72
73 return $values;
74 }
75
76 /**
77 * Transforms a checkbox/radio button array to a single choice.
78 *
79 * The input value is an array with the choices as keys and true/false as
80 * values, depending on whether a given choice is selected. The output
81 * is the selected choice.
82 *
83 * @param array $values An array of values
84 *
85 * @return mixed A scalar value
86 *
87 * @throws TransformationFailedException If the given value is not an array,
88 * if the recuperation of the choices
89 * fails or if some choice can't be
90 * found.
91 */
92 public function reverseTransform($values)
93 {
94 if (!is_array($values)) {
95 throw new TransformationFailedException('Expected an array.');
96 }
97
98 try {
99 $choices = $this->choiceList->getChoices();
100 } catch (\Exception $e) {
101 throw new TransformationFailedException('Can not get the choice list', $e->getCode(), $e);
102 }
103
104 foreach ($values as $i => $selected) {
105 if ($selected) {
106 if (isset($choices[$i])) {
107 return $choices[$i] === '' ? null : $choices[$i];
108 } elseif ($this->placeholderPresent && 'placeholder' === $i) {
109 return null;
110 } else {
111 throw new TransformationFailedException(sprintf('The choice "%s" does not exist', $i));
112 }
113 }
114 }
115
116 return null;
117 }
118}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php
new file mode 100644
index 00000000..5a818558
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php
@@ -0,0 +1,62 @@
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\DataTransformer;
13
14use Symfony\Component\Form\DataTransformerInterface;
15use Symfony\Component\Form\Exception\TransformationFailedException;
16use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
17
18/**
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class ChoiceToValueTransformer implements DataTransformerInterface
22{
23 private $choiceList;
24
25 /**
26 * Constructor.
27 *
28 * @param ChoiceListInterface $choiceList
29 */
30 public function __construct(ChoiceListInterface $choiceList)
31 {
32 $this->choiceList = $choiceList;
33 }
34
35 public function transform($choice)
36 {
37 return (string) current($this->choiceList->getValuesForChoices(array($choice)));
38 }
39
40 public function reverseTransform($value)
41 {
42 if (null !== $value && !is_scalar($value)) {
43 throw new TransformationFailedException('Expected a scalar.');
44 }
45
46 // These are now valid ChoiceList values, so we can return null
47 // right away
48 if ('' === $value || null === $value) {
49 return null;
50 }
51
52 $choices = $this->choiceList->getChoicesForValues(array($value));
53
54 if (1 !== count($choices)) {
55 throw new TransformationFailedException(sprintf('The choice "%s" does not exist or is not unique', $value));
56 }
57
58 $choice = current($choices);
59
60 return '' === $choice ? null : $choice;
61 }
62}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToBooleanArrayTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToBooleanArrayTransformer.php
new file mode 100644
index 00000000..a13c0d4d
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToBooleanArrayTransformer.php
@@ -0,0 +1,117 @@
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\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
15use Symfony\Component\Form\DataTransformerInterface;
16use Symfony\Component\Form\Exception\TransformationFailedException;
17
18/**
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class ChoicesToBooleanArrayTransformer implements DataTransformerInterface
22{
23 private $choiceList;
24
25 public function __construct(ChoiceListInterface $choiceList)
26 {
27 $this->choiceList = $choiceList;
28 }
29
30 /**
31 * Transforms an array of choices to a format appropriate for the nested
32 * checkboxes/radio buttons.
33 *
34 * The result is an array with the options as keys and true/false as values,
35 * depending on whether a given option is selected. If this field is rendered
36 * as select tag, the value is not modified.
37 *
38 * @param mixed $array An array
39 *
40 * @return mixed An array
41 *
42 * @throws TransformationFailedException If the given value is not an array
43 * or if the choices can not be retrieved.
44 */
45 public function transform($array)
46 {
47 if (null === $array) {
48 return array();
49 }
50
51 if (!is_array($array)) {
52 throw new TransformationFailedException('Expected an array.');
53 }
54
55 try {
56 $values = $this->choiceList->getValues();
57 } catch (\Exception $e) {
58 throw new TransformationFailedException('Can not get the choice list', $e->getCode(), $e);
59 }
60
61 $indexMap = array_flip($this->choiceList->getIndicesForChoices($array));
62
63 foreach ($values as $i => $value) {
64 $values[$i] = isset($indexMap[$i]);
65 }
66
67 return $values;
68 }
69
70 /**
71 * Transforms a checkbox/radio button array to an array of choices.
72 *
73 * The input value is an array with the choices as keys and true/false as
74 * values, depending on whether a given choice is selected. The output
75 * is an array with the selected choices.
76 *
77 * @param mixed $values An array
78 *
79 * @return mixed An array
80 *
81 * @throws TransformationFailedException If the given value is not an array,
82 * if the recuperation of the choices
83 * fails or if some choice can't be
84 * found.
85 */
86 public function reverseTransform($values)
87 {
88 if (!is_array($values)) {
89 throw new TransformationFailedException('Expected an array.');
90 }
91
92 try {
93 $choices = $this->choiceList->getChoices();
94 } catch (\Exception $e) {
95 throw new TransformationFailedException('Can not get the choice list', $e->getCode(), $e);
96 }
97
98 $result = array();
99 $unknown = array();
100
101 foreach ($values as $i => $selected) {
102 if ($selected) {
103 if (isset($choices[$i])) {
104 $result[] = $choices[$i];
105 } else {
106 $unknown[] = $i;
107 }
108 }
109 }
110
111 if (count($unknown) > 0) {
112 throw new TransformationFailedException(sprintf('The choices "%s" were not found', implode('", "', $unknown)));
113 }
114
115 return $result;
116 }
117}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php
new file mode 100644
index 00000000..4492865e
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php
@@ -0,0 +1,83 @@
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\DataTransformer;
13
14use Symfony\Component\Form\Exception\TransformationFailedException;
15
16use Symfony\Component\Form\DataTransformerInterface;
17use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
18
19/**
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class ChoicesToValuesTransformer implements DataTransformerInterface
23{
24 private $choiceList;
25
26 /**
27 * Constructor.
28 *
29 * @param ChoiceListInterface $choiceList
30 */
31 public function __construct(ChoiceListInterface $choiceList)
32 {
33 $this->choiceList = $choiceList;
34 }
35
36 /**
37 * @param array $array
38 *
39 * @return array
40 *
41 * @throws TransformationFailedException If the given value is not an array.
42 */
43 public function transform($array)
44 {
45 if (null === $array) {
46 return array();
47 }
48
49 if (!is_array($array)) {
50 throw new TransformationFailedException('Expected an array.');
51 }
52
53 return $this->choiceList->getValuesForChoices($array);
54 }
55
56 /**
57 * @param array $array
58 *
59 * @return array
60 *
61 * @throws TransformationFailedException If the given value is not an array
62 * or if no matching choice could be
63 * found for some given value.
64 */
65 public function reverseTransform($array)
66 {
67 if (null === $array) {
68 return array();
69 }
70
71 if (!is_array($array)) {
72 throw new TransformationFailedException('Expected an array.');
73 }
74
75 $choices = $this->choiceList->getChoicesForValues($array);
76
77 if (count($choices) !== count($array)) {
78 throw new TransformationFailedException('Could not find all matching choices for the given values');
79 }
80
81 return $choices;
82 }
83}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DataTransformerChain.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DataTransformerChain.php
new file mode 100644
index 00000000..9cc185e1
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DataTransformerChain.php
@@ -0,0 +1,86 @@
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\DataTransformer;
13
14use Symfony\Component\Form\DataTransformerInterface;
15use Symfony\Component\Form\Exception\TransformationFailedException;
16
17/**
18 * Passes a value through multiple value transformers
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class DataTransformerChain implements DataTransformerInterface
23{
24 /**
25 * The value transformers
26 * @var DataTransformerInterface[]
27 */
28 protected $transformers;
29
30 /**
31 * Uses the given value transformers to transform values
32 *
33 * @param array $transformers
34 */
35 public function __construct(array $transformers)
36 {
37 $this->transformers = $transformers;
38 }
39
40 /**
41 * Passes the value through the transform() method of all nested transformers
42 *
43 * The transformers receive the value in the same order as they were passed
44 * to the constructor. Each transformer receives the result of the previous
45 * transformer as input. The output of the last transformer is returned
46 * by this method.
47 *
48 * @param mixed $value The original value
49 *
50 * @return mixed The transformed value
51 *
52 * @throws TransformationFailedException
53 */
54 public function transform($value)
55 {
56 foreach ($this->transformers as $transformer) {
57 $value = $transformer->transform($value);
58 }
59
60 return $value;
61 }
62
63 /**
64 * Passes the value through the reverseTransform() method of all nested
65 * transformers
66 *
67 * The transformers receive the value in the reverse order as they were passed
68 * to the constructor. Each transformer receives the result of the previous
69 * transformer as input. The output of the last transformer is returned
70 * by this method.
71 *
72 * @param mixed $value The transformed value
73 *
74 * @return mixed The reverse-transformed value
75 *
76 * @throws TransformationFailedException
77 */
78 public function reverseTransform($value)
79 {
80 for ($i = count($this->transformers) - 1; $i >= 0; --$i) {
81 $value = $this->transformers[$i]->reverseTransform($value);
82 }
83
84 return $value;
85 }
86}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php
new file mode 100644
index 00000000..34af2820
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.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\DataTransformer;
13
14use Symfony\Component\Form\Exception\TransformationFailedException;
15use Symfony\Component\Form\Exception\UnexpectedTypeException;
16
17/**
18 * Transforms between a normalized time and a localized time string/array.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 * @author Florian Eckerstorfer <florian@eckerstorfer.org>
22 */
23class DateTimeToArrayTransformer extends BaseDateTimeTransformer
24{
25 private $pad;
26
27 private $fields;
28
29 /**
30 * Constructor.
31 *
32 * @param string $inputTimezone The input timezone
33 * @param string $outputTimezone The output timezone
34 * @param array $fields The date fields
35 * @param Boolean $pad Whether to use padding
36 *
37 * @throws UnexpectedTypeException if a timezone is not a string
38 */
39 public function __construct($inputTimezone = null, $outputTimezone = null, array $fields = null, $pad = false)
40 {
41 parent::__construct($inputTimezone, $outputTimezone);
42
43 if (null === $fields) {
44 $fields = array('year', 'month', 'day', 'hour', 'minute', 'second');
45 }
46
47 $this->fields = $fields;
48 $this->pad = (Boolean) $pad;
49 }
50
51 /**
52 * Transforms a normalized date into a localized date.
53 *
54 * @param \DateTime $dateTime Normalized date.
55 *
56 * @return array Localized date.
57 *
58 * @throws TransformationFailedException If the given value is not an
59 * instance of \DateTime or if the
60 * output timezone is not supported.
61 */
62 public function transform($dateTime)
63 {
64 if (null === $dateTime) {
65 return array_intersect_key(array(
66 'year' => '',
67 'month' => '',
68 'day' => '',
69 'hour' => '',
70 'minute' => '',
71 'second' => '',
72 ), array_flip($this->fields));
73 }
74
75 if (!$dateTime instanceof \DateTime) {
76 throw new TransformationFailedException('Expected a \DateTime.');
77 }
78
79 $dateTime = clone $dateTime;
80 if ($this->inputTimezone !== $this->outputTimezone) {
81 try {
82 $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
83 } catch (\Exception $e) {
84 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
85 }
86 }
87
88 $result = array_intersect_key(array(
89 'year' => $dateTime->format('Y'),
90 'month' => $dateTime->format('m'),
91 'day' => $dateTime->format('d'),
92 'hour' => $dateTime->format('H'),
93 'minute' => $dateTime->format('i'),
94 'second' => $dateTime->format('s'),
95 ), array_flip($this->fields));
96
97 if (!$this->pad) {
98 foreach ($result as &$entry) {
99 // remove leading zeros
100 $entry = (string) (int) $entry;
101 }
102 }
103
104 return $result;
105 }
106
107 /**
108 * Transforms a localized date into a normalized date.
109 *
110 * @param array $value Localized date
111 *
112 * @return \DateTime Normalized date
113 *
114 * @throws TransformationFailedException If the given value is not an array,
115 * if the value could not be transformed
116 * or if the input timezone is not
117 * supported.
118 */
119 public function reverseTransform($value)
120 {
121 if (null === $value) {
122 return null;
123 }
124
125 if (!is_array($value)) {
126 throw new TransformationFailedException('Expected an array.');
127 }
128
129 if ('' === implode('', $value)) {
130 return null;
131 }
132
133 $emptyFields = array();
134
135 foreach ($this->fields as $field) {
136 if (!isset($value[$field])) {
137 $emptyFields[] = $field;
138 }
139 }
140
141 if (count($emptyFields) > 0) {
142 throw new TransformationFailedException(
143 sprintf('The fields "%s" should not be empty', implode('", "', $emptyFields)
144 ));
145 }
146
147 if (isset($value['month']) && !ctype_digit($value['month']) && !is_int($value['month'])) {
148 throw new TransformationFailedException('This month is invalid');
149 }
150
151 if (isset($value['day']) && !ctype_digit($value['day']) && !is_int($value['day'])) {
152 throw new TransformationFailedException('This day is invalid');
153 }
154
155 if (isset($value['year']) && !ctype_digit($value['year']) && !is_int($value['year'])) {
156 throw new TransformationFailedException('This year is invalid');
157 }
158
159 if (!empty($value['month']) && !empty($value['day']) && !empty($value['year']) && false === checkdate($value['month'], $value['day'], $value['year'])) {
160 throw new TransformationFailedException('This is an invalid date');
161 }
162
163 try {
164 $dateTime = new \DateTime(sprintf(
165 '%s-%s-%s %s:%s:%s %s',
166 empty($value['year']) ? '1970' : $value['year'],
167 empty($value['month']) ? '1' : $value['month'],
168 empty($value['day']) ? '1' : $value['day'],
169 empty($value['hour']) ? '0' : $value['hour'],
170 empty($value['minute']) ? '0' : $value['minute'],
171 empty($value['second']) ? '0' : $value['second'],
172 $this->outputTimezone
173 ));
174
175 if ($this->inputTimezone !== $this->outputTimezone) {
176 $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
177 }
178 } catch (\Exception $e) {
179 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
180 }
181
182 return $dateTime;
183 }
184}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
new file mode 100644
index 00000000..d755e485
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
@@ -0,0 +1,169 @@
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\DataTransformer;
13
14use Symfony\Component\Form\Exception\TransformationFailedException;
15use Symfony\Component\Form\Exception\UnexpectedTypeException;
16
17/**
18 * Transforms between a normalized time and a localized time string
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 * @author Florian Eckerstorfer <florian@eckerstorfer.org>
22 */
23class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer
24{
25 private $dateFormat;
26 private $timeFormat;
27 private $pattern;
28 private $calendar;
29
30 /**
31 * Constructor.
32 *
33 * @see BaseDateTimeTransformer::formats for available format options
34 *
35 * @param string $inputTimezone The name of the input timezone
36 * @param string $outputTimezone The name of the output timezone
37 * @param integer $dateFormat The date format
38 * @param integer $timeFormat The time format
39 * @param integer $calendar One of the \IntlDateFormatter calendar constants
40 * @param string $pattern A pattern to pass to \IntlDateFormatter
41 *
42 * @throws UnexpectedTypeException If a format is not supported or if a timezone is not a string
43 */
44 public function __construct($inputTimezone = null, $outputTimezone = null, $dateFormat = null, $timeFormat = null, $calendar = \IntlDateFormatter::GREGORIAN, $pattern = null)
45 {
46 parent::__construct($inputTimezone, $outputTimezone);
47
48 if (null === $dateFormat) {
49 $dateFormat = \IntlDateFormatter::MEDIUM;
50 }
51
52 if (null === $timeFormat) {
53 $timeFormat = \IntlDateFormatter::SHORT;
54 }
55
56 if (!in_array($dateFormat, self::$formats, true)) {
57 throw new UnexpectedTypeException($dateFormat, implode('", "', self::$formats));
58 }
59
60 if (!in_array($timeFormat, self::$formats, true)) {
61 throw new UnexpectedTypeException($timeFormat, implode('", "', self::$formats));
62 }
63
64 $this->dateFormat = $dateFormat;
65 $this->timeFormat = $timeFormat;
66 $this->calendar = $calendar;
67 $this->pattern = $pattern;
68 }
69
70 /**
71 * Transforms a normalized date into a localized date string/array.
72 *
73 * @param \DateTime $dateTime Normalized date.
74 *
75 * @return string|array Localized date string/array.
76 *
77 * @throws TransformationFailedException If the given value is not an instance
78 * of \DateTime or if the date could not
79 * be transformed.
80 */
81 public function transform($dateTime)
82 {
83 if (null === $dateTime) {
84 return '';
85 }
86
87 if (!$dateTime instanceof \DateTime) {
88 throw new TransformationFailedException('Expected a \DateTime.');
89 }
90
91 // convert time to UTC before passing it to the formatter
92 $dateTime = clone $dateTime;
93 if ('UTC' !== $this->inputTimezone) {
94 $dateTime->setTimezone(new \DateTimeZone('UTC'));
95 }
96
97 $value = $this->getIntlDateFormatter()->format((int) $dateTime->format('U'));
98
99 if (intl_get_error_code() != 0) {
100 throw new TransformationFailedException(intl_get_error_message());
101 }
102
103 return $value;
104 }
105
106 /**
107 * Transforms a localized date string/array into a normalized date.
108 *
109 * @param string|array $value Localized date string/array
110 *
111 * @return \DateTime Normalized date
112 *
113 * @throws TransformationFailedException if the given value is not a string,
114 * if the date could not be parsed or
115 * if the input timezone is not supported
116 */
117 public function reverseTransform($value)
118 {
119 if (!is_string($value)) {
120 throw new TransformationFailedException('Expected a string.');
121 }
122
123 if ('' === $value) {
124 return null;
125 }
126
127 $timestamp = $this->getIntlDateFormatter()->parse($value);
128
129 if (intl_get_error_code() != 0) {
130 throw new TransformationFailedException(intl_get_error_message());
131 }
132
133 try {
134 // read timestamp into DateTime object - the formatter delivers in UTC
135 $dateTime = new \DateTime(sprintf('@%s UTC', $timestamp));
136 } catch (\Exception $e) {
137 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
138 }
139
140 if ('UTC' !== $this->inputTimezone) {
141 try {
142 $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
143 } catch (\Exception $e) {
144 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
145 }
146 }
147
148 return $dateTime;
149 }
150
151 /**
152 * Returns a preconfigured IntlDateFormatter instance
153 *
154 * @return \IntlDateFormatter
155 */
156 protected function getIntlDateFormatter()
157 {
158 $dateFormat = $this->dateFormat;
159 $timeFormat = $this->timeFormat;
160 $timezone = $this->outputTimezone;
161 $calendar = $this->calendar;
162 $pattern = $this->pattern;
163
164 $intlDateFormatter = new \IntlDateFormatter(\Locale::getDefault(), $dateFormat, $timeFormat, $timezone, $calendar, $pattern);
165 $intlDateFormatter->setLenient(false);
166
167 return $intlDateFormatter;
168 }
169}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php
new file mode 100644
index 00000000..0eb07422
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php
@@ -0,0 +1,82 @@
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\DataTransformer;
13
14use Symfony\Component\Form\Exception\TransformationFailedException;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class DateTimeToRfc3339Transformer extends BaseDateTimeTransformer
20{
21 /**
22 * {@inheritDoc}
23 */
24 public function transform($dateTime)
25 {
26 if (null === $dateTime) {
27 return '';
28 }
29
30 if (!$dateTime instanceof \DateTime) {
31 throw new TransformationFailedException('Expected a \DateTime.');
32 }
33
34 if ($this->inputTimezone !== $this->outputTimezone) {
35 $dateTime = clone $dateTime;
36 $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
37 }
38
39 return preg_replace('/\+00:00$/', 'Z', $dateTime->format('c'));
40 }
41
42 /**
43 * {@inheritDoc}
44 */
45 public function reverseTransform($rfc3339)
46 {
47 if (!is_string($rfc3339)) {
48 throw new TransformationFailedException('Expected a string.');
49 }
50
51 if ('' === $rfc3339) {
52 return null;
53 }
54
55 try {
56 $dateTime = new \DateTime($rfc3339);
57 } catch (\Exception $e) {
58 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
59 }
60
61 if ($this->outputTimezone !== $this->inputTimezone) {
62 try {
63 $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
64 } catch (\Exception $e) {
65 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
66 }
67 }
68
69 if (preg_match('/(\d{4})-(\d{2})-(\d{2})/', $rfc3339, $matches)) {
70 if (!checkdate($matches[2], $matches[3], $matches[1])) {
71 throw new TransformationFailedException(sprintf(
72 'The date "%s-%s-%s" is not a valid date.',
73 $matches[1],
74 $matches[2],
75 $matches[3]
76 ));
77 }
78 }
79
80 return $dateTime;
81 }
82}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php
new file mode 100644
index 00000000..131f45cb
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php
@@ -0,0 +1,231 @@
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\DataTransformer;
13
14use Symfony\Component\Form\Exception\TransformationFailedException;
15use Symfony\Component\Form\Exception\UnexpectedTypeException;
16
17/**
18 * Transforms between a date string and a DateTime object
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 * @author Florian Eckerstorfer <florian@eckerstorfer.org>
22 */
23class DateTimeToStringTransformer extends BaseDateTimeTransformer
24{
25 /**
26 * Format used for generating strings
27 * @var string
28 */
29 private $generateFormat;
30
31 /**
32 * Format used for parsing strings
33 *
34 * Different than the {@link $generateFormat} because formats for parsing
35 * support additional characters in PHP that are not supported for
36 * generating strings.
37 *
38 * @var string
39 */
40 private $parseFormat;
41
42 /**
43 * Whether to parse by appending a pipe "|" to the parse format.
44 *
45 * This only works as of PHP 5.3.7.
46 *
47 * @var Boolean
48 */
49 private $parseUsingPipe;
50
51 /**
52 * Transforms a \DateTime instance to a string
53 *
54 * @see \DateTime::format() for supported formats
55 *
56 * @param string $inputTimezone The name of the input timezone
57 * @param string $outputTimezone The name of the output timezone
58 * @param string $format The date format
59 * @param Boolean $parseUsingPipe Whether to parse by appending a pipe "|" to the parse format
60 *
61 * @throws UnexpectedTypeException if a timezone is not a string
62 */
63 public function __construct($inputTimezone = null, $outputTimezone = null, $format = 'Y-m-d H:i:s', $parseUsingPipe = null)
64 {
65 parent::__construct($inputTimezone, $outputTimezone);
66
67 $this->generateFormat = $this->parseFormat = $format;
68
69 // The pipe in the parser pattern only works as of PHP 5.3.7
70 // See http://bugs.php.net/54316
71 $this->parseUsingPipe = null === $parseUsingPipe
72 ? version_compare(phpversion(), '5.3.7', '>=')
73 : $parseUsingPipe;
74
75 // See http://php.net/manual/en/datetime.createfromformat.php
76 // The character "|" in the format makes sure that the parts of a date
77 // that are *not* specified in the format are reset to the corresponding
78 // values from 1970-01-01 00:00:00 instead of the current time.
79 // Without "|" and "Y-m-d", "2010-02-03" becomes "2010-02-03 12:32:47",
80 // where the time corresponds to the current server time.
81 // With "|" and "Y-m-d", "2010-02-03" becomes "2010-02-03 00:00:00",
82 // which is at least deterministic and thus used here.
83 if ($this->parseUsingPipe && false === strpos($this->parseFormat, '|')) {
84 $this->parseFormat .= '|';
85 }
86 }
87
88 /**
89 * Transforms a DateTime object into a date string with the configured format
90 * and timezone
91 *
92 * @param \DateTime $value A DateTime object
93 *
94 * @return string A value as produced by PHP's date() function
95 *
96 * @throws TransformationFailedException If the given value is not a \DateTime
97 * instance or if the output timezone
98 * is not supported.
99 */
100 public function transform($value)
101 {
102 if (null === $value) {
103 return '';
104 }
105
106 if (!$value instanceof \DateTime) {
107 throw new TransformationFailedException('Expected a \DateTime.');
108 }
109
110 $value = clone $value;
111 try {
112 $value->setTimezone(new \DateTimeZone($this->outputTimezone));
113 } catch (\Exception $e) {
114 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
115 }
116
117 return $value->format($this->generateFormat);
118 }
119
120 /**
121 * Transforms a date string in the configured timezone into a DateTime object.
122 *
123 * @param string $value A value as produced by PHP's date() function
124 *
125 * @return \DateTime An instance of \DateTime
126 *
127 * @throws TransformationFailedException If the given value is not a string,
128 * if the date could not be parsed or
129 * if the input timezone is not supported.
130 */
131 public function reverseTransform($value)
132 {
133 if (empty($value)) {
134 return null;
135 }
136
137 if (!is_string($value)) {
138 throw new TransformationFailedException('Expected a string.');
139 }
140
141 try {
142 $outputTz = new \DateTimeZone($this->outputTimezone);
143 $dateTime = \DateTime::createFromFormat($this->parseFormat, $value, $outputTz);
144
145 $lastErrors = \DateTime::getLastErrors();
146
147 if (0 < $lastErrors['warning_count'] || 0 < $lastErrors['error_count']) {
148 throw new TransformationFailedException(
149 implode(', ', array_merge(
150 array_values($lastErrors['warnings']),
151 array_values($lastErrors['errors'])
152 ))
153 );
154 }
155
156 // On PHP versions < 5.3.7 we need to emulate the pipe operator
157 // and reset parts not given in the format to their equivalent
158 // of the UNIX base timestamp.
159 if (!$this->parseUsingPipe) {
160 list($year, $month, $day, $hour, $minute, $second) = explode('-', $dateTime->format('Y-m-d-H-i-s'));
161
162 // Check which of the date parts are present in the pattern
163 preg_match(
164 '/(' .
165 '(?P<day>[djDl])|' .
166 '(?P<month>[FMmn])|' .
167 '(?P<year>[Yy])|' .
168 '(?P<hour>[ghGH])|' .
169 '(?P<minute>i)|' .
170 '(?P<second>s)|' .
171 '(?P<dayofyear>z)|' .
172 '(?P<timestamp>U)|' .
173 '[^djDlFMmnYyghGHiszU]' .
174 ')*/',
175 $this->parseFormat,
176 $matches
177 );
178
179 // preg_match() does not guarantee to set all indices, so
180 // set them unless given
181 $matches = array_merge(array(
182 'day' => false,
183 'month' => false,
184 'year' => false,
185 'hour' => false,
186 'minute' => false,
187 'second' => false,
188 'dayofyear' => false,
189 'timestamp' => false,
190 ), $matches);
191
192 // Reset all parts that don't exist in the format to the
193 // corresponding part of the UNIX base timestamp
194 if (!$matches['timestamp']) {
195 if (!$matches['dayofyear']) {
196 if (!$matches['day']) {
197 $day = 1;
198 }
199 if (!$matches['month']) {
200 $month = 1;
201 }
202 }
203 if (!$matches['year']) {
204 $year = 1970;
205 }
206 if (!$matches['hour']) {
207 $hour = 0;
208 }
209 if (!$matches['minute']) {
210 $minute = 0;
211 }
212 if (!$matches['second']) {
213 $second = 0;
214 }
215 $dateTime->setDate($year, $month, $day);
216 $dateTime->setTime($hour, $minute, $second);
217 }
218 }
219
220 if ($this->inputTimezone !== $this->outputTimezone) {
221 $dateTime->setTimeZone(new \DateTimeZone($this->inputTimezone));
222 }
223 } catch (TransformationFailedException $e) {
224 throw $e;
225 } catch (\Exception $e) {
226 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
227 }
228
229 return $dateTime;
230 }
231}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToTimestampTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToTimestampTransformer.php
new file mode 100644
index 00000000..d2ca6604
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToTimestampTransformer.php
@@ -0,0 +1,89 @@
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\DataTransformer;
13
14use Symfony\Component\Form\Exception\TransformationFailedException;
15
16/**
17 * Transforms between a timestamp and a DateTime object
18 *
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 * @author Florian Eckerstorfer <florian@eckerstorfer.org>
21 */
22class DateTimeToTimestampTransformer extends BaseDateTimeTransformer
23{
24 /**
25 * Transforms a DateTime object into a timestamp in the configured timezone.
26 *
27 * @param \DateTime $value A \DateTime object
28 *
29 * @return integer A timestamp
30 *
31 * @throws TransformationFailedException If the given value is not an instance
32 * of \DateTime or if the output
33 * timezone is not supported.
34 */
35 public function transform($value)
36 {
37 if (null === $value) {
38 return null;
39 }
40
41 if (!$value instanceof \DateTime) {
42 throw new TransformationFailedException('Expected a \DateTime.');
43 }
44
45 $value = clone $value;
46 try {
47 $value->setTimezone(new \DateTimeZone($this->outputTimezone));
48 } catch (\Exception $e) {
49 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
50 }
51
52 return (int) $value->format('U');
53 }
54
55 /**
56 * Transforms a timestamp in the configured timezone into a DateTime object
57 *
58 * @param string $value A timestamp
59 *
60 * @return \DateTime A \DateTime object
61 *
62 * @throws TransformationFailedException If the given value is not a timestamp
63 * or if the given timestamp is invalid.
64 */
65 public function reverseTransform($value)
66 {
67 if (null === $value) {
68 return null;
69 }
70
71 if (!is_numeric($value)) {
72 throw new TransformationFailedException('Expected a numeric.');
73 }
74
75 try {
76 $dateTime = new \DateTime();
77 $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
78 $dateTime->setTimestamp($value);
79
80 if ($this->inputTimezone !== $this->outputTimezone) {
81 $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
82 }
83 } catch (\Exception $e) {
84 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
85 }
86
87 return $dateTime;
88 }
89}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php
new file mode 100644
index 00000000..6bb48a9a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php
@@ -0,0 +1,53 @@
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\DataTransformer;
13
14use Symfony\Component\Form\Exception\TransformationFailedException;
15
16/**
17 * Transforms between an integer and a localized number with grouping
18 * (each thousand) and comma separators.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class IntegerToLocalizedStringTransformer extends NumberToLocalizedStringTransformer
23{
24 /**
25 * {@inheritDoc}
26 */
27 public function reverseTransform($value)
28 {
29 if (!is_string($value)) {
30 throw new TransformationFailedException('Expected a string.');
31 }
32
33 if ('' === $value) {
34 return null;
35 }
36
37 if ('NaN' === $value) {
38 throw new TransformationFailedException('"NaN" is not a valid integer');
39 }
40
41 $formatter = $this->getNumberFormatter();
42 $value = $formatter->parse(
43 $value,
44 PHP_INT_SIZE == 8 ? $formatter::TYPE_INT64 : $formatter::TYPE_INT32
45 );
46
47 if (intl_is_failure($formatter->getErrorCode())) {
48 throw new TransformationFailedException($formatter->getErrorMessage());
49 }
50
51 return $value;
52 }
53}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php
new file mode 100644
index 00000000..5b8e9d96
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php
@@ -0,0 +1,90 @@
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\DataTransformer;
13
14use Symfony\Component\Form\Exception\TransformationFailedException;
15
16/**
17 * Transforms between a normalized format and a localized money string.
18 *
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 * @author Florian Eckerstorfer <florian@eckerstorfer.org>
21 */
22class MoneyToLocalizedStringTransformer extends NumberToLocalizedStringTransformer
23{
24
25 private $divisor;
26
27 public function __construct($precision = null, $grouping = null, $roundingMode = null, $divisor = null)
28 {
29 if (null === $grouping) {
30 $grouping = true;
31 }
32
33 if (null === $precision) {
34 $precision = 2;
35 }
36
37 parent::__construct($precision, $grouping, $roundingMode);
38
39 if (null === $divisor) {
40 $divisor = 1;
41 }
42
43 $this->divisor = $divisor;
44 }
45
46 /**
47 * Transforms a normalized format into a localized money string.
48 *
49 * @param number $value Normalized number
50 *
51 * @return string Localized money string.
52 *
53 * @throws TransformationFailedException If the given value is not numeric or
54 * if the value can not be transformed.
55 */
56 public function transform($value)
57 {
58 if (null !== $value) {
59 if (!is_numeric($value)) {
60 throw new TransformationFailedException('Expected a numeric.');
61 }
62
63 $value /= $this->divisor;
64 }
65
66 return parent::transform($value);
67 }
68
69 /**
70 * Transforms a localized money string into a normalized format.
71 *
72 * @param string $value Localized money string
73 *
74 * @return number Normalized number
75 *
76 * @throws TransformationFailedException If the given value is not a string
77 * or if the value can not be transformed.
78 */
79 public function reverseTransform($value)
80 {
81 $value = parent::reverseTransform($value);
82
83 if (null !== $value) {
84 $value *= $this->divisor;
85 }
86
87 return $value;
88 }
89
90}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php
new file mode 100644
index 00000000..b0c59b3e
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.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\DataTransformer;
13
14use Symfony\Component\Form\DataTransformerInterface;
15use Symfony\Component\Form\Exception\TransformationFailedException;
16
17/**
18 * Transforms between a number type and a localized number with grouping
19 * (each thousand) and comma separators.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 * @author Florian Eckerstorfer <florian@eckerstorfer.org>
23 */
24class NumberToLocalizedStringTransformer implements DataTransformerInterface
25{
26 const ROUND_FLOOR = \NumberFormatter::ROUND_FLOOR;
27 const ROUND_DOWN = \NumberFormatter::ROUND_DOWN;
28 const ROUND_HALFDOWN = \NumberFormatter::ROUND_HALFDOWN;
29 const ROUND_HALFEVEN = \NumberFormatter::ROUND_HALFEVEN;
30 const ROUND_HALFUP = \NumberFormatter::ROUND_HALFUP;
31 const ROUND_UP = \NumberFormatter::ROUND_UP;
32 const ROUND_CEILING = \NumberFormatter::ROUND_CEILING;
33
34 protected $precision;
35
36 protected $grouping;
37
38 protected $roundingMode;
39
40 public function __construct($precision = null, $grouping = null, $roundingMode = null)
41 {
42 if (null === $grouping) {
43 $grouping = false;
44 }
45
46 if (null === $roundingMode) {
47 $roundingMode = self::ROUND_HALFUP;
48 }
49
50 $this->precision = $precision;
51 $this->grouping = $grouping;
52 $this->roundingMode = $roundingMode;
53 }
54
55 /**
56 * Transforms a number type into localized number.
57 *
58 * @param integer|float $value Number value.
59 *
60 * @return string Localized value.
61 *
62 * @throws TransformationFailedException If the given value is not numeric
63 * or if the value can not be transformed.
64 */
65 public function transform($value)
66 {
67 if (null === $value) {
68 return '';
69 }
70
71 if (!is_numeric($value)) {
72 throw new TransformationFailedException('Expected a numeric.');
73 }
74
75 $formatter = $this->getNumberFormatter();
76 $value = $formatter->format($value);
77
78 if (intl_is_failure($formatter->getErrorCode())) {
79 throw new TransformationFailedException($formatter->getErrorMessage());
80 }
81
82 // Convert fixed spaces to normal ones
83 $value = str_replace("\xc2\xa0", ' ', $value);
84
85 return $value;
86 }
87
88 /**
89 * Transforms a localized number into an integer or float
90 *
91 * @param string $value The localized value
92 *
93 * @return integer|float The numeric value
94 *
95 * @throws TransformationFailedException If the given value is not a string
96 * or if the value can not be transformed.
97 */
98 public function reverseTransform($value)
99 {
100 if (!is_string($value)) {
101 throw new TransformationFailedException('Expected a string.');
102 }
103
104 if ('' === $value) {
105 return null;
106 }
107
108 if ('NaN' === $value) {
109 throw new TransformationFailedException('"NaN" is not a valid number');
110 }
111
112 $position = 0;
113 $formatter = $this->getNumberFormatter();
114 $groupSep = $formatter->getSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL);
115 $decSep = $formatter->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL);
116
117 if ('.' !== $decSep && (!$this->grouping || '.' !== $groupSep)) {
118 $value = str_replace('.', $decSep, $value);
119 }
120
121 if (',' !== $decSep && (!$this->grouping || ',' !== $groupSep)) {
122 $value = str_replace(',', $decSep, $value);
123 }
124
125 $result = $formatter->parse($value, \NumberFormatter::TYPE_DOUBLE, $position);
126
127 if (intl_is_failure($formatter->getErrorCode())) {
128 throw new TransformationFailedException($formatter->getErrorMessage());
129 }
130
131 if ($result >= PHP_INT_MAX || $result <= -PHP_INT_MAX) {
132 throw new TransformationFailedException('I don\'t have a clear idea what infinity looks like');
133 }
134
135 if (function_exists('mb_detect_encoding') && false !== $encoding = mb_detect_encoding($value)) {
136 $strlen = function ($string) use ($encoding) {
137 return mb_strlen($string, $encoding);
138 };
139 $substr = function ($string, $offset, $length) use ($encoding) {
140 return mb_substr($string, $offset, $length, $encoding);
141 };
142 } else {
143 $strlen = 'strlen';
144 $substr = 'substr';
145 }
146
147 $length = $strlen($value);
148
149 // After parsing, position holds the index of the character where the
150 // parsing stopped
151 if ($position < $length) {
152 // Check if there are unrecognized characters at the end of the
153 // number (excluding whitespace characters)
154 $remainder = trim($substr($value, $position, $length), " \t\n\r\0\x0b\xc2\xa0");
155
156 if ('' !== $remainder) {
157 throw new TransformationFailedException(
158 sprintf('The number contains unrecognized characters: "%s"', $remainder)
159 );
160 }
161 }
162
163 return $result;
164 }
165
166 /**
167 * Returns a preconfigured \NumberFormatter instance
168 *
169 * @return \NumberFormatter
170 */
171 protected function getNumberFormatter()
172 {
173 $formatter = new \NumberFormatter(\Locale::getDefault(), \NumberFormatter::DECIMAL);
174
175 if (null !== $this->precision) {
176 $formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, $this->precision);
177 $formatter->setAttribute(\NumberFormatter::ROUNDING_MODE, $this->roundingMode);
178 }
179
180 $formatter->setAttribute(\NumberFormatter::GROUPING_USED, $this->grouping);
181
182 return $formatter;
183 }
184}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php
new file mode 100644
index 00000000..e099d436
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php
@@ -0,0 +1,149 @@
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\DataTransformer;
13
14use Symfony\Component\Form\DataTransformerInterface;
15use Symfony\Component\Form\Exception\TransformationFailedException;
16use Symfony\Component\Form\Exception\UnexpectedTypeException;
17
18/**
19 * Transforms between a normalized format (integer or float) and a percentage value.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 * @author Florian Eckerstorfer <florian@eckerstorfer.org>
23 */
24class PercentToLocalizedStringTransformer implements DataTransformerInterface
25{
26 const FRACTIONAL = 'fractional';
27 const INTEGER = 'integer';
28
29 protected static $types = array(
30 self::FRACTIONAL,
31 self::INTEGER,
32 );
33
34 private $type;
35
36 private $precision;
37
38 /**
39 * Constructor.
40 *
41 * @see self::$types for a list of supported types
42 *
43 * @param integer $precision The precision
44 * @param string $type One of the supported types
45 *
46 * @throws UnexpectedTypeException if the given value of type is unknown
47 */
48 public function __construct($precision = null, $type = null)
49 {
50 if (null === $precision) {
51 $precision = 0;
52 }
53
54 if (null === $type) {
55 $type = self::FRACTIONAL;
56 }
57
58 if (!in_array($type, self::$types, true)) {
59 throw new UnexpectedTypeException($type, implode('", "', self::$types));
60 }
61
62 $this->type = $type;
63 $this->precision = $precision;
64 }
65
66 /**
67 * Transforms between a normalized format (integer or float) into a percentage value.
68 *
69 * @param number $value Normalized value
70 *
71 * @return number Percentage value
72 *
73 * @throws TransformationFailedException If the given value is not numeric or
74 * if the value could not be transformed.
75 */
76 public function transform($value)
77 {
78 if (null === $value) {
79 return '';
80 }
81
82 if (!is_numeric($value)) {
83 throw new TransformationFailedException('Expected a numeric.');
84 }
85
86 if (self::FRACTIONAL == $this->type) {
87 $value *= 100;
88 }
89
90 $formatter = $this->getNumberFormatter();
91 $value = $formatter->format($value);
92
93 if (intl_is_failure($formatter->getErrorCode())) {
94 throw new TransformationFailedException($formatter->getErrorMessage());
95 }
96
97 // replace the UTF-8 non break spaces
98 return $value;
99 }
100
101 /**
102 * Transforms between a percentage value into a normalized format (integer or float).
103 *
104 * @param number $value Percentage value.
105 *
106 * @return number Normalized value.
107 *
108 * @throws TransformationFailedException If the given value is not a string or
109 * if the value could not be transformed.
110 */
111 public function reverseTransform($value)
112 {
113 if (!is_string($value)) {
114 throw new TransformationFailedException('Expected a string.');
115 }
116
117 if ('' === $value) {
118 return null;
119 }
120
121 $formatter = $this->getNumberFormatter();
122 // replace normal spaces so that the formatter can read them
123 $value = $formatter->parse(str_replace(' ', ' ', $value));
124
125 if (intl_is_failure($formatter->getErrorCode())) {
126 throw new TransformationFailedException($formatter->getErrorMessage());
127 }
128
129 if (self::FRACTIONAL == $this->type) {
130 $value /= 100;
131 }
132
133 return $value;
134 }
135
136 /**
137 * Returns a preconfigured \NumberFormatter instance
138 *
139 * @return \NumberFormatter
140 */
141 protected function getNumberFormatter()
142 {
143 $formatter = new \NumberFormatter(\Locale::getDefault(), \NumberFormatter::DECIMAL);
144
145 $formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, $this->precision);
146
147 return $formatter;
148 }
149}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php
new file mode 100644
index 00000000..c34a0139
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php
@@ -0,0 +1,91 @@
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\DataTransformer;
13
14use Symfony\Component\Form\DataTransformerInterface;
15use Symfony\Component\Form\Exception\TransformationFailedException;
16
17/**
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20class ValueToDuplicatesTransformer implements DataTransformerInterface
21{
22 private $keys;
23
24 public function __construct(array $keys)
25 {
26 $this->keys = $keys;
27 }
28
29 /**
30 * Duplicates the given value through the array.
31 *
32 * @param mixed $value The value
33 *
34 * @return array The array
35 */
36 public function transform($value)
37 {
38 $result = array();
39
40 foreach ($this->keys as $key) {
41 $result[$key] = $value;
42 }
43
44 return $result;
45 }
46
47 /**
48 * Extracts the duplicated value from an array.
49 *
50 * @param array $array
51 *
52 * @return mixed The value
53 *
54 * @throws TransformationFailedException If the given value is not an array or
55 * if the given array can not be transformed.
56 */
57 public function reverseTransform($array)
58 {
59 if (!is_array($array)) {
60 throw new TransformationFailedException('Expected an array.');
61 }
62
63 $result = current($array);
64 $emptyKeys = array();
65
66 foreach ($this->keys as $key) {
67 if (!empty($array[$key])) {
68 if ($array[$key] !== $result) {
69 throw new TransformationFailedException(
70 'All values in the array should be the same'
71 );
72 }
73 } else {
74 $emptyKeys[] = $key;
75 }
76 }
77
78 if (count($emptyKeys) > 0) {
79 if (count($emptyKeys) == count($this->keys)) {
80 // All keys empty
81 return null;
82 }
83
84 throw new TransformationFailedException(
85 sprintf('The keys "%s" should not be empty', implode('", "', $emptyKeys)
86 ));
87 }
88
89 return $result;
90 }
91}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixCheckboxInputListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixCheckboxInputListener.php
new file mode 100644
index 00000000..1f62e060
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixCheckboxInputListener.php
@@ -0,0 +1,62 @@
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\EventListener;
13
14use Symfony\Component\Form\FormEvents;
15use Symfony\Component\Form\FormEvent;
16use Symfony\Component\EventDispatcher\EventSubscriberInterface;
17use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
18
19/**
20 * Takes care of converting the input from a list of checkboxes to a correctly
21 * indexed array.
22 *
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25class FixCheckboxInputListener implements EventSubscriberInterface
26{
27 private $choiceList;
28
29 /**
30 * Constructor.
31 *
32 * @param ChoiceListInterface $choiceList
33 */
34 public function __construct(ChoiceListInterface $choiceList)
35 {
36 $this->choiceList = $choiceList;
37 }
38
39 public function preSubmit(FormEvent $event)
40 {
41 $values = (array) $event->getData();
42 $indices = $this->choiceList->getIndicesForValues($values);
43
44 $event->setData(count($indices) > 0 ? array_combine($indices, $values) : array());
45 }
46
47 /**
48 * Alias of {@link preSubmit()}.
49 *
50 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
51 * {@link preSubmit()} instead.
52 */
53 public function preBind(FormEvent $event)
54 {
55 $this->preSubmit($event);
56 }
57
58 public static function getSubscribedEvents()
59 {
60 return array(FormEvents::PRE_SUBMIT => 'preSubmit');
61 }
62}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixRadioInputListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixRadioInputListener.php
new file mode 100644
index 00000000..bf03792f
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixRadioInputListener.php
@@ -0,0 +1,66 @@
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\EventListener;
13
14use Symfony\Component\Form\FormEvents;
15use Symfony\Component\Form\FormEvent;
16use Symfony\Component\EventDispatcher\EventSubscriberInterface;
17use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
18
19/**
20 * Takes care of converting the input from a single radio button
21 * to an array.
22 *
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25class FixRadioInputListener implements EventSubscriberInterface
26{
27 private $choiceList;
28
29 private $placeholderPresent;
30
31 /**
32 * Constructor.
33 *
34 * @param ChoiceListInterface $choiceList
35 * @param Boolean $placeholderPresent
36 */
37 public function __construct(ChoiceListInterface $choiceList, $placeholderPresent)
38 {
39 $this->choiceList = $choiceList;
40 $this->placeholderPresent = $placeholderPresent;
41 }
42
43 public function preSubmit(FormEvent $event)
44 {
45 $value = $event->getData();
46 $index = current($this->choiceList->getIndicesForValues(array($value)));
47
48 $event->setData(false !== $index ? array($index => $value) : ($this->placeholderPresent ? array('placeholder' => '') : array())) ;
49 }
50
51 /**
52 * Alias of {@link preSubmit()}.
53 *
54 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
55 * {@link preSubmit()} instead.
56 */
57 public function preBind(FormEvent $event)
58 {
59 $this->preSubmit($event);
60 }
61
62 public static function getSubscribedEvents()
63 {
64 return array(FormEvents::PRE_SUBMIT => 'preSubmit');
65 }
66}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php
new file mode 100644
index 00000000..e25dacf2
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php
@@ -0,0 +1,56 @@
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\EventListener;
13
14use Symfony\Component\Form\FormEvents;
15use Symfony\Component\Form\FormEvent;
16use Symfony\Component\EventDispatcher\EventSubscriberInterface;
17
18/**
19 * Adds a protocol to a URL if it doesn't already have one.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23class FixUrlProtocolListener implements EventSubscriberInterface
24{
25 private $defaultProtocol;
26
27 public function __construct($defaultProtocol = 'http')
28 {
29 $this->defaultProtocol = $defaultProtocol;
30 }
31
32 public function onSubmit(FormEvent $event)
33 {
34 $data = $event->getData();
35
36 if ($this->defaultProtocol && $data && !preg_match('~^\w+://~', $data)) {
37 $event->setData($this->defaultProtocol.'://'.$data);
38 }
39 }
40
41 /**
42 * Alias of {@link onSubmit()}.
43 *
44 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
45 * {@link onSubmit()} instead.
46 */
47 public function onBind(FormEvent $event)
48 {
49 $this->onSubmit($event);
50 }
51
52 public static function getSubscribedEvents()
53 {
54 return array(FormEvents::SUBMIT => 'onSubmit');
55 }
56}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/MergeCollectionListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/MergeCollectionListener.php
new file mode 100644
index 00000000..4d0bdfaa
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/MergeCollectionListener.php
@@ -0,0 +1,137 @@
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\EventListener;
13
14use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15use Symfony\Component\Form\FormEvents;
16use Symfony\Component\Form\FormEvent;
17use Symfony\Component\Form\Exception\UnexpectedTypeException;
18
19/**
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class MergeCollectionListener implements EventSubscriberInterface
23{
24 /**
25 * Whether elements may be added to the collection
26 * @var Boolean
27 */
28 private $allowAdd;
29
30 /**
31 * Whether elements may be removed from the collection
32 * @var Boolean
33 */
34 private $allowDelete;
35
36 /**
37 * Creates a new listener.
38 *
39 * @param Boolean $allowAdd Whether values might be added to the
40 * collection.
41 * @param Boolean $allowDelete Whether values might be removed from the
42 * collection.
43 */
44 public function __construct($allowAdd = false, $allowDelete = false)
45 {
46 $this->allowAdd = $allowAdd;
47 $this->allowDelete = $allowDelete;
48 }
49
50 public static function getSubscribedEvents()
51 {
52 return array(
53 FormEvents::SUBMIT => 'onSubmit',
54 );
55 }
56
57 public function onSubmit(FormEvent $event)
58 {
59 $dataToMergeInto = $event->getForm()->getNormData();
60 $data = $event->getData();
61
62 if (null === $data) {
63 $data = array();
64 }
65
66 if (!is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) {
67 throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)');
68 }
69
70 if (null !== $dataToMergeInto && !is_array($dataToMergeInto) && !($dataToMergeInto instanceof \Traversable && $dataToMergeInto instanceof \ArrayAccess)) {
71 throw new UnexpectedTypeException($dataToMergeInto, 'array or (\Traversable and \ArrayAccess)');
72 }
73
74 // If we are not allowed to change anything, return immediately
75 if ((!$this->allowAdd && !$this->allowDelete) || $data === $dataToMergeInto) {
76 $event->setData($dataToMergeInto);
77
78 return;
79 }
80
81 if (!$dataToMergeInto) {
82 // No original data was set. Set it if allowed
83 if ($this->allowAdd) {
84 $dataToMergeInto = $data;
85 }
86 } else {
87 // Calculate delta
88 $itemsToAdd = is_object($data) ? clone $data : $data;
89 $itemsToDelete = array();
90
91 foreach ($dataToMergeInto as $beforeKey => $beforeItem) {
92 foreach ($data as $afterKey => $afterItem) {
93 if ($afterItem === $beforeItem) {
94 // Item found, next original item
95 unset($itemsToAdd[$afterKey]);
96 continue 2;
97 }
98 }
99
100 // Item not found, remember for deletion
101 $itemsToDelete[] = $beforeKey;
102 }
103
104 // Remove deleted items before adding to free keys that are to be
105 // replaced
106 if ($this->allowDelete) {
107 foreach ($itemsToDelete as $key) {
108 unset($dataToMergeInto[$key]);
109 }
110 }
111
112 // Add remaining items
113 if ($this->allowAdd) {
114 foreach ($itemsToAdd as $key => $item) {
115 if (!isset($dataToMergeInto[$key])) {
116 $dataToMergeInto[$key] = $item;
117 } else {
118 $dataToMergeInto[] = $item;
119 }
120 }
121 }
122 }
123
124 $event->setData($dataToMergeInto);
125 }
126
127 /**
128 * Alias of {@link onSubmit()}.
129 *
130 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
131 * {@link onSubmit()} instead.
132 */
133 public function onBind(FormEvent $event)
134 {
135 $this->onSubmit($event);
136 }
137}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php
new file mode 100644
index 00000000..f1c39db2
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php
@@ -0,0 +1,173 @@
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\EventListener;
13
14use Symfony\Component\Form\FormEvents;
15use Symfony\Component\Form\FormEvent;
16use Symfony\Component\Form\Exception\UnexpectedTypeException;
17use Symfony\Component\EventDispatcher\EventSubscriberInterface;
18
19/**
20 * Resize a collection form element based on the data sent from the client.
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class ResizeFormListener implements EventSubscriberInterface
25{
26 /**
27 * @var string
28 */
29 protected $type;
30
31 /**
32 * @var array
33 */
34 protected $options;
35
36 /**
37 * Whether children could be added to the group
38 * @var Boolean
39 */
40 protected $allowAdd;
41
42 /**
43 * Whether children could be removed from the group
44 * @var Boolean
45 */
46 protected $allowDelete;
47
48 public function __construct($type, array $options = array(), $allowAdd = false, $allowDelete = false)
49 {
50 $this->type = $type;
51 $this->allowAdd = $allowAdd;
52 $this->allowDelete = $allowDelete;
53 $this->options = $options;
54 }
55
56 public static function getSubscribedEvents()
57 {
58 return array(
59 FormEvents::PRE_SET_DATA => 'preSetData',
60 FormEvents::PRE_SUBMIT => 'preSubmit',
61 // (MergeCollectionListener, MergeDoctrineCollectionListener)
62 FormEvents::SUBMIT => array('onSubmit', 50),
63 );
64 }
65
66 public function preSetData(FormEvent $event)
67 {
68 $form = $event->getForm();
69 $data = $event->getData();
70
71 if (null === $data) {
72 $data = array();
73 }
74
75 if (!is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) {
76 throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)');
77 }
78
79 // First remove all rows
80 foreach ($form as $name => $child) {
81 $form->remove($name);
82 }
83
84 // Then add all rows again in the correct order
85 foreach ($data as $name => $value) {
86 $form->add($name, $this->type, array_replace(array(
87 'property_path' => '['.$name.']',
88 ), $this->options));
89 }
90 }
91
92 public function preSubmit(FormEvent $event)
93 {
94 $form = $event->getForm();
95 $data = $event->getData();
96
97 if (null === $data || '' === $data) {
98 $data = array();
99 }
100
101 if (!is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) {
102 throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)');
103 }
104
105 // Remove all empty rows
106 if ($this->allowDelete) {
107 foreach ($form as $name => $child) {
108 if (!isset($data[$name])) {
109 $form->remove($name);
110 }
111 }
112 }
113
114 // Add all additional rows
115 if ($this->allowAdd) {
116 foreach ($data as $name => $value) {
117 if (!$form->has($name)) {
118 $form->add($name, $this->type, array_replace(array(
119 'property_path' => '['.$name.']',
120 ), $this->options));
121 }
122 }
123 }
124 }
125
126 public function onSubmit(FormEvent $event)
127 {
128 $form = $event->getForm();
129 $data = $event->getData();
130
131 if (null === $data) {
132 $data = array();
133 }
134
135 if (!is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) {
136 throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)');
137 }
138
139 // The data mapper only adds, but does not remove items, so do this
140 // here
141 if ($this->allowDelete) {
142 foreach ($data as $name => $child) {
143 if (!$form->has($name)) {
144 unset($data[$name]);
145 }
146 }
147 }
148
149 $event->setData($data);
150 }
151
152 /**
153 * Alias of {@link preSubmit()}.
154 *
155 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
156 * {@link preSubmit()} instead.
157 */
158 public function preBind(FormEvent $event)
159 {
160 $this->preSubmit($event);
161 }
162
163 /**
164 * Alias of {@link onSubmit()}.
165 *
166 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
167 * {@link onSubmit()} instead.
168 */
169 public function onBind(FormEvent $event)
170 {
171 $this->onSubmit($event);
172 }
173}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/TrimListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/TrimListener.php
new file mode 100644
index 00000000..cbe6e0ab
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/TrimListener.php
@@ -0,0 +1,55 @@
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\EventListener;
13
14use Symfony\Component\Form\FormEvents;
15use Symfony\Component\Form\FormEvent;
16use Symfony\Component\EventDispatcher\EventSubscriberInterface;
17
18/**
19 * Trims string data
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23class TrimListener implements EventSubscriberInterface
24{
25 public function preSubmit(FormEvent $event)
26 {
27 $data = $event->getData();
28
29 if (!is_string($data)) {
30 return;
31 }
32
33 if (null !== $result = @preg_replace('/^[\pZ\p{Cc}]+|[\pZ\p{Cc}]+$/u', '', $data)) {
34 $event->setData($result);
35 } else {
36 $event->setData(trim($data));
37 }
38 }
39
40 /**
41 * Alias of {@link preSubmit()}.
42 *
43 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
44 * {@link preSubmit()} instead.
45 */
46 public function preBind(FormEvent $event)
47 {
48 $this->preSubmit($event);
49 }
50
51 public static function getSubscribedEvents()
52 {
53 return array(FormEvents::PRE_SUBMIT => 'preSubmit');
54 }
55}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/BaseType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/BaseType.php
new file mode 100644
index 00000000..79333a67
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/BaseType.php
@@ -0,0 +1,121 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilderInterface;
16use Symfony\Component\Form\FormInterface;
17use Symfony\Component\Form\FormView;
18use Symfony\Component\OptionsResolver\OptionsResolverInterface;
19
20/**
21 * Encapsulates common logic of {@link FormType} and {@link ButtonType}.
22 *
23 * This type does not appear in the form's type inheritance chain and as such
24 * cannot be extended (via {@link FormTypeExtension}s) nor themed.
25 *
26 * @author Bernhard Schussek <bschussek@gmail.com>
27 */
28abstract class BaseType extends AbstractType
29{
30 /**
31 * {@inheritdoc}
32 */
33 public function buildForm(FormBuilderInterface $builder, array $options)
34 {
35 $builder->setDisabled($options['disabled']);
36 }
37
38 /**
39 * {@inheritdoc}
40 */
41 public function buildView(FormView $view, FormInterface $form, array $options)
42 {
43 $name = $form->getName();
44 $blockName = $options['block_name'] ?: $form->getName();
45 $translationDomain = $options['translation_domain'];
46
47 if ($view->parent) {
48 if ('' !== ($parentFullName = $view->parent->vars['full_name'])) {
49 $id = sprintf('%s_%s', $view->parent->vars['id'], $name);
50 $fullName = sprintf('%s[%s]', $parentFullName, $name);
51 $uniqueBlockPrefix = sprintf('%s_%s', $view->parent->vars['unique_block_prefix'], $blockName);
52 } else {
53 $id = $name;
54 $fullName = $name;
55 $uniqueBlockPrefix = '_'.$blockName;
56 }
57
58 if (!$translationDomain) {
59 $translationDomain = $view->parent->vars['translation_domain'];
60 }
61 } else {
62 $id = $name;
63 $fullName = $name;
64 $uniqueBlockPrefix = '_'.$blockName;
65
66 // Strip leading underscores and digits. These are allowed in
67 // form names, but not in HTML4 ID attributes.
68 // http://www.w3.org/TR/html401/struct/global.html#adef-id
69 $id = ltrim($id, '_0123456789');
70 }
71
72 $blockPrefixes = array();
73 for ($type = $form->getConfig()->getType(); null !== $type; $type = $type->getParent()) {
74 array_unshift($blockPrefixes, $type->getName());
75 }
76 $blockPrefixes[] = $uniqueBlockPrefix;
77
78 if (!$translationDomain) {
79 $translationDomain = 'messages';
80 }
81
82 $view->vars = array_replace($view->vars, array(
83 'form' => $view,
84 'id' => $id,
85 'name' => $name,
86 'full_name' => $fullName,
87 'disabled' => $form->isDisabled(),
88 'label' => $options['label'],
89 'multipart' => false,
90 'attr' => $options['attr'],
91 'block_prefixes' => $blockPrefixes,
92 'unique_block_prefix' => $uniqueBlockPrefix,
93 'translation_domain' => $translationDomain,
94 // Using the block name here speeds up performance in collection
95 // forms, where each entry has the same full block name.
96 // Including the type is important too, because if rows of a
97 // collection form have different types (dynamically), they should
98 // be rendered differently.
99 // https://github.com/symfony/symfony/issues/5038
100 'cache_key' => $uniqueBlockPrefix.'_'.$form->getConfig()->getType()->getName(),
101 ));
102 }
103
104 /**
105 * {@inheritdoc}
106 */
107 public function setDefaultOptions(OptionsResolverInterface $resolver)
108 {
109 $resolver->setDefaults(array(
110 'block_name' => null,
111 'disabled' => false,
112 'label' => null,
113 'attr' => array(),
114 'translation_domain' => null,
115 ));
116
117 $resolver->setAllowedTypes(array(
118 'attr' => 'array',
119 ));
120 }
121}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/BirthdayType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/BirthdayType.php
new file mode 100644
index 00000000..5314c140
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/BirthdayType.php
@@ -0,0 +1,44 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\OptionsResolver\OptionsResolverInterface;
16
17class BirthdayType extends AbstractType
18{
19 /**
20 * {@inheritdoc}
21 */
22 public function setDefaultOptions(OptionsResolverInterface $resolver)
23 {
24 $resolver->setDefaults(array(
25 'years' => range(date('Y') - 120, date('Y')),
26 ));
27 }
28
29 /**
30 * {@inheritdoc}
31 */
32 public function getParent()
33 {
34 return 'date';
35 }
36
37 /**
38 * {@inheritdoc}
39 */
40 public function getName()
41 {
42 return 'birthday';
43 }
44}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ButtonType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ButtonType.php
new file mode 100644
index 00000000..3569963b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ButtonType.php
@@ -0,0 +1,38 @@
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\Type;
13
14use Symfony\Component\Form\ButtonTypeInterface;
15
16/**
17 * A form button.
18 *
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class ButtonType extends BaseType implements ButtonTypeInterface
22{
23 /**
24 * {@inheritdoc}
25 */
26 public function getParent()
27 {
28 return null;
29 }
30
31 /**
32 * {@inheritdoc}
33 */
34 public function getName()
35 {
36 return 'button';
37 }
38}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CheckboxType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CheckboxType.php
new file mode 100644
index 00000000..214e581a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CheckboxType.php
@@ -0,0 +1,67 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilderInterface;
16use Symfony\Component\Form\FormInterface;
17use Symfony\Component\Form\Extension\Core\DataTransformer\BooleanToStringTransformer;
18use Symfony\Component\Form\FormView;
19use Symfony\Component\OptionsResolver\OptionsResolverInterface;
20
21class CheckboxType extends AbstractType
22{
23 /**
24 * {@inheritdoc}
25 */
26 public function buildForm(FormBuilderInterface $builder, array $options)
27 {
28 $builder
29 ->addViewTransformer(new BooleanToStringTransformer($options['value']))
30 ;
31 }
32
33 /**
34 * {@inheritdoc}
35 */
36 public function buildView(FormView $view, FormInterface $form, array $options)
37 {
38 $view->vars = array_replace($view->vars, array(
39 'value' => $options['value'],
40 'checked' => null !== $form->getViewData(),
41 ));
42 }
43
44 /**
45 * {@inheritdoc}
46 */
47 public function setDefaultOptions(OptionsResolverInterface $resolver)
48 {
49 $emptyData = function (FormInterface $form, $clientData) {
50 return $clientData;
51 };
52
53 $resolver->setDefaults(array(
54 'value' => '1',
55 'empty_data' => $emptyData,
56 'compound' => false,
57 ));
58 }
59
60 /**
61 * {@inheritdoc}
62 */
63 public function getName()
64 {
65 return 'checkbox';
66 }
67}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
new file mode 100644
index 00000000..9a3fdef1
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
@@ -0,0 +1,274 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\Extension\Core\View\ChoiceView;
16use Symfony\Component\Form\FormBuilderInterface;
17use Symfony\Component\Form\FormInterface;
18use Symfony\Component\Form\FormView;
19use Symfony\Component\Form\Exception\LogicException;
20use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
21use Symfony\Component\Form\Extension\Core\EventListener\FixRadioInputListener;
22use Symfony\Component\Form\Extension\Core\EventListener\FixCheckboxInputListener;
23use Symfony\Component\Form\Extension\Core\EventListener\MergeCollectionListener;
24use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer;
25use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToBooleanArrayTransformer;
26use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer;
27use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToBooleanArrayTransformer;
28use Symfony\Component\OptionsResolver\Options;
29use Symfony\Component\OptionsResolver\OptionsResolverInterface;
30
31class ChoiceType extends AbstractType
32{
33 /**
34 * Caches created choice lists.
35 * @var array
36 */
37 private $choiceListCache = array();
38
39 /**
40 * {@inheritdoc}
41 */
42 public function buildForm(FormBuilderInterface $builder, array $options)
43 {
44 if (!$options['choice_list'] && !is_array($options['choices']) && !$options['choices'] instanceof \Traversable) {
45 throw new LogicException('Either the option "choices" or "choice_list" must be set.');
46 }
47
48 if ($options['expanded']) {
49 // Initialize all choices before doing the index check below.
50 // This helps in cases where index checks are optimized for non
51 // initialized choice lists. For example, when using an SQL driver,
52 // the index check would read in one SQL query and the initialization
53 // requires another SQL query. When the initialization is done first,
54 // one SQL query is sufficient.
55 $preferredViews = $options['choice_list']->getPreferredViews();
56 $remainingViews = $options['choice_list']->getRemainingViews();
57
58 // Check if the choices already contain the empty value
59 // Only add the empty value option if this is not the case
60 if (null !== $options['empty_value'] && 0 === count($options['choice_list']->getIndicesForValues(array('')))) {
61 $placeholderView = new ChoiceView(null, '', $options['empty_value']);
62
63 // "placeholder" is a reserved index
64 // see also ChoiceListInterface::getIndicesForChoices()
65 $this->addSubForms($builder, array('placeholder' => $placeholderView), $options);
66 }
67
68 $this->addSubForms($builder, $preferredViews, $options);
69 $this->addSubForms($builder, $remainingViews, $options);
70
71 if ($options['multiple']) {
72 $builder->addViewTransformer(new ChoicesToBooleanArrayTransformer($options['choice_list']));
73 $builder->addEventSubscriber(new FixCheckboxInputListener($options['choice_list']), 10);
74 } else {
75 $builder->addViewTransformer(new ChoiceToBooleanArrayTransformer($options['choice_list'], $builder->has('placeholder')));
76 $builder->addEventSubscriber(new FixRadioInputListener($options['choice_list'], $builder->has('placeholder')), 10);
77 }
78 } else {
79 if ($options['multiple']) {
80 $builder->addViewTransformer(new ChoicesToValuesTransformer($options['choice_list']));
81 } else {
82 $builder->addViewTransformer(new ChoiceToValueTransformer($options['choice_list']));
83 }
84 }
85
86 if ($options['multiple'] && $options['by_reference']) {
87 // Make sure the collection created during the client->norm
88 // transformation is merged back into the original collection
89 $builder->addEventSubscriber(new MergeCollectionListener(true, true));
90 }
91 }
92
93 /**
94 * {@inheritdoc}
95 */
96 public function buildView(FormView $view, FormInterface $form, array $options)
97 {
98 $view->vars = array_replace($view->vars, array(
99 'multiple' => $options['multiple'],
100 'expanded' => $options['expanded'],
101 'preferred_choices' => $options['choice_list']->getPreferredViews(),
102 'choices' => $options['choice_list']->getRemainingViews(),
103 'separator' => '-------------------',
104 'empty_value' => null,
105 ));
106
107 // The decision, whether a choice is selected, is potentially done
108 // thousand of times during the rendering of a template. Provide a
109 // closure here that is optimized for the value of the form, to
110 // avoid making the type check inside the closure.
111 if ($options['multiple']) {
112 $view->vars['is_selected'] = function ($choice, array $values) {
113 return false !== array_search($choice, $values, true);
114 };
115 } else {
116 $view->vars['is_selected'] = function ($choice, $value) {
117 return $choice === $value;
118 };
119 }
120
121 // Check if the choices already contain the empty value
122 // Only add the empty value option if this is not the case
123 if (null !== $options['empty_value'] && 0 === count($options['choice_list']->getIndicesForValues(array('')))) {
124 $view->vars['empty_value'] = $options['empty_value'];
125 }
126
127 if ($options['multiple'] && !$options['expanded']) {
128 // Add "[]" to the name in case a select tag with multiple options is
129 // displayed. Otherwise only one of the selected options is sent in the
130 // POST request.
131 $view->vars['full_name'] = $view->vars['full_name'].'[]';
132 }
133 }
134
135 /**
136 * {@inheritdoc}
137 */
138 public function finishView(FormView $view, FormInterface $form, array $options)
139 {
140 if ($options['expanded']) {
141 // Radio buttons should have the same name as the parent
142 $childName = $view->vars['full_name'];
143
144 // Checkboxes should append "[]" to allow multiple selection
145 if ($options['multiple']) {
146 $childName .= '[]';
147 }
148
149 foreach ($view as $childView) {
150 $childView->vars['full_name'] = $childName;
151 }
152 }
153 }
154
155 /**
156 * {@inheritdoc}
157 */
158 public function setDefaultOptions(OptionsResolverInterface $resolver)
159 {
160 $choiceListCache =& $this->choiceListCache;
161
162 $choiceList = function (Options $options) use (&$choiceListCache) {
163 // Harden against NULL values (like in EntityType and ModelType)
164 $choices = null !== $options['choices'] ? $options['choices'] : array();
165
166 // Reuse existing choice lists in order to increase performance
167 $hash = md5(json_encode(array($choices, $options['preferred_choices'])));
168
169 if (!isset($choiceListCache[$hash])) {
170 $choiceListCache[$hash] = new SimpleChoiceList($choices, $options['preferred_choices']);
171 }
172
173 return $choiceListCache[$hash];
174 };
175
176 $emptyData = function (Options $options) {
177 if ($options['multiple'] || $options['expanded']) {
178 return array();
179 }
180
181 return '';
182 };
183
184 $emptyValue = function (Options $options) {
185 return $options['required'] ? null : '';
186 };
187
188 $emptyValueNormalizer = function (Options $options, $emptyValue) {
189 if ($options['multiple']) {
190 // never use an empty value for this case
191 return null;
192 } elseif (false === $emptyValue) {
193 // an empty value should be added but the user decided otherwise
194 return null;
195 } elseif ($options['expanded'] && '' === $emptyValue) {
196 // never use an empty label for radio buttons
197 return 'None';
198 }
199
200 // empty value has been set explicitly
201 return $emptyValue;
202 };
203
204 $compound = function (Options $options) {
205 return $options['expanded'];
206 };
207
208 $resolver->setDefaults(array(
209 'multiple' => false,
210 'expanded' => false,
211 'choice_list' => $choiceList,
212 'choices' => array(),
213 'preferred_choices' => array(),
214 'empty_data' => $emptyData,
215 'empty_value' => $emptyValue,
216 'error_bubbling' => false,
217 'compound' => $compound,
218 // The view data is always a string, even if the "data" option
219 // is manually set to an object.
220 // See https://github.com/symfony/symfony/pull/5582
221 'data_class' => null,
222 ));
223
224 $resolver->setNormalizers(array(
225 'empty_value' => $emptyValueNormalizer,
226 ));
227
228 $resolver->setAllowedTypes(array(
229 'choice_list' => array('null', 'Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface'),
230 ));
231 }
232
233 /**
234 * {@inheritdoc}
235 */
236 public function getName()
237 {
238 return 'choice';
239 }
240
241 /**
242 * Adds the sub fields for an expanded choice field.
243 *
244 * @param FormBuilderInterface $builder The form builder.
245 * @param array $choiceViews The choice view objects.
246 * @param array $options The build options.
247 */
248 private function addSubForms(FormBuilderInterface $builder, array $choiceViews, array $options)
249 {
250 foreach ($choiceViews as $i => $choiceView) {
251 if (is_array($choiceView)) {
252 // Flatten groups
253 $this->addSubForms($builder, $choiceView, $options);
254 } else {
255 $choiceOpts = array(
256 'value' => $choiceView->value,
257 'label' => $choiceView->label,
258 'translation_domain' => $options['translation_domain'],
259 );
260
261 if ($options['multiple']) {
262 $choiceType = 'checkbox';
263 // The user can check 0 or more checkboxes. If required
264 // is true, he is required to check all of them.
265 $choiceOpts['required'] = false;
266 } else {
267 $choiceType = 'radio';
268 }
269
270 $builder->add($i, $choiceType, $choiceOpts);
271 }
272 }
273 }
274}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CollectionType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CollectionType.php
new file mode 100644
index 00000000..0cb3af1b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CollectionType.php
@@ -0,0 +1,103 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilderInterface;
16use Symfony\Component\Form\FormView;
17use Symfony\Component\Form\FormInterface;
18use Symfony\Component\Form\Extension\Core\EventListener\ResizeFormListener;
19use Symfony\Component\OptionsResolver\Options;
20use Symfony\Component\OptionsResolver\OptionsResolverInterface;
21
22class CollectionType extends AbstractType
23{
24 /**
25 * {@inheritdoc}
26 */
27 public function buildForm(FormBuilderInterface $builder, array $options)
28 {
29 if ($options['allow_add'] && $options['prototype']) {
30 $prototype = $builder->create($options['prototype_name'], $options['type'], array_replace(array(
31 'label' => $options['prototype_name'].'label__',
32 ), $options['options']));
33 $builder->setAttribute('prototype', $prototype->getForm());
34 }
35
36 $resizeListener = new ResizeFormListener(
37 $options['type'],
38 $options['options'],
39 $options['allow_add'],
40 $options['allow_delete']
41 );
42
43 $builder->addEventSubscriber($resizeListener);
44 }
45
46 /**
47 * {@inheritdoc}
48 */
49 public function buildView(FormView $view, FormInterface $form, array $options)
50 {
51 $view->vars = array_replace($view->vars, array(
52 'allow_add' => $options['allow_add'],
53 'allow_delete' => $options['allow_delete'],
54 ));
55
56 if ($form->getConfig()->hasAttribute('prototype')) {
57 $view->vars['prototype'] = $form->getConfig()->getAttribute('prototype')->createView($view);
58 }
59 }
60
61 /**
62 * {@inheritdoc}
63 */
64 public function finishView(FormView $view, FormInterface $form, array $options)
65 {
66 if ($form->getConfig()->hasAttribute('prototype') && $view->vars['prototype']->vars['multipart']) {
67 $view->vars['multipart'] = true;
68 }
69 }
70
71 /**
72 * {@inheritdoc}
73 */
74 public function setDefaultOptions(OptionsResolverInterface $resolver)
75 {
76 $optionsNormalizer = function (Options $options, $value) {
77 $value['block_name'] = 'entry';
78
79 return $value;
80 };
81
82 $resolver->setDefaults(array(
83 'allow_add' => false,
84 'allow_delete' => false,
85 'prototype' => true,
86 'prototype_name' => '__name__',
87 'type' => 'text',
88 'options' => array(),
89 ));
90
91 $resolver->setNormalizers(array(
92 'options' => $optionsNormalizer,
93 ));
94 }
95
96 /**
97 * {@inheritdoc}
98 */
99 public function getName()
100 {
101 return 'collection';
102 }
103}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CountryType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CountryType.php
new file mode 100644
index 00000000..3482ba66
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CountryType.php
@@ -0,0 +1,45 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Intl\Intl;
16use Symfony\Component\OptionsResolver\OptionsResolverInterface;
17
18class CountryType extends AbstractType
19{
20 /**
21 * {@inheritdoc}
22 */
23 public function setDefaultOptions(OptionsResolverInterface $resolver)
24 {
25 $resolver->setDefaults(array(
26 'choices' => Intl::getRegionBundle()->getCountryNames(),
27 ));
28 }
29
30 /**
31 * {@inheritdoc}
32 */
33 public function getParent()
34 {
35 return 'choice';
36 }
37
38 /**
39 * {@inheritdoc}
40 */
41 public function getName()
42 {
43 return 'country';
44 }
45}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php
new file mode 100644
index 00000000..3a925e3a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php
@@ -0,0 +1,45 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Intl\Intl;
16use Symfony\Component\OptionsResolver\OptionsResolverInterface;
17
18class CurrencyType extends AbstractType
19{
20 /**
21 * {@inheritdoc}
22 */
23 public function setDefaultOptions(OptionsResolverInterface $resolver)
24 {
25 $resolver->setDefaults(array(
26 'choices' => Intl::getCurrencyBundle()->getCurrencyNames(),
27 ));
28 }
29
30 /**
31 * {@inheritdoc}
32 */
33 public function getParent()
34 {
35 return 'choice';
36 }
37
38 /**
39 * {@inheritdoc}
40 */
41 public function getName()
42 {
43 return 'currency';
44 }
45}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php
new file mode 100644
index 00000000..a612b6fc
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php
@@ -0,0 +1,281 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
16use Symfony\Component\Form\FormInterface;
17use Symfony\Component\Form\FormBuilderInterface;
18use Symfony\Component\Form\FormView;
19use Symfony\Component\Form\ReversedTransformer;
20use Symfony\Component\Form\Extension\Core\DataTransformer\DataTransformerChain;
21use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
22use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
23use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer;
24use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
25use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToRfc3339Transformer;
26use Symfony\Component\Form\Extension\Core\DataTransformer\ArrayToPartsTransformer;
27use Symfony\Component\OptionsResolver\Options;
28use Symfony\Component\OptionsResolver\OptionsResolverInterface;
29
30class DateTimeType extends AbstractType
31{
32 const DEFAULT_DATE_FORMAT = \IntlDateFormatter::MEDIUM;
33
34 const DEFAULT_TIME_FORMAT = \IntlDateFormatter::MEDIUM;
35
36 /**
37 * This is not quite the HTML5 format yet, because ICU lacks the
38 * capability of parsing and generating RFC 3339 dates, which
39 * are like the below pattern but with a timezone suffix. The
40 * timezone suffix is
41 *
42 * * "Z" for UTC
43 * * "(-|+)HH:mm" for other timezones (note the colon!)
44 *
45 * For more information see:
46 *
47 * http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Time-Format-Syntax
48 * http://www.w3.org/TR/html-markup/input.datetime.html
49 * http://tools.ietf.org/html/rfc3339
50 *
51 * An ICU ticket was created:
52 * http://icu-project.org/trac/ticket/9421
53 *
54 * It was supposedly fixed, but is not available in all PHP installations
55 * yet. To temporarily circumvent this issue, DateTimeToRfc3339Transformer
56 * is used when the format matches this constant.
57 */
58 const HTML5_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZZZZZ";
59
60 private static $acceptedFormats = array(
61 \IntlDateFormatter::FULL,
62 \IntlDateFormatter::LONG,
63 \IntlDateFormatter::MEDIUM,
64 \IntlDateFormatter::SHORT,
65 );
66
67 /**
68 * {@inheritdoc}
69 */
70 public function buildForm(FormBuilderInterface $builder, array $options)
71 {
72 $parts = array('year', 'month', 'day', 'hour');
73 $dateParts = array('year', 'month', 'day');
74 $timeParts = array('hour');
75
76 if ($options['with_minutes']) {
77 $parts[] = 'minute';
78 $timeParts[] = 'minute';
79 }
80
81 if ($options['with_seconds']) {
82 $parts[] = 'second';
83 $timeParts[] = 'second';
84 }
85
86 $dateFormat = is_int($options['date_format']) ? $options['date_format'] : self::DEFAULT_DATE_FORMAT;
87 $timeFormat = self::DEFAULT_TIME_FORMAT;
88 $calendar = \IntlDateFormatter::GREGORIAN;
89 $pattern = is_string($options['format']) ? $options['format'] : null;
90
91 if (!in_array($dateFormat, self::$acceptedFormats, true)) {
92 throw new InvalidOptionsException('The "date_format" option must be one of the IntlDateFormatter constants (FULL, LONG, MEDIUM, SHORT) or a string representing a custom format.');
93 }
94
95 if ('single_text' === $options['widget']) {
96 if (self::HTML5_FORMAT === $pattern) {
97 $builder->addViewTransformer(new DateTimeToRfc3339Transformer(
98 $options['model_timezone'],
99 $options['view_timezone']
100 ));
101 } else {
102 $builder->addViewTransformer(new DateTimeToLocalizedStringTransformer(
103 $options['model_timezone'],
104 $options['view_timezone'],
105 $dateFormat,
106 $timeFormat,
107 $calendar,
108 $pattern
109 ));
110 }
111 } else {
112 // Only pass a subset of the options to children
113 $dateOptions = array_intersect_key($options, array_flip(array(
114 'years',
115 'months',
116 'days',
117 'empty_value',
118 'required',
119 'translation_domain',
120 )));
121
122 $timeOptions = array_intersect_key($options, array_flip(array(
123 'hours',
124 'minutes',
125 'seconds',
126 'with_minutes',
127 'with_seconds',
128 'empty_value',
129 'required',
130 'translation_domain',
131 )));
132
133 if (null !== $options['date_widget']) {
134 $dateOptions['widget'] = $options['date_widget'];
135 }
136
137 if (null !== $options['time_widget']) {
138 $timeOptions['widget'] = $options['time_widget'];
139 }
140
141 if (null !== $options['date_format']) {
142 $dateOptions['format'] = $options['date_format'];
143 }
144
145 $dateOptions['input'] = $timeOptions['input'] = 'array';
146 $dateOptions['error_bubbling'] = $timeOptions['error_bubbling'] = true;
147
148 $builder
149 ->addViewTransformer(new DataTransformerChain(array(
150 new DateTimeToArrayTransformer($options['model_timezone'], $options['view_timezone'], $parts),
151 new ArrayToPartsTransformer(array(
152 'date' => $dateParts,
153 'time' => $timeParts,
154 )),
155 )))
156 ->add('date', 'date', $dateOptions)
157 ->add('time', 'time', $timeOptions)
158 ;
159 }
160
161 if ('string' === $options['input']) {
162 $builder->addModelTransformer(new ReversedTransformer(
163 new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'])
164 ));
165 } elseif ('timestamp' === $options['input']) {
166 $builder->addModelTransformer(new ReversedTransformer(
167 new DateTimeToTimestampTransformer($options['model_timezone'], $options['model_timezone'])
168 ));
169 } elseif ('array' === $options['input']) {
170 $builder->addModelTransformer(new ReversedTransformer(
171 new DateTimeToArrayTransformer($options['model_timezone'], $options['model_timezone'], $parts)
172 ));
173 }
174 }
175
176 /**
177 * {@inheritdoc}
178 */
179 public function buildView(FormView $view, FormInterface $form, array $options)
180 {
181 $view->vars['widget'] = $options['widget'];
182
183 // Change the input to a HTML5 date input if
184 // * the widget is set to "single_text"
185 // * the format matches the one expected by HTML5
186 if ('single_text' === $options['widget'] && self::HTML5_FORMAT === $options['format']) {
187 $view->vars['type'] = 'datetime';
188 }
189 }
190
191 /**
192 * {@inheritdoc}
193 */
194 public function setDefaultOptions(OptionsResolverInterface $resolver)
195 {
196 $compound = function (Options $options) {
197 return $options['widget'] !== 'single_text';
198 };
199
200 // Defaults to the value of "widget"
201 $dateWidget = function (Options $options) {
202 return $options['widget'];
203 };
204
205 // Defaults to the value of "widget"
206 $timeWidget = function (Options $options) {
207 return $options['widget'];
208 };
209
210 $resolver->setDefaults(array(
211 'input' => 'datetime',
212 'model_timezone' => null,
213 'view_timezone' => null,
214 'format' => self::HTML5_FORMAT,
215 'date_format' => null,
216 'widget' => null,
217 'date_widget' => $dateWidget,
218 'time_widget' => $timeWidget,
219 'with_minutes' => true,
220 'with_seconds' => false,
221 // Don't modify \DateTime classes by reference, we treat
222 // them like immutable value objects
223 'by_reference' => false,
224 'error_bubbling' => false,
225 // If initialized with a \DateTime object, FormType initializes
226 // this option to "\DateTime". Since the internal, normalized
227 // representation is not \DateTime, but an array, we need to unset
228 // this option.
229 'data_class' => null,
230 'compound' => $compound,
231 ));
232
233 // Don't add some defaults in order to preserve the defaults
234 // set in DateType and TimeType
235 $resolver->setOptional(array(
236 'empty_value',
237 'years',
238 'months',
239 'days',
240 'hours',
241 'minutes',
242 'seconds',
243 ));
244
245 $resolver->setAllowedValues(array(
246 'input' => array(
247 'datetime',
248 'string',
249 'timestamp',
250 'array',
251 ),
252 'date_widget' => array(
253 null, // inherit default from DateType
254 'single_text',
255 'text',
256 'choice',
257 ),
258 'time_widget' => array(
259 null, // inherit default from TimeType
260 'single_text',
261 'text',
262 'choice',
263 ),
264 // This option will overwrite "date_widget" and "time_widget" options
265 'widget' => array(
266 null, // default, don't overwrite options
267 'single_text',
268 'text',
269 'choice',
270 ),
271 ));
272 }
273
274 /**
275 * {@inheritdoc}
276 */
277 public function getName()
278 {
279 return 'datetime';
280 }
281}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/DateType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/DateType.php
new file mode 100644
index 00000000..93d3502e
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/DateType.php
@@ -0,0 +1,309 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\FormBuilderInterface;
17use Symfony\Component\Form\FormView;
18use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer;
19use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
20use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
21use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
22use Symfony\Component\Form\ReversedTransformer;
23use Symfony\Component\OptionsResolver\Options;
24use Symfony\Component\OptionsResolver\OptionsResolverInterface;
25use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
26
27class DateType extends AbstractType
28{
29 const DEFAULT_FORMAT = \IntlDateFormatter::MEDIUM;
30
31 const HTML5_FORMAT = 'yyyy-MM-dd';
32
33 private static $acceptedFormats = array(
34 \IntlDateFormatter::FULL,
35 \IntlDateFormatter::LONG,
36 \IntlDateFormatter::MEDIUM,
37 \IntlDateFormatter::SHORT,
38 );
39
40 /**
41 * {@inheritdoc}
42 */
43 public function buildForm(FormBuilderInterface $builder, array $options)
44 {
45 $dateFormat = is_int($options['format']) ? $options['format'] : self::DEFAULT_FORMAT;
46 $timeFormat = \IntlDateFormatter::NONE;
47 $calendar = \IntlDateFormatter::GREGORIAN;
48 $pattern = is_string($options['format']) ? $options['format'] : null;
49
50 if (!in_array($dateFormat, self::$acceptedFormats, true)) {
51 throw new InvalidOptionsException('The "format" option must be one of the IntlDateFormatter constants (FULL, LONG, MEDIUM, SHORT) or a string representing a custom format.');
52 }
53
54 if (null !== $pattern && (false === strpos($pattern, 'y') || false === strpos($pattern, 'M') || false === strpos($pattern, 'd'))) {
55 throw new InvalidOptionsException(sprintf('The "format" option should contain the letters "y", "M" and "d". Its current value is "%s".', $pattern));
56 }
57
58 if ('single_text' === $options['widget']) {
59 $builder->addViewTransformer(new DateTimeToLocalizedStringTransformer(
60 $options['model_timezone'],
61 $options['view_timezone'],
62 $dateFormat,
63 $timeFormat,
64 $calendar,
65 $pattern
66 ));
67 } else {
68 $yearOptions = $monthOptions = $dayOptions = array(
69 'error_bubbling' => true,
70 );
71
72 $formatter = new \IntlDateFormatter(
73 \Locale::getDefault(),
74 $dateFormat,
75 $timeFormat,
76 'UTC',
77 $calendar,
78 $pattern
79 );
80 $formatter->setLenient(false);
81
82 if ('choice' === $options['widget']) {
83 // Only pass a subset of the options to children
84 $yearOptions['choices'] = $this->formatTimestamps($formatter, '/y+/', $this->listYears($options['years']));
85 $yearOptions['empty_value'] = $options['empty_value']['year'];
86 $monthOptions['choices'] = $this->formatTimestamps($formatter, '/[M|L]+/', $this->listMonths($options['months']));
87 $monthOptions['empty_value'] = $options['empty_value']['month'];
88 $dayOptions['choices'] = $this->formatTimestamps($formatter, '/d+/', $this->listDays($options['days']));
89 $dayOptions['empty_value'] = $options['empty_value']['day'];
90 }
91
92 // Append generic carry-along options
93 foreach (array('required', 'translation_domain') as $passOpt) {
94 $yearOptions[$passOpt] = $monthOptions[$passOpt] = $dayOptions[$passOpt] = $options[$passOpt];
95 }
96
97 $builder
98 ->add('year', $options['widget'], $yearOptions)
99 ->add('month', $options['widget'], $monthOptions)
100 ->add('day', $options['widget'], $dayOptions)
101 ->addViewTransformer(new DateTimeToArrayTransformer(
102 $options['model_timezone'], $options['view_timezone'], array('year', 'month', 'day')
103 ))
104 ->setAttribute('formatter', $formatter)
105 ;
106 }
107
108 if ('string' === $options['input']) {
109 $builder->addModelTransformer(new ReversedTransformer(
110 new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'], 'Y-m-d')
111 ));
112 } elseif ('timestamp' === $options['input']) {
113 $builder->addModelTransformer(new ReversedTransformer(
114 new DateTimeToTimestampTransformer($options['model_timezone'], $options['model_timezone'])
115 ));
116 } elseif ('array' === $options['input']) {
117 $builder->addModelTransformer(new ReversedTransformer(
118 new DateTimeToArrayTransformer($options['model_timezone'], $options['model_timezone'], array('year', 'month', 'day'))
119 ));
120 }
121 }
122
123 /**
124 * {@inheritdoc}
125 */
126 public function finishView(FormView $view, FormInterface $form, array $options)
127 {
128 $view->vars['widget'] = $options['widget'];
129
130 // Change the input to a HTML5 date input if
131 // * the widget is set to "single_text"
132 // * the format matches the one expected by HTML5
133 if ('single_text' === $options['widget'] && self::HTML5_FORMAT === $options['format']) {
134 $view->vars['type'] = 'date';
135 }
136
137 if ($form->getConfig()->hasAttribute('formatter')) {
138 $pattern = $form->getConfig()->getAttribute('formatter')->getPattern();
139
140 // remove special characters unless the format was explicitly specified
141 if (!is_string($options['format'])) {
142 $pattern = preg_replace('/[^yMd]+/', '', $pattern);
143 }
144
145 // set right order with respect to locale (e.g.: de_DE=dd.MM.yy; en_US=M/d/yy)
146 // lookup various formats at http://userguide.icu-project.org/formatparse/datetime
147 if (preg_match('/^([yMd]+)[^yMd]*([yMd]+)[^yMd]*([yMd]+)$/', $pattern)) {
148 $pattern = preg_replace(array('/y+/', '/M+/', '/d+/'), array('{{ year }}', '{{ month }}', '{{ day }}'), $pattern);
149 } else {
150 // default fallback
151 $pattern = '{{ year }}{{ month }}{{ day }}';
152 }
153
154 $view->vars['date_pattern'] = $pattern;
155 }
156 }
157
158 /**
159 * {@inheritdoc}
160 */
161 public function setDefaultOptions(OptionsResolverInterface $resolver)
162 {
163 $compound = function (Options $options) {
164 return $options['widget'] !== 'single_text';
165 };
166
167 $emptyValue = $emptyValueDefault = function (Options $options) {
168 return $options['required'] ? null : '';
169 };
170
171 $emptyValueNormalizer = function (Options $options, $emptyValue) use ($emptyValueDefault) {
172 if (is_array($emptyValue)) {
173 $default = $emptyValueDefault($options);
174
175 return array_merge(
176 array('year' => $default, 'month' => $default, 'day' => $default),
177 $emptyValue
178 );
179 }
180
181 return array(
182 'year' => $emptyValue,
183 'month' => $emptyValue,
184 'day' => $emptyValue
185 );
186 };
187
188 $format = function (Options $options) {
189 return $options['widget'] === 'single_text' ? DateType::HTML5_FORMAT : DateType::DEFAULT_FORMAT;
190 };
191
192 $resolver->setDefaults(array(
193 'years' => range(date('Y') - 5, date('Y') + 5),
194 'months' => range(1, 12),
195 'days' => range(1, 31),
196 'widget' => 'choice',
197 'input' => 'datetime',
198 'format' => $format,
199 'model_timezone' => null,
200 'view_timezone' => null,
201 'empty_value' => $emptyValue,
202 // Don't modify \DateTime classes by reference, we treat
203 // them like immutable value objects
204 'by_reference' => false,
205 'error_bubbling' => false,
206 // If initialized with a \DateTime object, FormType initializes
207 // this option to "\DateTime". Since the internal, normalized
208 // representation is not \DateTime, but an array, we need to unset
209 // this option.
210 'data_class' => null,
211 'compound' => $compound,
212 ));
213
214 $resolver->setNormalizers(array(
215 'empty_value' => $emptyValueNormalizer,
216 ));
217
218 $resolver->setAllowedValues(array(
219 'input' => array(
220 'datetime',
221 'string',
222 'timestamp',
223 'array',
224 ),
225 'widget' => array(
226 'single_text',
227 'text',
228 'choice',
229 ),
230 ));
231
232 $resolver->setAllowedTypes(array(
233 'format' => array('int', 'string'),
234 ));
235 }
236
237 /**
238 * {@inheritdoc}
239 */
240 public function getName()
241 {
242 return 'date';
243 }
244
245 private function formatTimestamps(\IntlDateFormatter $formatter, $regex, array $timestamps)
246 {
247 $pattern = $formatter->getPattern();
248 $timezone = $formatter->getTimezoneId();
249
250 if (version_compare(\PHP_VERSION, '5.5.0-dev', '>=')) {
251 $formatter->setTimeZone(\DateTimeZone::UTC);
252 } else {
253 $formatter->setTimeZoneId(\DateTimeZone::UTC);
254 }
255
256 if (preg_match($regex, $pattern, $matches)) {
257 $formatter->setPattern($matches[0]);
258
259 foreach ($timestamps as $key => $timestamp) {
260 $timestamps[$key] = $formatter->format($timestamp);
261 }
262
263 // I'd like to clone the formatter above, but then we get a
264 // segmentation fault, so let's restore the old state instead
265 $formatter->setPattern($pattern);
266 }
267
268 if (version_compare(\PHP_VERSION, '5.5.0-dev', '>=')) {
269 $formatter->setTimeZone($timezone);
270 } else {
271 $formatter->setTimeZoneId($timezone);
272 }
273
274 return $timestamps;
275 }
276
277 private function listYears(array $years)
278 {
279 $result = array();
280
281 foreach ($years as $year) {
282 $result[$year] = gmmktime(0, 0, 0, 6, 15, $year);
283 }
284
285 return $result;
286 }
287
288 private function listMonths(array $months)
289 {
290 $result = array();
291
292 foreach ($months as $month) {
293 $result[$month] = gmmktime(0, 0, 0, $month, 15);
294 }
295
296 return $result;
297 }
298
299 private function listDays(array $days)
300 {
301 $result = array();
302
303 foreach ($days as $day) {
304 $result[$day] = gmmktime(0, 0, 0, 5, $day);
305 }
306
307 return $result;
308 }
309}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/EmailType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/EmailType.php
new file mode 100644
index 00000000..26652ef6
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/EmailType.php
@@ -0,0 +1,33 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15
16class EmailType extends AbstractType
17{
18 /**
19 * {@inheritdoc}
20 */
21 public function getParent()
22 {
23 return 'text';
24 }
25
26 /**
27 * {@inheritdoc}
28 */
29 public function getName()
30 {
31 return 'email';
32 }
33}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/FileType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/FileType.php
new file mode 100644
index 00000000..2c09da6f
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/FileType.php
@@ -0,0 +1,61 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\FormView;
17use Symfony\Component\OptionsResolver\OptionsResolverInterface;
18
19class FileType extends AbstractType
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function buildView(FormView $view, FormInterface $form, array $options)
25 {
26 $view->vars = array_replace($view->vars, array(
27 'type' => 'file',
28 'value' => '',
29 ));
30 }
31
32 /**
33 * {@inheritdoc}
34 */
35 public function finishView(FormView $view, FormInterface $form, array $options)
36 {
37 $view
38 ->vars['multipart'] = true
39 ;
40 }
41
42 /**
43 * {@inheritdoc}
44 */
45 public function setDefaultOptions(OptionsResolverInterface $resolver)
46 {
47 $resolver->setDefaults(array(
48 'compound' => false,
49 'data_class' => 'Symfony\Component\HttpFoundation\File\File',
50 'empty_data' => null,
51 ));
52 }
53
54 /**
55 * {@inheritdoc}
56 */
57 public function getName()
58 {
59 return 'file';
60 }
61}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/FormType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/FormType.php
new file mode 100644
index 00000000..0c39d3eb
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/FormType.php
@@ -0,0 +1,214 @@
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\Type;
13
14use Symfony\Component\Form\FormBuilderInterface;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\FormView;
17use Symfony\Component\Form\Extension\Core\EventListener\TrimListener;
18use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
19use Symfony\Component\Form\Exception\LogicException;
20use Symfony\Component\OptionsResolver\Options;
21use Symfony\Component\OptionsResolver\OptionsResolverInterface;
22use Symfony\Component\PropertyAccess\PropertyAccess;
23use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
24
25class FormType extends BaseType
26{
27 /**
28 * @var PropertyAccessorInterface
29 */
30 private $propertyAccessor;
31
32 public function __construct(PropertyAccessorInterface $propertyAccessor = null)
33 {
34 $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::getPropertyAccessor();
35 }
36
37 /**
38 * {@inheritdoc}
39 */
40 public function buildForm(FormBuilderInterface $builder, array $options)
41 {
42 parent::buildForm($builder, $options);
43
44 $builder
45 ->setRequired($options['required'])
46 ->setErrorBubbling($options['error_bubbling'])
47 ->setEmptyData($options['empty_data'])
48 ->setPropertyPath($options['property_path'])
49 ->setMapped($options['mapped'])
50 ->setByReference($options['by_reference'])
51 ->setInheritData($options['inherit_data'])
52 ->setCompound($options['compound'])
53 ->setData(isset($options['data']) ? $options['data'] : null)
54 ->setDataLocked(isset($options['data']))
55 ->setDataMapper($options['compound'] ? new PropertyPathMapper($this->propertyAccessor) : null)
56 ->setMethod($options['method'])
57 ->setAction($options['action'])
58 ->setAutoInitialize($options['auto_initialize'])
59 ;
60
61 if ($options['trim']) {
62 $builder->addEventSubscriber(new TrimListener());
63 }
64 }
65
66 /**
67 * {@inheritdoc}
68 */
69 public function buildView(FormView $view, FormInterface $form, array $options)
70 {
71 parent::buildView($view, $form, $options);
72
73 $name = $form->getName();
74 $readOnly = $options['read_only'];
75
76 if ($view->parent) {
77 if ('' === $name) {
78 throw new LogicException('Form node with empty name can be used only as root form node.');
79 }
80
81 // Complex fields are read-only if they themselves or their parents are.
82 if (!$readOnly) {
83 $readOnly = $view->parent->vars['read_only'];
84 }
85 }
86
87 $view->vars = array_replace($view->vars, array(
88 'read_only' => $readOnly,
89 'errors' => $form->getErrors(),
90 'valid' => $form->isSubmitted() ? $form->isValid() : true,
91 'value' => $form->getViewData(),
92 'data' => $form->getNormData(),
93 'required' => $form->isRequired(),
94 'max_length' => $options['max_length'],
95 'pattern' => $options['pattern'],
96 'size' => null,
97 'label_attr' => $options['label_attr'],
98 'compound' => $form->getConfig()->getCompound(),
99 'method' => $form->getConfig()->getMethod(),
100 'action' => $form->getConfig()->getAction(),
101 ));
102 }
103
104 /**
105 * {@inheritdoc}
106 */
107 public function finishView(FormView $view, FormInterface $form, array $options)
108 {
109 $multipart = false;
110
111 foreach ($view->children as $child) {
112 if ($child->vars['multipart']) {
113 $multipart = true;
114 break;
115 }
116 }
117
118 $view->vars['multipart'] = $multipart;
119 }
120
121 /**
122 * {@inheritdoc}
123 */
124 public function setDefaultOptions(OptionsResolverInterface $resolver)
125 {
126 parent::setDefaultOptions($resolver);
127
128 // Derive "data_class" option from passed "data" object
129 $dataClass = function (Options $options) {
130 return isset($options['data']) && is_object($options['data']) ? get_class($options['data']) : null;
131 };
132
133 // Derive "empty_data" closure from "data_class" option
134 $emptyData = function (Options $options) {
135 $class = $options['data_class'];
136
137 if (null !== $class) {
138 return function (FormInterface $form) use ($class) {
139 return $form->isEmpty() && !$form->isRequired() ? null : new $class();
140 };
141 }
142
143 return function (FormInterface $form) {
144 return $form->getConfig()->getCompound() ? array() : '';
145 };
146 };
147
148 // For any form that is not represented by a single HTML control,
149 // errors should bubble up by default
150 $errorBubbling = function (Options $options) {
151 return $options['compound'];
152 };
153
154 // BC with old "virtual" option
155 $inheritData = function (Options $options) {
156 if (null !== $options['virtual']) {
157 // Uncomment this as soon as the deprecation note should be shown
158 // trigger_error('The form option "virtual" is deprecated since version 2.3 and will be removed in 3.0. Use "inherit_data" instead.', E_USER_DEPRECATED);
159 return $options['virtual'];
160 }
161
162 return false;
163 };
164
165 // If data is given, the form is locked to that data
166 // (independent of its value)
167 $resolver->setOptional(array(
168 'data',
169 ));
170
171 $resolver->setDefaults(array(
172 'data_class' => $dataClass,
173 'empty_data' => $emptyData,
174 'trim' => true,
175 'required' => true,
176 'read_only' => false,
177 'max_length' => null,
178 'pattern' => null,
179 'property_path' => null,
180 'mapped' => true,
181 'by_reference' => true,
182 'error_bubbling' => $errorBubbling,
183 'label_attr' => array(),
184 'virtual' => null,
185 'inherit_data' => $inheritData,
186 'compound' => true,
187 'method' => 'POST',
188 // According to RFC 2396 (http://www.ietf.org/rfc/rfc2396.txt)
189 // section 4.2., empty URIs are considered same-document references
190 'action' => '',
191 'auto_initialize' => true,
192 ));
193
194 $resolver->setAllowedTypes(array(
195 'label_attr' => 'array',
196 ));
197 }
198
199 /**
200 * {@inheritdoc}
201 */
202 public function getParent()
203 {
204 return null;
205 }
206
207 /**
208 * {@inheritdoc}
209 */
210 public function getName()
211 {
212 return 'form';
213 }
214}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/HiddenType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/HiddenType.php
new file mode 100644
index 00000000..bd4fa898
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/HiddenType.php
@@ -0,0 +1,40 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\OptionsResolver\OptionsResolverInterface;
16
17class HiddenType extends AbstractType
18{
19 /**
20 * {@inheritdoc}
21 */
22 public function setDefaultOptions(OptionsResolverInterface $resolver)
23 {
24 $resolver->setDefaults(array(
25 // hidden fields cannot have a required attribute
26 'required' => false,
27 // Pass errors to the parent
28 'error_bubbling' => true,
29 'compound' => false,
30 ));
31 }
32
33 /**
34 * {@inheritdoc}
35 */
36 public function getName()
37 {
38 return 'hidden';
39 }
40}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/IntegerType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/IntegerType.php
new file mode 100644
index 00000000..b224cac5
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/IntegerType.php
@@ -0,0 +1,68 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilderInterface;
16use Symfony\Component\Form\Extension\Core\DataTransformer\IntegerToLocalizedStringTransformer;
17use Symfony\Component\OptionsResolver\OptionsResolverInterface;
18
19class IntegerType extends AbstractType
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function buildForm(FormBuilderInterface $builder, array $options)
25 {
26 $builder->addViewTransformer(
27 new IntegerToLocalizedStringTransformer(
28 $options['precision'],
29 $options['grouping'],
30 $options['rounding_mode']
31 ));
32 }
33
34 /**
35 * {@inheritdoc}
36 */
37 public function setDefaultOptions(OptionsResolverInterface $resolver)
38 {
39 $resolver->setDefaults(array(
40 // default precision is locale specific (usually around 3)
41 'precision' => null,
42 'grouping' => false,
43 // Integer cast rounds towards 0, so do the same when displaying fractions
44 'rounding_mode' => \NumberFormatter::ROUND_DOWN,
45 'compound' => false,
46 ));
47
48 $resolver->setAllowedValues(array(
49 'rounding_mode' => array(
50 \NumberFormatter::ROUND_FLOOR,
51 \NumberFormatter::ROUND_DOWN,
52 \NumberFormatter::ROUND_HALFDOWN,
53 \NumberFormatter::ROUND_HALFEVEN,
54 \NumberFormatter::ROUND_HALFUP,
55 \NumberFormatter::ROUND_UP,
56 \NumberFormatter::ROUND_CEILING,
57 ),
58 ));
59 }
60
61 /**
62 * {@inheritdoc}
63 */
64 public function getName()
65 {
66 return 'integer';
67 }
68}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/LanguageType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/LanguageType.php
new file mode 100644
index 00000000..37b2bf33
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/LanguageType.php
@@ -0,0 +1,45 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Intl\Intl;
16use Symfony\Component\OptionsResolver\OptionsResolverInterface;
17
18class LanguageType extends AbstractType
19{
20 /**
21 * {@inheritdoc}
22 */
23 public function setDefaultOptions(OptionsResolverInterface $resolver)
24 {
25 $resolver->setDefaults(array(
26 'choices' => Intl::getLanguageBundle()->getLanguageNames(),
27 ));
28 }
29
30 /**
31 * {@inheritdoc}
32 */
33 public function getParent()
34 {
35 return 'choice';
36 }
37
38 /**
39 * {@inheritdoc}
40 */
41 public function getName()
42 {
43 return 'language';
44 }
45}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/LocaleType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/LocaleType.php
new file mode 100644
index 00000000..c68c561a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/LocaleType.php
@@ -0,0 +1,46 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Intl\Intl;
16use Symfony\Component\Locale\Locale;
17use Symfony\Component\OptionsResolver\OptionsResolverInterface;
18
19class LocaleType extends AbstractType
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function setDefaultOptions(OptionsResolverInterface $resolver)
25 {
26 $resolver->setDefaults(array(
27 'choices' => Intl::getLocaleBundle()->getLocaleNames(),
28 ));
29 }
30
31 /**
32 * {@inheritdoc}
33 */
34 public function getParent()
35 {
36 return 'choice';
37 }
38
39 /**
40 * {@inheritdoc}
41 */
42 public function getName()
43 {
44 return 'locale';
45 }
46}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/MoneyType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/MoneyType.php
new file mode 100644
index 00000000..9e36f9ce
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/MoneyType.php
@@ -0,0 +1,111 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\FormBuilderInterface;
17use Symfony\Component\Form\Extension\Core\DataTransformer\MoneyToLocalizedStringTransformer;
18use Symfony\Component\Form\FormView;
19use Symfony\Component\OptionsResolver\OptionsResolverInterface;
20
21class MoneyType extends AbstractType
22{
23 protected static $patterns = array();
24
25 /**
26 * {@inheritdoc}
27 */
28 public function buildForm(FormBuilderInterface $builder, array $options)
29 {
30 $builder
31 ->addViewTransformer(new MoneyToLocalizedStringTransformer(
32 $options['precision'],
33 $options['grouping'],
34 null,
35 $options['divisor']
36 ))
37 ;
38 }
39
40 /**
41 * {@inheritdoc}
42 */
43 public function buildView(FormView $view, FormInterface $form, array $options)
44 {
45 $view->vars['money_pattern'] = self::getPattern($options['currency']);
46 }
47
48 /**
49 * {@inheritdoc}
50 */
51 public function setDefaultOptions(OptionsResolverInterface $resolver)
52 {
53 $resolver->setDefaults(array(
54 'precision' => 2,
55 'grouping' => false,
56 'divisor' => 1,
57 'currency' => 'EUR',
58 'compound' => false,
59 ));
60 }
61
62 /**
63 * {@inheritdoc}
64 */
65 public function getName()
66 {
67 return 'money';
68 }
69
70 /**
71 * Returns the pattern for this locale
72 *
73 * The pattern contains the placeholder "{{ widget }}" where the HTML tag should
74 * be inserted
75 */
76 protected static function getPattern($currency)
77 {
78 if (!$currency) {
79 return '{{ widget }}';
80 }
81
82 $locale = \Locale::getDefault();
83
84 if (!isset(self::$patterns[$locale])) {
85 self::$patterns[$locale] = array();
86 }
87
88 if (!isset(self::$patterns[$locale][$currency])) {
89 $format = new \NumberFormatter($locale, \NumberFormatter::CURRENCY);
90 $pattern = $format->formatCurrency('123', $currency);
91
92 // the spacings between currency symbol and number are ignored, because
93 // a single space leads to better readability in combination with input
94 // fields
95
96 // the regex also considers non-break spaces (0xC2 or 0xA0 in UTF-8)
97
98 preg_match('/^([^\s\xc2\xa0]*)[\s\xc2\xa0]*123(?:[,.]0+)?[\s\xc2\xa0]*([^\s\xc2\xa0]*)$/u', $pattern, $matches);
99
100 if (!empty($matches[1])) {
101 self::$patterns[$locale][$currency] = $matches[1].' {{ widget }}';
102 } elseif (!empty($matches[2])) {
103 self::$patterns[$locale][$currency] = '{{ widget }} '.$matches[2];
104 } else {
105 self::$patterns[$locale][$currency] = '{{ widget }}';
106 }
107 }
108
109 return self::$patterns[$locale][$currency];
110 }
111}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/NumberType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/NumberType.php
new file mode 100644
index 00000000..beb3c89a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/NumberType.php
@@ -0,0 +1,66 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilderInterface;
16use Symfony\Component\Form\Extension\Core\DataTransformer\NumberToLocalizedStringTransformer;
17use Symfony\Component\OptionsResolver\OptionsResolverInterface;
18
19class NumberType extends AbstractType
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function buildForm(FormBuilderInterface $builder, array $options)
25 {
26 $builder->addViewTransformer(new NumberToLocalizedStringTransformer(
27 $options['precision'],
28 $options['grouping'],
29 $options['rounding_mode']
30 ));
31 }
32
33 /**
34 * {@inheritdoc}
35 */
36 public function setDefaultOptions(OptionsResolverInterface $resolver)
37 {
38 $resolver->setDefaults(array(
39 // default precision is locale specific (usually around 3)
40 'precision' => null,
41 'grouping' => false,
42 'rounding_mode' => \NumberFormatter::ROUND_HALFUP,
43 'compound' => false,
44 ));
45
46 $resolver->setAllowedValues(array(
47 'rounding_mode' => array(
48 \NumberFormatter::ROUND_FLOOR,
49 \NumberFormatter::ROUND_DOWN,
50 \NumberFormatter::ROUND_HALFDOWN,
51 \NumberFormatter::ROUND_HALFEVEN,
52 \NumberFormatter::ROUND_HALFUP,
53 \NumberFormatter::ROUND_UP,
54 \NumberFormatter::ROUND_CEILING,
55 ),
56 ));
57 }
58
59 /**
60 * {@inheritdoc}
61 */
62 public function getName()
63 {
64 return 'number';
65 }
66}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/PasswordType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/PasswordType.php
new file mode 100644
index 00000000..5a5b1635
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/PasswordType.php
@@ -0,0 +1,57 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\FormView;
17use Symfony\Component\OptionsResolver\OptionsResolverInterface;
18
19class PasswordType extends AbstractType
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function buildView(FormView $view, FormInterface $form, array $options)
25 {
26 if ($options['always_empty'] || !$form->isSubmitted()) {
27 $view->vars['value'] = '';
28 }
29 }
30
31 /**
32 * {@inheritdoc}
33 */
34 public function setDefaultOptions(OptionsResolverInterface $resolver)
35 {
36 $resolver->setDefaults(array(
37 'always_empty' => true,
38 'trim' => false,
39 ));
40 }
41
42 /**
43 * {@inheritdoc}
44 */
45 public function getParent()
46 {
47 return 'text';
48 }
49
50 /**
51 * {@inheritdoc}
52 */
53 public function getName()
54 {
55 return 'password';
56 }
57}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/PercentType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/PercentType.php
new file mode 100644
index 00000000..b1df9436
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/PercentType.php
@@ -0,0 +1,55 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilderInterface;
16use Symfony\Component\Form\Extension\Core\DataTransformer\PercentToLocalizedStringTransformer;
17use Symfony\Component\OptionsResolver\OptionsResolverInterface;
18
19class PercentType extends AbstractType
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function buildForm(FormBuilderInterface $builder, array $options)
25 {
26 $builder->addViewTransformer(new PercentToLocalizedStringTransformer($options['precision'], $options['type']));
27 }
28
29 /**
30 * {@inheritdoc}
31 */
32 public function setDefaultOptions(OptionsResolverInterface $resolver)
33 {
34 $resolver->setDefaults(array(
35 'precision' => 0,
36 'type' => 'fractional',
37 'compound' => false,
38 ));
39
40 $resolver->setAllowedValues(array(
41 'type' => array(
42 'fractional',
43 'integer',
44 ),
45 ));
46 }
47
48 /**
49 * {@inheritdoc}
50 */
51 public function getName()
52 {
53 return 'percent';
54 }
55}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/RadioType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/RadioType.php
new file mode 100644
index 00000000..dfa7c7d5
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/RadioType.php
@@ -0,0 +1,33 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15
16class RadioType extends AbstractType
17{
18 /**
19 * {@inheritdoc}
20 */
21 public function getParent()
22 {
23 return 'checkbox';
24 }
25
26 /**
27 * {@inheritdoc}
28 */
29 public function getName()
30 {
31 return 'radio';
32 }
33}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/RepeatedType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/RepeatedType.php
new file mode 100644
index 00000000..9a3cd146
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/RepeatedType.php
@@ -0,0 +1,67 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilderInterface;
16use Symfony\Component\Form\Extension\Core\DataTransformer\ValueToDuplicatesTransformer;
17use Symfony\Component\OptionsResolver\OptionsResolverInterface;
18
19class RepeatedType extends AbstractType
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function buildForm(FormBuilderInterface $builder, array $options)
25 {
26 // Overwrite required option for child fields
27 $options['first_options']['required'] = $options['required'];
28 $options['second_options']['required'] = $options['required'];
29
30 if (!isset($options['options']['error_bubbling'])) {
31 $options['options']['error_bubbling'] = $options['error_bubbling'];
32 }
33
34 $builder
35 ->addViewTransformer(new ValueToDuplicatesTransformer(array(
36 $options['first_name'],
37 $options['second_name'],
38 )))
39 ->add($options['first_name'], $options['type'], array_merge($options['options'], $options['first_options']))
40 ->add($options['second_name'], $options['type'], array_merge($options['options'], $options['second_options']))
41 ;
42 }
43
44 /**
45 * {@inheritdoc}
46 */
47 public function setDefaultOptions(OptionsResolverInterface $resolver)
48 {
49 $resolver->setDefaults(array(
50 'type' => 'text',
51 'options' => array(),
52 'first_options' => array(),
53 'second_options' => array(),
54 'first_name' => 'first',
55 'second_name' => 'second',
56 'error_bubbling' => false,
57 ));
58 }
59
60 /**
61 * {@inheritdoc}
62 */
63 public function getName()
64 {
65 return 'repeated';
66 }
67}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ResetType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ResetType.php
new file mode 100644
index 00000000..cf55f7c5
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ResetType.php
@@ -0,0 +1,39 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\ButtonTypeInterface;
16
17/**
18 * A reset button.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class ResetType extends AbstractType implements ButtonTypeInterface
23{
24 /**
25 * {@inheritdoc}
26 */
27 public function getParent()
28 {
29 return 'button';
30 }
31
32 /**
33 * {@inheritdoc}
34 */
35 public function getName()
36 {
37 return 'reset';
38 }
39}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/SearchType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/SearchType.php
new file mode 100644
index 00000000..bf82972d
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/SearchType.php
@@ -0,0 +1,33 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15
16class SearchType extends AbstractType
17{
18 /**
19 * {@inheritdoc}
20 */
21 public function getParent()
22 {
23 return 'text';
24 }
25
26 /**
27 * {@inheritdoc}
28 */
29 public function getName()
30 {
31 return 'search';
32 }
33}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/SubmitType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/SubmitType.php
new file mode 100644
index 00000000..6d160b96
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/SubmitType.php
@@ -0,0 +1,46 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\FormView;
17use Symfony\Component\Form\SubmitButtonTypeInterface;
18
19/**
20 * A submit button.
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class SubmitType extends AbstractType implements SubmitButtonTypeInterface
25{
26 public function buildView(FormView $view, FormInterface $form, array $options)
27 {
28 $view->vars['clicked'] = $form->isClicked();
29 }
30
31 /**
32 * {@inheritdoc}
33 */
34 public function getParent()
35 {
36 return 'button';
37 }
38
39 /**
40 * {@inheritdoc}
41 */
42 public function getName()
43 {
44 return 'submit';
45 }
46}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TextType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TextType.php
new file mode 100644
index 00000000..11503261
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TextType.php
@@ -0,0 +1,36 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\OptionsResolver\OptionsResolverInterface;
16
17class TextType extends AbstractType
18{
19 /**
20 * {@inheritdoc}
21 */
22 public function setDefaultOptions(OptionsResolverInterface $resolver)
23 {
24 $resolver->setDefaults(array(
25 'compound' => false,
26 ));
27 }
28
29 /**
30 * {@inheritdoc}
31 */
32 public function getName()
33 {
34 return 'text';
35 }
36}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TextareaType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TextareaType.php
new file mode 100644
index 00000000..0e749b15
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TextareaType.php
@@ -0,0 +1,43 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormView;
16use Symfony\Component\Form\FormInterface;
17
18class TextareaType extends AbstractType
19{
20 /**
21 * {@inheritdoc}
22 */
23 public function buildView(FormView $view, FormInterface $form, array $options)
24 {
25 $view->vars['pattern'] = null;
26 }
27
28 /**
29 * {@inheritdoc}
30 */
31 public function getParent()
32 {
33 return 'text';
34 }
35
36 /**
37 * {@inheritdoc}
38 */
39 public function getName()
40 {
41 return 'textarea';
42 }
43}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TimeType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TimeType.php
new file mode 100644
index 00000000..d7a2a9ef
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TimeType.php
@@ -0,0 +1,225 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\FormBuilderInterface;
17use Symfony\Component\Form\ReversedTransformer;
18use Symfony\Component\Form\Exception\InvalidConfigurationException;
19use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
20use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
21use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
22use Symfony\Component\Form\FormView;
23use Symfony\Component\OptionsResolver\Options;
24use Symfony\Component\OptionsResolver\OptionsResolverInterface;
25
26class TimeType extends AbstractType
27{
28 /**
29 * {@inheritdoc}
30 */
31 public function buildForm(FormBuilderInterface $builder, array $options)
32 {
33 $parts = array('hour');
34 $format = 'H';
35
36 if ($options['with_seconds'] && !$options['with_minutes']) {
37 throw new InvalidConfigurationException('You can not disable minutes if you have enabled seconds.');
38 }
39
40 if ($options['with_minutes']) {
41 $format .= ':i';
42 $parts[] = 'minute';
43 }
44
45 if ($options['with_seconds']) {
46 $format .= ':s';
47 $parts[] = 'second';
48 }
49
50 if ('single_text' === $options['widget']) {
51 $builder->addViewTransformer(new DateTimeToStringTransformer($options['model_timezone'], $options['view_timezone'], $format));
52 } else {
53 $hourOptions = $minuteOptions = $secondOptions = array(
54 'error_bubbling' => true,
55 );
56
57 if ('choice' === $options['widget']) {
58 $hours = $minutes = array();
59
60 foreach ($options['hours'] as $hour) {
61 $hours[$hour] = str_pad($hour, 2, '0', STR_PAD_LEFT);
62 }
63
64 // Only pass a subset of the options to children
65 $hourOptions['choices'] = $hours;
66 $hourOptions['empty_value'] = $options['empty_value']['hour'];
67
68 if ($options['with_minutes']) {
69 foreach ($options['minutes'] as $minute) {
70 $minutes[$minute] = str_pad($minute, 2, '0', STR_PAD_LEFT);
71 }
72
73 $minuteOptions['choices'] = $minutes;
74 $minuteOptions['empty_value'] = $options['empty_value']['minute'];
75 }
76
77 if ($options['with_seconds']) {
78 $seconds = array();
79
80 foreach ($options['seconds'] as $second) {
81 $seconds[$second] = str_pad($second, 2, '0', STR_PAD_LEFT);
82 }
83
84 $secondOptions['choices'] = $seconds;
85 $secondOptions['empty_value'] = $options['empty_value']['second'];
86 }
87
88 // Append generic carry-along options
89 foreach (array('required', 'translation_domain') as $passOpt) {
90 $hourOptions[$passOpt] = $options[$passOpt];
91
92 if ($options['with_minutes']) {
93 $minuteOptions[$passOpt] = $options[$passOpt];
94 }
95
96 if ($options['with_seconds']) {
97 $secondOptions[$passOpt] = $options[$passOpt];
98 }
99 }
100 }
101
102 $builder->add('hour', $options['widget'], $hourOptions);
103
104 if ($options['with_minutes']) {
105 $builder->add('minute', $options['widget'], $minuteOptions);
106 }
107
108 if ($options['with_seconds']) {
109 $builder->add('second', $options['widget'], $secondOptions);
110 }
111
112 $builder->addViewTransformer(new DateTimeToArrayTransformer($options['model_timezone'], $options['view_timezone'], $parts, 'text' === $options['widget']));
113 }
114
115 if ('string' === $options['input']) {
116 $builder->addModelTransformer(new ReversedTransformer(
117 new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'], 'H:i:s')
118 ));
119 } elseif ('timestamp' === $options['input']) {
120 $builder->addModelTransformer(new ReversedTransformer(
121 new DateTimeToTimestampTransformer($options['model_timezone'], $options['model_timezone'])
122 ));
123 } elseif ('array' === $options['input']) {
124 $builder->addModelTransformer(new ReversedTransformer(
125 new DateTimeToArrayTransformer($options['model_timezone'], $options['model_timezone'], $parts)
126 ));
127 }
128 }
129
130 /**
131 * {@inheritdoc}
132 */
133 public function buildView(FormView $view, FormInterface $form, array $options)
134 {
135 $view->vars = array_replace($view->vars, array(
136 'widget' => $options['widget'],
137 'with_minutes' => $options['with_minutes'],
138 'with_seconds' => $options['with_seconds'],
139 ));
140
141 if ('single_text' === $options['widget']) {
142 $view->vars['type'] = 'time';
143 }
144 }
145
146 /**
147 * {@inheritdoc}
148 */
149 public function setDefaultOptions(OptionsResolverInterface $resolver)
150 {
151 $compound = function (Options $options) {
152 return $options['widget'] !== 'single_text';
153 };
154
155 $emptyValue = $emptyValueDefault = function (Options $options) {
156 return $options['required'] ? null : '';
157 };
158
159 $emptyValueNormalizer = function (Options $options, $emptyValue) use ($emptyValueDefault) {
160 if (is_array($emptyValue)) {
161 $default = $emptyValueDefault($options);
162
163 return array_merge(
164 array('hour' => $default, 'minute' => $default, 'second' => $default),
165 $emptyValue
166 );
167 }
168
169 return array(
170 'hour' => $emptyValue,
171 'minute' => $emptyValue,
172 'second' => $emptyValue
173 );
174 };
175
176 $resolver->setDefaults(array(
177 'hours' => range(0, 23),
178 'minutes' => range(0, 59),
179 'seconds' => range(0, 59),
180 'widget' => 'choice',
181 'input' => 'datetime',
182 'with_minutes' => true,
183 'with_seconds' => false,
184 'model_timezone' => null,
185 'view_timezone' => null,
186 'empty_value' => $emptyValue,
187 // Don't modify \DateTime classes by reference, we treat
188 // them like immutable value objects
189 'by_reference' => false,
190 'error_bubbling' => false,
191 // If initialized with a \DateTime object, FormType initializes
192 // this option to "\DateTime". Since the internal, normalized
193 // representation is not \DateTime, but an array, we need to unset
194 // this option.
195 'data_class' => null,
196 'compound' => $compound,
197 ));
198
199 $resolver->setNormalizers(array(
200 'empty_value' => $emptyValueNormalizer,
201 ));
202
203 $resolver->setAllowedValues(array(
204 'input' => array(
205 'datetime',
206 'string',
207 'timestamp',
208 'array',
209 ),
210 'widget' => array(
211 'single_text',
212 'text',
213 'choice',
214 ),
215 ));
216 }
217
218 /**
219 * {@inheritdoc}
220 */
221 public function getName()
222 {
223 return 'time';
224 }
225}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php
new file mode 100644
index 00000000..cd4a2ad3
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php
@@ -0,0 +1,86 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\OptionsResolver\OptionsResolverInterface;
16
17class TimezoneType extends AbstractType
18{
19 /**
20 * Stores the available timezone choices
21 * @var array
22 */
23 private static $timezones;
24
25 /**
26 * {@inheritdoc}
27 */
28 public function setDefaultOptions(OptionsResolverInterface $resolver)
29 {
30 $resolver->setDefaults(array(
31 'choices' => self::getTimezones(),
32 ));
33 }
34
35 /**
36 * {@inheritdoc}
37 */
38 public function getParent()
39 {
40 return 'choice';
41 }
42
43 /**
44 * {@inheritdoc}
45 */
46 public function getName()
47 {
48 return 'timezone';
49 }
50
51 /**
52 * Returns the timezone choices.
53 *
54 * The choices are generated from the ICU function
55 * \DateTimeZone::listIdentifiers(). They are cached during a single request,
56 * so multiple timezone fields on the same page don't lead to unnecessary
57 * overhead.
58 *
59 * @return array The timezone choices
60 */
61 public static function getTimezones()
62 {
63 if (null === static::$timezones) {
64 static::$timezones = array();
65
66 foreach (\DateTimeZone::listIdentifiers() as $timezone) {
67 $parts = explode('/', $timezone);
68
69 if (count($parts) > 2) {
70 $region = $parts[0];
71 $name = $parts[1].' - '.$parts[2];
72 } elseif (count($parts) > 1) {
73 $region = $parts[0];
74 $name = $parts[1];
75 } else {
76 $region = 'Other';
77 $name = $parts[0];
78 }
79
80 static::$timezones[$region][$timezone] = str_replace('_', ' ', $name);
81 }
82 }
83
84 return static::$timezones;
85 }
86}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/UrlType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/UrlType.php
new file mode 100644
index 00000000..27749b1a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/UrlType.php
@@ -0,0 +1,54 @@
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\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilderInterface;
16use Symfony\Component\Form\Extension\Core\EventListener\FixUrlProtocolListener;
17use Symfony\Component\OptionsResolver\OptionsResolverInterface;
18
19class UrlType extends AbstractType
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function buildForm(FormBuilderInterface $builder, array $options)
25 {
26 $builder->addEventSubscriber(new FixUrlProtocolListener($options['default_protocol']));
27 }
28
29 /**
30 * {@inheritdoc}
31 */
32 public function setDefaultOptions(OptionsResolverInterface $resolver)
33 {
34 $resolver->setDefaults(array(
35 'default_protocol' => 'http',
36 ));
37 }
38
39 /**
40 * {@inheritdoc}
41 */
42 public function getParent()
43 {
44 return 'text';
45 }
46
47 /**
48 * {@inheritdoc}
49 */
50 public function getName()
51 {
52 return 'url';
53 }
54}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/View/ChoiceView.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/View/ChoiceView.php
new file mode 100644
index 00000000..97cdd214
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/View/ChoiceView.php
@@ -0,0 +1,55 @@
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\View;
13
14/**
15 * Represents a choice in templates.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class ChoiceView
20{
21 /**
22 * The original choice value.
23 *
24 * @var mixed
25 */
26 public $data;
27
28 /**
29 * The view representation of the choice.
30 *
31 * @var string
32 */
33 public $value;
34
35 /**
36 * The label displayed to humans.
37 *
38 * @var string
39 */
40 public $label;
41
42 /**
43 * Creates a new ChoiceView.
44 *
45 * @param mixed $data The original choice.
46 * @param string $value The view representation of the choice.
47 * @param string $label The label displayed to humans.
48 */
49 public function __construct($data, $value, $label)
50 {
51 $this->data = $data;
52 $this->value = $value;
53 $this->label = $label;
54 }
55}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php
new file mode 100644
index 00000000..f9d9e40a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php
@@ -0,0 +1,64 @@
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\Csrf;
13
14use Symfony\Component\Form\Extension\Csrf\Type;
15use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
16use Symfony\Component\Form\AbstractExtension;
17use Symfony\Component\Translation\TranslatorInterface;
18
19/**
20 * This extension protects forms by using a CSRF token.
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class CsrfExtension extends AbstractExtension
25{
26 /**
27 * @var CsrfProviderInterface
28 */
29 private $csrfProvider;
30
31 /**
32 * @var TranslatorInterface
33 */
34 private $translator;
35
36 /**
37 * @var null|string
38 */
39 private $translationDomain;
40
41 /**
42 * Constructor.
43 *
44 * @param CsrfProviderInterface $csrfProvider The CSRF provider
45 * @param TranslatorInterface $translator The translator for translating error messages.
46 * @param null|string $translationDomain The translation domain for translating.
47 */
48 public function __construct(CsrfProviderInterface $csrfProvider, TranslatorInterface $translator = null, $translationDomain = null)
49 {
50 $this->csrfProvider = $csrfProvider;
51 $this->translator = $translator;
52 $this->translationDomain = $translationDomain;
53 }
54
55 /**
56 * {@inheritDoc}
57 */
58 protected function loadTypeExtensions()
59 {
60 return array(
61 new Type\FormTypeCsrfExtension($this->csrfProvider, true, '_token', $this->translator, $this->translationDomain),
62 );
63 }
64}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/CsrfProviderInterface.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/CsrfProviderInterface.php
new file mode 100644
index 00000000..7143b130
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/CsrfProviderInterface.php
@@ -0,0 +1,49 @@
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\Csrf\CsrfProvider;
13
14/**
15 * Marks classes able to provide CSRF protection
16 *
17 * You can generate a CSRF token by using the method generateCsrfToken(). To
18 * this method you should pass a value that is unique to the page that should
19 * be secured against CSRF attacks. This value doesn't necessarily have to be
20 * secret. Implementations of this interface are responsible for adding more
21 * secret information.
22 *
23 * If you want to secure a form submission against CSRF attacks, you could
24 * supply an "intention" string. This way you make sure that the form can only
25 * be submitted to pages that are designed to handle the form, that is, that use
26 * the same intention string to validate the CSRF token with isCsrfTokenValid().
27 *
28 * @author Bernhard Schussek <bschussek@gmail.com>
29 */
30interface CsrfProviderInterface
31{
32 /**
33 * Generates a CSRF token for a page of your application.
34 *
35 * @param string $intention Some value that identifies the action intention
36 * (i.e. "authenticate"). Doesn't have to be a secret value.
37 */
38 public function generateCsrfToken($intention);
39
40 /**
41 * Validates a CSRF token.
42 *
43 * @param string $intention The intention used when generating the CSRF token
44 * @param string $token The token supplied by the browser
45 *
46 * @return Boolean Whether the token supplied by the browser is correct
47 */
48 public function isCsrfTokenValid($intention, $token);
49}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php
new file mode 100644
index 00000000..5354886c
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php
@@ -0,0 +1,78 @@
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\Csrf\CsrfProvider;
13
14/**
15 * Default implementation of CsrfProviderInterface.
16 *
17 * This provider uses the session ID returned by session_id() as well as a
18 * user-defined secret value to secure the CSRF token.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class DefaultCsrfProvider implements CsrfProviderInterface
23{
24 /**
25 * A secret value used for generating the CSRF token
26 * @var string
27 */
28 protected $secret;
29
30 /**
31 * Initializes the provider with a secret value
32 *
33 * A recommended value for the secret is a generated value with at least
34 * 32 characters and mixed letters, digits and special characters.
35 *
36 * @param string $secret A secret value included in the CSRF token
37 */
38 public function __construct($secret)
39 {
40 $this->secret = $secret;
41 }
42
43 /**
44 * {@inheritDoc}
45 */
46 public function generateCsrfToken($intention)
47 {
48 return sha1($this->secret.$intention.$this->getSessionId());
49 }
50
51 /**
52 * {@inheritDoc}
53 */
54 public function isCsrfTokenValid($intention, $token)
55 {
56 return $token === $this->generateCsrfToken($intention);
57 }
58
59 /**
60 * Returns the ID of the user session.
61 *
62 * Automatically starts the session if necessary.
63 *
64 * @return string The session ID
65 */
66 protected function getSessionId()
67 {
68 if (version_compare(PHP_VERSION, '5.4', '>=')) {
69 if (PHP_SESSION_NONE === session_status()) {
70 session_start();
71 }
72 } elseif (!session_id()) {
73 session_start();
74 }
75
76 return session_id();
77 }
78}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProvider.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProvider.php
new file mode 100644
index 00000000..ea1fa585
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProvider.php
@@ -0,0 +1,57 @@
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\Csrf\CsrfProvider;
13
14use Symfony\Component\HttpFoundation\Session\Session;
15
16/**
17 * This provider uses a Symfony2 Session object to retrieve the user's
18 * session ID.
19 *
20 * @see DefaultCsrfProvider
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class SessionCsrfProvider extends DefaultCsrfProvider
25{
26 /**
27 * The user session from which the session ID is returned
28 * @var Session
29 */
30 protected $session;
31
32 /**
33 * Initializes the provider with a Session object and a secret value.
34 *
35 * A recommended value for the secret is a generated value with at least
36 * 32 characters and mixed letters, digits and special characters.
37 *
38 * @param Session $session The user session
39 * @param string $secret A secret value included in the CSRF token
40 */
41 public function __construct(Session $session, $secret)
42 {
43 parent::__construct($secret);
44
45 $this->session = $session;
46 }
47
48 /**
49 * {@inheritdoc}
50 */
51 protected function getSessionId()
52 {
53 $this->session->start();
54
55 return $this->session->getId();
56 }
57}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php
new file mode 100644
index 00000000..547e9d75
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php
@@ -0,0 +1,115 @@
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\Csrf\EventListener;
13
14use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15use Symfony\Component\Form\FormEvents;
16use Symfony\Component\Form\FormError;
17use Symfony\Component\Form\FormEvent;
18use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
19use Symfony\Component\Translation\TranslatorInterface;
20
21/**
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class CsrfValidationListener implements EventSubscriberInterface
25{
26 /**
27 * The name of the CSRF field
28 * @var string
29 */
30 private $fieldName;
31
32 /**
33 * The provider for generating and validating CSRF tokens
34 * @var CsrfProviderInterface
35 */
36 private $csrfProvider;
37
38 /**
39 * A text mentioning the intention of the CSRF token
40 *
41 * Validation of the token will only succeed if it was generated in the
42 * same session and with the same intention.
43 *
44 * @var string
45 */
46 private $intention;
47
48 /**
49 * The message displayed in case of an error.
50 * @var string
51 */
52 private $errorMessage;
53
54 /**
55 * @var TranslatorInterface
56 */
57 private $translator;
58
59 /**
60 * @var null|string
61 */
62 private $translationDomain;
63
64 public static function getSubscribedEvents()
65 {
66 return array(
67 FormEvents::PRE_SUBMIT => 'preSubmit',
68 );
69 }
70
71 public function __construct($fieldName, CsrfProviderInterface $csrfProvider, $intention, $errorMessage, TranslatorInterface $translator = null, $translationDomain = null)
72 {
73 $this->fieldName = $fieldName;
74 $this->csrfProvider = $csrfProvider;
75 $this->intention = $intention;
76 $this->errorMessage = $errorMessage;
77 $this->translator = $translator;
78 $this->translationDomain = $translationDomain;
79 }
80
81 public function preSubmit(FormEvent $event)
82 {
83 $form = $event->getForm();
84 $data = $event->getData();
85
86 if ($form->isRoot() && $form->getConfig()->getOption('compound')) {
87 if (!isset($data[$this->fieldName]) || !$this->csrfProvider->isCsrfTokenValid($this->intention, $data[$this->fieldName])) {
88 $errorMessage = $this->errorMessage;
89
90 if (null !== $this->translator) {
91 $errorMessage = $this->translator->trans($errorMessage, array(), $this->translationDomain);
92 }
93
94 $form->addError(new FormError($errorMessage));
95 }
96
97 if (is_array($data)) {
98 unset($data[$this->fieldName]);
99 }
100 }
101
102 $event->setData($data);
103 }
104
105 /**
106 * Alias of {@link preSubmit()}.
107 *
108 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
109 * {@link preSubmit()} instead.
110 */
111 public function preBind(FormEvent $event)
112 {
113 $this->preSubmit($event);
114 }
115}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php
new file mode 100644
index 00000000..336cf047
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php
@@ -0,0 +1,129 @@
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\Csrf\Type;
13
14use Symfony\Component\Form\AbstractTypeExtension;
15use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
16use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener;
17use Symfony\Component\Form\FormBuilderInterface;
18use Symfony\Component\Form\FormView;
19use Symfony\Component\Form\FormInterface;
20use Symfony\Component\OptionsResolver\OptionsResolverInterface;
21use Symfony\Component\Translation\TranslatorInterface;
22
23/**
24 * @author Bernhard Schussek <bschussek@gmail.com>
25 */
26class FormTypeCsrfExtension extends AbstractTypeExtension
27{
28 /**
29 * @var CsrfProviderInterface
30 */
31 private $defaultCsrfProvider;
32
33 /**
34 * @var Boolean
35 */
36 private $defaultEnabled;
37
38 /**
39 * @var string
40 */
41 private $defaultFieldName;
42
43 /**
44 * @var TranslatorInterface
45 */
46 private $translator;
47
48 /**
49 * @var null|string
50 */
51 private $translationDomain;
52
53 public function __construct(CsrfProviderInterface $defaultCsrfProvider, $defaultEnabled = true, $defaultFieldName = '_token', TranslatorInterface $translator = null, $translationDomain = null)
54 {
55 $this->defaultCsrfProvider = $defaultCsrfProvider;
56 $this->defaultEnabled = $defaultEnabled;
57 $this->defaultFieldName = $defaultFieldName;
58 $this->translator = $translator;
59 $this->translationDomain = $translationDomain;
60 }
61
62 /**
63 * Adds a CSRF field to the form when the CSRF protection is enabled.
64 *
65 * @param FormBuilderInterface $builder The form builder
66 * @param array $options The options
67 */
68 public function buildForm(FormBuilderInterface $builder, array $options)
69 {
70 if (!$options['csrf_protection']) {
71 return;
72 }
73
74 $builder
75 ->setAttribute('csrf_factory', $builder->getFormFactory())
76 ->addEventSubscriber(new CsrfValidationListener(
77 $options['csrf_field_name'],
78 $options['csrf_provider'],
79 $options['intention'],
80 $options['csrf_message'],
81 $this->translator,
82 $this->translationDomain
83 ))
84 ;
85 }
86
87 /**
88 * Adds a CSRF field to the root form view.
89 *
90 * @param FormView $view The form view
91 * @param FormInterface $form The form
92 * @param array $options The options
93 */
94 public function finishView(FormView $view, FormInterface $form, array $options)
95 {
96 if ($options['csrf_protection'] && !$view->parent && $options['compound']) {
97 $factory = $form->getConfig()->getAttribute('csrf_factory');
98 $data = $options['csrf_provider']->generateCsrfToken($options['intention']);
99
100 $csrfForm = $factory->createNamed($options['csrf_field_name'], 'hidden', $data, array(
101 'mapped' => false,
102 ));
103
104 $view->children[$options['csrf_field_name']] = $csrfForm->createView($view);
105 }
106 }
107
108 /**
109 * {@inheritDoc}
110 */
111 public function setDefaultOptions(OptionsResolverInterface $resolver)
112 {
113 $resolver->setDefaults(array(
114 'csrf_protection' => $this->defaultEnabled,
115 'csrf_field_name' => $this->defaultFieldName,
116 'csrf_provider' => $this->defaultCsrfProvider,
117 'csrf_message' => 'The CSRF token is invalid. Please try to resubmit the form.',
118 'intention' => 'unknown',
119 ));
120 }
121
122 /**
123 * {@inheritDoc}
124 */
125 public function getExtendedType()
126 {
127 return 'form';
128 }
129}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/DependencyInjection/DependencyInjectionExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/DependencyInjection/DependencyInjectionExtension.php
new file mode 100644
index 00000000..6637ac8c
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/DependencyInjection/DependencyInjectionExtension.php
@@ -0,0 +1,101 @@
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\DependencyInjection;
13
14use Symfony\Component\Form\FormExtensionInterface;
15use Symfony\Component\Form\FormTypeGuesserChain;
16use Symfony\Component\Form\Exception\InvalidArgumentException;
17use Symfony\Component\DependencyInjection\ContainerInterface;
18
19class DependencyInjectionExtension implements FormExtensionInterface
20{
21 private $container;
22
23 private $typeServiceIds;
24
25 private $guesserServiceIds;
26
27 private $guesser;
28
29 private $guesserLoaded = false;
30
31 public function __construct(ContainerInterface $container,
32 array $typeServiceIds, array $typeExtensionServiceIds,
33 array $guesserServiceIds)
34 {
35 $this->container = $container;
36 $this->typeServiceIds = $typeServiceIds;
37 $this->typeExtensionServiceIds = $typeExtensionServiceIds;
38 $this->guesserServiceIds = $guesserServiceIds;
39 }
40
41 public function getType($name)
42 {
43 if (!isset($this->typeServiceIds[$name])) {
44 throw new InvalidArgumentException(sprintf('The field type "%s" is not registered with the service container.', $name));
45 }
46
47 $type = $this->container->get($this->typeServiceIds[$name]);
48
49 if ($type->getName() !== $name) {
50 throw new InvalidArgumentException(
51 sprintf('The type name specified for the service "%s" does not match the actual name. Expected "%s", given "%s"',
52 $this->typeServiceIds[$name],
53 $name,
54 $type->getName()
55 ));
56 }
57
58 return $type;
59 }
60
61 public function hasType($name)
62 {
63 return isset($this->typeServiceIds[$name]);
64 }
65
66 public function getTypeExtensions($name)
67 {
68 $extensions = array();
69
70 if (isset($this->typeExtensionServiceIds[$name])) {
71 foreach ($this->typeExtensionServiceIds[$name] as $serviceId) {
72 $extensions[] = $this->container->get($serviceId);
73 }
74 }
75
76 return $extensions;
77 }
78
79 public function hasTypeExtensions($name)
80 {
81 return isset($this->typeExtensionServiceIds[$name]);
82 }
83
84 public function getTypeGuesser()
85 {
86 if (!$this->guesserLoaded) {
87 $this->guesserLoaded = true;
88 $guessers = array();
89
90 foreach ($this->guesserServiceIds as $serviceId) {
91 $guessers[] = $this->container->get($serviceId);
92 }
93
94 if (count($guessers) > 0) {
95 $this->guesser = new FormTypeGuesserChain($guessers);
96 }
97 }
98
99 return $this->guesser;
100 }
101}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/EventListener/BindRequestListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/EventListener/BindRequestListener.php
new file mode 100644
index 00000000..6205b98d
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/EventListener/BindRequestListener.php
@@ -0,0 +1,91 @@
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\HttpFoundation\EventListener;
13
14use Symfony\Component\Form\FormEvents;
15use Symfony\Component\Form\FormEvent;
16use Symfony\Component\Form\Exception\LogicException;
17use Symfony\Component\EventDispatcher\EventSubscriberInterface;
18use Symfony\Component\HttpFoundation\Request;
19
20/**
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 *
23 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Pass the
24 * Request instance to {@link Form::process()} instead.
25 */
26class BindRequestListener implements EventSubscriberInterface
27{
28 public static function getSubscribedEvents()
29 {
30 // High priority in order to supersede other listeners
31 return array(FormEvents::PRE_BIND => array('preBind', 128));
32 }
33
34 public function preBind(FormEvent $event)
35 {
36 $form = $event->getForm();
37
38 /* @var Request $request */
39 $request = $event->getData();
40
41 // Only proceed if we actually deal with a Request
42 if (!$request instanceof Request) {
43 return;
44 }
45
46 // Uncomment this as soon as the deprecation note should be shown
47 // trigger_error('Passing a Request instance to Form::submit() is deprecated since version 2.3 and will be disabled in 3.0. Call Form::process($request) instead.', E_USER_DEPRECATED);
48
49 $name = $form->getConfig()->getName();
50 $default = $form->getConfig()->getCompound() ? array() : null;
51
52 // Store the bound data in case of a post request
53 switch ($request->getMethod()) {
54 case 'POST':
55 case 'PUT':
56 case 'DELETE':
57 case 'PATCH':
58 if ('' === $name) {
59 // Form bound without name
60 $params = $request->request->all();
61 $files = $request->files->all();
62 } else {
63 $params = $request->request->get($name, $default);
64 $files = $request->files->get($name, $default);
65 }
66
67 if (is_array($params) && is_array($files)) {
68 $data = array_replace_recursive($params, $files);
69 } else {
70 $data = $params ?: $files;
71 }
72
73 break;
74
75 case 'GET':
76 $data = '' === $name
77 ? $request->query->all()
78 : $request->query->get($name, $default);
79
80 break;
81
82 default:
83 throw new LogicException(sprintf(
84 'The request method "%s" is not supported',
85 $request->getMethod()
86 ));
87 }
88
89 $event->setData($data);
90 }
91}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationExtension.php
new file mode 100644
index 00000000..08bd89c9
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationExtension.php
@@ -0,0 +1,29 @@
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\HttpFoundation;
13
14use Symfony\Component\Form\AbstractExtension;
15
16/**
17 * Integrates the HttpFoundation component with the Form library.
18 *
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class HttpFoundationExtension extends AbstractExtension
22{
23 protected function loadTypeExtensions()
24 {
25 return array(
26 new Type\FormTypeHttpFoundationExtension(),
27 );
28 }
29}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php b/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php
new file mode 100644
index 00000000..cc485156
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php
@@ -0,0 +1,79 @@
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\HttpFoundation;
13
14use Symfony\Component\Form\Exception\UnexpectedTypeException;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\RequestHandlerInterface;
17use Symfony\Component\HttpFoundation\Request;
18
19/**
20 * A request processor using the {@link Request} class of the HttpFoundation
21 * component.
22 *
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25class HttpFoundationRequestHandler implements RequestHandlerInterface
26{
27 /**
28 * {@inheritdoc}
29 */
30 public function handleRequest(FormInterface $form, $request = null)
31 {
32 if (!$request instanceof Request) {
33 throw new UnexpectedTypeException($request, 'Symfony\Component\HttpFoundation\Request');
34 }
35
36 $name = $form->getName();
37 $method = $form->getConfig()->getMethod();
38
39 if ($method !== $request->getMethod()) {
40 return;
41 }
42
43 if ('GET' === $method) {
44 if ('' === $name) {
45 $data = $request->query->all();
46 } else {
47 // Don't submit GET requests if the form's name does not exist
48 // in the request
49 if (!$request->query->has($name)) {
50 return;
51 }
52
53 $data = $request->query->get($name);
54 }
55 } else {
56 if ('' === $name) {
57 $params = $request->request->all();
58 $files = $request->files->all();
59 } else {
60 $default = $form->getConfig()->getCompound() ? array() : null;
61 $params = $request->request->get($name, $default);
62 $files = $request->files->get($name, $default);
63 }
64
65 if (is_array($params) && is_array($files)) {
66 $data = array_replace_recursive($params, $files);
67 } else {
68 $data = $params ?: $files;
69 }
70 }
71
72 // Don't auto-submit the form unless at least one field is present.
73 if ('' === $name && count(array_intersect_key($data, $form->all())) <= 0) {
74 return;
75 }
76
77 $form->submit($data, 'PATCH' !== $method);
78 }
79}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php
new file mode 100644
index 00000000..9b09b05c
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php
@@ -0,0 +1,56 @@
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\HttpFoundation\Type;
13
14use Symfony\Component\Form\AbstractTypeExtension;
15use Symfony\Component\Form\Extension\HttpFoundation\EventListener\BindRequestListener;
16use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler;
17use Symfony\Component\Form\FormBuilderInterface;
18
19/**
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class FormTypeHttpFoundationExtension extends AbstractTypeExtension
23{
24 /**
25 * @var BindRequestListener
26 */
27 private $listener;
28
29 /**
30 * @var HttpFoundationRequestHandler
31 */
32 private $requestHandler;
33
34 public function __construct()
35 {
36 $this->listener = new BindRequestListener();
37 $this->requestHandler = new HttpFoundationRequestHandler();
38 }
39
40 /**
41 * {@inheritdoc}
42 */
43 public function buildForm(FormBuilderInterface $builder, array $options)
44 {
45 $builder->addEventSubscriber($this->listener);
46 $builder->setRequestHandler($this->requestHandler);
47 }
48
49 /**
50 * {@inheritdoc}
51 */
52 public function getExtendedType()
53 {
54 return 'form';
55 }
56}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Templating/TemplatingExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Templating/TemplatingExtension.php
new file mode 100644
index 00000000..573cb518
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Templating/TemplatingExtension.php
@@ -0,0 +1,33 @@
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\Templating;
13
14use Symfony\Component\Form\AbstractExtension;
15use Symfony\Component\Form\FormRenderer;
16use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
17use Symfony\Component\Templating\PhpEngine;
18use Symfony\Bundle\FrameworkBundle\Templating\Helper\FormHelper;
19
20/**
21 * Integrates the Templating component with the Form library.
22 *
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25class TemplatingExtension extends AbstractExtension
26{
27 public function __construct(PhpEngine $engine, CsrfProviderInterface $csrfProvider = null, array $defaultThemes = array())
28 {
29 $engine->addHelpers(array(
30 new FormHelper(new FormRenderer(new TemplatingRendererEngine($engine, $defaultThemes), $csrfProvider))
31 ));
32 }
33}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Templating/TemplatingRendererEngine.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Templating/TemplatingRendererEngine.php
new file mode 100644
index 00000000..c1dda60b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Templating/TemplatingRendererEngine.php
@@ -0,0 +1,125 @@
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\Templating;
13
14use Symfony\Component\Form\AbstractRendererEngine;
15use Symfony\Component\Form\FormView;
16use Symfony\Component\Templating\EngineInterface;
17
18/**
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class TemplatingRendererEngine extends AbstractRendererEngine
22{
23 /**
24 * @var EngineInterface
25 */
26 private $engine;
27
28 public function __construct(EngineInterface $engine, array $defaultThemes = array())
29 {
30 parent::__construct($defaultThemes);
31
32 $this->engine = $engine;
33 }
34
35 /**
36 * {@inheritdoc}
37 */
38 public function renderBlock(FormView $view, $resource, $blockName, array $variables = array())
39 {
40 return trim($this->engine->render($resource, $variables));
41 }
42
43 /**
44 * Loads the cache with the resource for a given block name.
45 *
46 * This implementation tries to load as few blocks as possible, since each block
47 * is represented by a template on the file system.
48 *
49 * @see getResourceForBlock()
50 *
51 * @param string $cacheKey The cache key of the form view.
52 * @param FormView $view The form view for finding the applying themes.
53 * @param string $blockName The name of the block to load.
54 *
55 * @return Boolean True if the resource could be loaded, false otherwise.
56 */
57 protected function loadResourceForBlockName($cacheKey, FormView $view, $blockName)
58 {
59 // Recursively try to find the block in the themes assigned to $view,
60 // then of its parent form, then of the parent form of the parent and so on.
61 // When the root form is reached in this recursion, also the default
62 // themes are taken into account.
63
64 // Check each theme whether it contains the searched block
65 if (isset($this->themes[$cacheKey])) {
66 for ($i = count($this->themes[$cacheKey]) - 1; $i >= 0; --$i) {
67 if ($this->loadResourceFromTheme($cacheKey, $blockName, $this->themes[$cacheKey][$i])) {
68 return true;
69 }
70 }
71 }
72
73 // Check the default themes once we reach the root form without success
74 if (!$view->parent) {
75 for ($i = count($this->defaultThemes) - 1; $i >= 0; --$i) {
76 if ($this->loadResourceFromTheme($cacheKey, $blockName, $this->defaultThemes[$i])) {
77 return true;
78 }
79 }
80 }
81
82 // If we did not find anything in the themes of the current view, proceed
83 // with the themes of the parent view
84 if ($view->parent) {
85 $parentCacheKey = $view->parent->vars[self::CACHE_KEY_VAR];
86
87 if (!isset($this->resources[$parentCacheKey][$blockName])) {
88 $this->loadResourceForBlockName($parentCacheKey, $view->parent, $blockName);
89 }
90
91 // If a template exists in the parent themes, cache that template
92 // for the current theme as well to speed up further accesses
93 if ($this->resources[$parentCacheKey][$blockName]) {
94 $this->resources[$cacheKey][$blockName] = $this->resources[$parentCacheKey][$blockName];
95
96 return true;
97 }
98 }
99
100 // Cache that we didn't find anything to speed up further accesses
101 $this->resources[$cacheKey][$blockName] = false;
102
103 return false;
104 }
105
106 /**
107 * Tries to load the resource for a block from a theme.
108 *
109 * @param string $cacheKey The cache key for storing the resource.
110 * @param string $blockName The name of the block to load a resource for.
111 * @param mixed $theme The theme to load the block from.
112 *
113 * @return Boolean True if the resource could be loaded, false otherwise.
114 */
115 protected function loadResourceFromTheme($cacheKey, $blockName, $theme)
116 {
117 if ($this->engine->exists($templateName = $theme.':'.$blockName.'.html.php')) {
118 $this->resources[$cacheKey][$blockName] = $templateName;
119
120 return true;
121 }
122
123 return false;
124 }
125}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/Form.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/Form.php
new file mode 100644
index 00000000..87e33297
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/Form.php
@@ -0,0 +1,33 @@
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\Validator\Constraints;
13
14use Symfony\Component\Validator\Constraint;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class Form extends Constraint
20{
21 /**
22 * Violation code marking an invalid form.
23 */
24 const ERR_INVALID = 1;
25
26 /**
27 * {@inheritdoc}
28 */
29 public function getTargets()
30 {
31 return self::CLASS_CONSTRAINT;
32 }
33}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php
new file mode 100644
index 00000000..bad5a007
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php
@@ -0,0 +1,236 @@
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\Validator\Constraints;
13
14use Symfony\Component\Form\ClickableInterface;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\Extension\Validator\Util\ServerParams;
17use Symfony\Component\Validator\Constraint;
18use Symfony\Component\Validator\ConstraintValidator;
19
20/**
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23class FormValidator extends ConstraintValidator
24{
25 /**
26 * @var ServerParams
27 */
28 private $serverParams;
29
30 /**
31 * Creates a validator with the given server parameters.
32 *
33 * @param ServerParams $params The server parameters. Default
34 * parameters are created if null.
35 */
36 public function __construct(ServerParams $params = null)
37 {
38 $this->serverParams = $params ?: new ServerParams();
39 }
40
41 /**
42 * {@inheritdoc}
43 */
44 public function validate($form, Constraint $constraint)
45 {
46 if (!$form instanceof FormInterface) {
47 return;
48 }
49
50 /* @var FormInterface $form */
51 $config = $form->getConfig();
52
53 if ($form->isSynchronized()) {
54 // Validate the form data only if transformation succeeded
55 $groups = self::getValidationGroups($form);
56
57 // Validate the data against its own constraints
58 if (self::allowDataWalking($form)) {
59 foreach ($groups as $group) {
60 $this->context->validate($form->getData(), 'data', $group, true);
61 }
62 }
63
64 // Validate the data against the constraints defined
65 // in the form
66 $constraints = $config->getOption('constraints');
67 foreach ($constraints as $constraint) {
68 foreach ($groups as $group) {
69 if (in_array($group, $constraint->groups)) {
70 $this->context->validateValue($form->getData(), $constraint, 'data', $group);
71
72 // Prevent duplicate validation
73 continue 2;
74 }
75 }
76 }
77 } else {
78 $childrenSynchronized = true;
79
80 foreach ($form as $child) {
81 if (!$child->isSynchronized()) {
82 $childrenSynchronized = false;
83 break;
84 }
85 }
86
87 // Mark the form with an error if it is not synchronized BUT all
88 // of its children are synchronized. If any child is not
89 // synchronized, an error is displayed there already and showing
90 // a second error in its parent form is pointless, or worse, may
91 // lead to duplicate errors if error bubbling is enabled on the
92 // child.
93 // See also https://github.com/symfony/symfony/issues/4359
94 if ($childrenSynchronized) {
95 $clientDataAsString = is_scalar($form->getViewData())
96 ? (string) $form->getViewData()
97 : gettype($form->getViewData());
98
99 $this->context->addViolation(
100 $config->getOption('invalid_message'),
101 array_replace(array('{{ value }}' => $clientDataAsString), $config->getOption('invalid_message_parameters')),
102 $form->getViewData(),
103 null,
104 Form::ERR_INVALID
105 );
106 }
107 }
108
109 // Mark the form with an error if it contains extra fields
110 if (count($form->getExtraData()) > 0) {
111 $this->context->addViolation(
112 $config->getOption('extra_fields_message'),
113 array('{{ extra_fields }}' => implode('", "', array_keys($form->getExtraData()))),
114 $form->getExtraData()
115 );
116 }
117
118 // Mark the form with an error if the uploaded size was too large
119 $length = $this->serverParams->getContentLength();
120
121 if ($form->isRoot() && null !== $length) {
122 $max = $this->serverParams->getPostMaxSize();
123
124 if (!empty($max) && $length > $max) {
125 $this->context->addViolation(
126 $config->getOption('post_max_size_message'),
127 array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()),
128 $length
129 );
130 }
131 }
132 }
133
134 /**
135 * Returns whether the data of a form may be walked.
136 *
137 * @param FormInterface $form The form to test.
138 *
139 * @return Boolean Whether the graph walker may walk the data.
140 */
141 private static function allowDataWalking(FormInterface $form)
142 {
143 $data = $form->getData();
144
145 // Scalar values cannot have mapped constraints
146 if (!is_object($data) && !is_array($data)) {
147 return false;
148 }
149
150 // Root forms are always validated
151 if ($form->isRoot()) {
152 return true;
153 }
154
155 // Non-root forms are validated if validation cascading
156 // is enabled in all ancestor forms
157 while (null !== ($form = $form->getParent())) {
158 if (!$form->getConfig()->getOption('cascade_validation')) {
159 return false;
160 }
161 }
162
163 return true;
164 }
165
166 /**
167 * Returns the validation groups of the given form.
168 *
169 * @param FormInterface $form The form.
170 *
171 * @return array The validation groups.
172 */
173 private static function getValidationGroups(FormInterface $form)
174 {
175 $button = self::findClickedButton($form->getRoot());
176
177 if (null !== $button) {
178 $groups = $button->getConfig()->getOption('validation_groups');
179
180 if (null !== $groups) {
181 return self::resolveValidationGroups($groups, $form);
182 }
183 }
184
185 do {
186 $groups = $form->getConfig()->getOption('validation_groups');
187
188 if (null !== $groups) {
189 return self::resolveValidationGroups($groups, $form);
190 }
191
192 $form = $form->getParent();
193 } while (null !== $form);
194
195 return array(Constraint::DEFAULT_GROUP);
196 }
197
198 /**
199 * Extracts a clicked button from a form tree, if one exists.
200 *
201 * @param FormInterface $form The root form.
202 *
203 * @return ClickableInterface|null The clicked button or null.
204 */
205 private static function findClickedButton(FormInterface $form)
206 {
207 if ($form instanceof ClickableInterface && $form->isClicked()) {
208 return $form;
209 }
210
211 foreach ($form as $child) {
212 if (null !== ($button = self::findClickedButton($child))) {
213 return $button;
214 }
215 }
216
217 return null;
218 }
219
220 /**
221 * Post-processes the validation groups option for a given form.
222 *
223 * @param array|callable $groups The validation groups.
224 * @param FormInterface $form The validated form.
225 *
226 * @return array The validation groups.
227 */
228 private static function resolveValidationGroups($groups, FormInterface $form)
229 {
230 if (!is_string($groups) && is_callable($groups)) {
231 $groups = call_user_func($groups, $form);
232 }
233
234 return (array) $groups;
235 }
236}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php
new file mode 100644
index 00000000..14147531
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php
@@ -0,0 +1,68 @@
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\Validator\EventListener;
13
14use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapperInterface;
16use Symfony\Component\Validator\ValidatorInterface;
17use Symfony\Component\Form\FormEvents;
18use Symfony\Component\Form\FormEvent;
19use Symfony\Component\Form\Extension\Validator\Constraints\Form;
20
21/**
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class ValidationListener implements EventSubscriberInterface
25{
26 private $validator;
27
28 private $violationMapper;
29
30 /**
31 * {@inheritdoc}
32 */
33 public static function getSubscribedEvents()
34 {
35 return array(FormEvents::POST_SUBMIT => 'validateForm');
36 }
37
38 public function __construct(ValidatorInterface $validator, ViolationMapperInterface $violationMapper)
39 {
40 $this->validator = $validator;
41 $this->violationMapper = $violationMapper;
42 }
43
44 /**
45 * Validates the form and its domain object.
46 *
47 * @param FormEvent $event The event object
48 */
49 public function validateForm(FormEvent $event)
50 {
51 $form = $event->getForm();
52
53 if ($form->isRoot()) {
54 // Validate the form in group "Default"
55 $violations = $this->validator->validate($form);
56
57 if (count($violations) > 0) {
58 foreach ($violations as $violation) {
59 // Allow the "invalid" constraint to be put onto
60 // non-synchronized forms
61 $allowNonSynchronized = Form::ERR_INVALID === $violation->getCode();
62
63 $this->violationMapper->mapViolation($violation, $form, $allowNonSynchronized);
64 }
65 }
66 }
67 }
68}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/BaseValidatorExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/BaseValidatorExtension.php
new file mode 100644
index 00000000..7c5e6784
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/BaseValidatorExtension.php
@@ -0,0 +1,56 @@
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\Validator\Type;
13
14use Symfony\Component\Form\AbstractTypeExtension;
15use Symfony\Component\OptionsResolver\Options;
16use Symfony\Component\OptionsResolver\OptionsResolverInterface;
17
18/**
19 * Encapsulates common logic of {@link FormTypeValidatorExtension} and
20 * {@link SubmitTypeValidatorExtension}.
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24abstract class BaseValidatorExtension extends AbstractTypeExtension
25{
26 /**
27 * {@inheritdoc}
28 */
29 public function setDefaultOptions(OptionsResolverInterface $resolver)
30 {
31 // Make sure that validation groups end up as null, closure or array
32 $validationGroupsNormalizer = function (Options $options, $groups) {
33 if (false === $groups) {
34 return array();
35 }
36
37 if (empty($groups)) {
38 return null;
39 }
40
41 if (is_callable($groups)) {
42 return $groups;
43 }
44
45 return (array) $groups;
46 };
47
48 $resolver->setDefaults(array(
49 'validation_groups' => null,
50 ));
51
52 $resolver->setNormalizers(array(
53 'validation_groups' => $validationGroupsNormalizer,
54 ));
55 }
56}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php
new file mode 100644
index 00000000..344bddad
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php
@@ -0,0 +1,84 @@
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\Validator\Type;
13
14use Symfony\Component\Form\FormBuilderInterface;
15use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper;
16use Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener;
17use Symfony\Component\Validator\ValidatorInterface;
18use Symfony\Component\OptionsResolver\Options;
19use Symfony\Component\OptionsResolver\OptionsResolverInterface;
20
21/**
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class FormTypeValidatorExtension extends BaseValidatorExtension
25{
26 /**
27 * @var ValidatorInterface
28 */
29 private $validator;
30
31 /**
32 * @var ViolationMapper
33 */
34 private $violationMapper;
35
36 public function __construct(ValidatorInterface $validator)
37 {
38 $this->validator = $validator;
39 $this->violationMapper = new ViolationMapper();
40 }
41
42 /**
43 * {@inheritdoc}
44 */
45 public function buildForm(FormBuilderInterface $builder, array $options)
46 {
47 $builder->addEventSubscriber(new ValidationListener($this->validator, $this->violationMapper));
48 }
49
50 /**
51 * {@inheritdoc}
52 */
53 public function setDefaultOptions(OptionsResolverInterface $resolver)
54 {
55 parent::setDefaultOptions($resolver);
56
57 // Constraint should always be converted to an array
58 $constraintsNormalizer = function (Options $options, $constraints) {
59 return is_object($constraints) ? array($constraints) : (array) $constraints;
60 };
61
62 $resolver->setDefaults(array(
63 'error_mapping' => array(),
64 'constraints' => array(),
65 'cascade_validation' => false,
66 'invalid_message' => 'This value is not valid.',
67 'invalid_message_parameters' => array(),
68 'extra_fields_message' => 'This form should not contain extra fields.',
69 'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.',
70 ));
71
72 $resolver->setNormalizers(array(
73 'constraints' => $constraintsNormalizer,
74 ));
75 }
76
77 /**
78 * {@inheritdoc}
79 */
80 public function getExtendedType()
81 {
82 return 'form';
83 }
84}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/RepeatedTypeValidatorExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/RepeatedTypeValidatorExtension.php
new file mode 100644
index 00000000..858ff0fa
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/RepeatedTypeValidatorExtension.php
@@ -0,0 +1,45 @@
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\Validator\Type;
13
14use Symfony\Component\Form\AbstractTypeExtension;
15use Symfony\Component\OptionsResolver\Options;
16use Symfony\Component\OptionsResolver\OptionsResolverInterface;
17
18/**
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class RepeatedTypeValidatorExtension extends AbstractTypeExtension
22{
23 /**
24 * {@inheritdoc}
25 */
26 public function setDefaultOptions(OptionsResolverInterface $resolver)
27 {
28 // Map errors to the first field
29 $errorMapping = function (Options $options) {
30 return array('.' => $options['first_name']);
31 };
32
33 $resolver->setDefaults(array(
34 'error_mapping' => $errorMapping,
35 ));
36 }
37
38 /**
39 * {@inheritdoc}
40 */
41 public function getExtendedType()
42 {
43 return 'repeated';
44 }
45}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/SubmitTypeValidatorExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/SubmitTypeValidatorExtension.php
new file mode 100644
index 00000000..5aad67fb
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/SubmitTypeValidatorExtension.php
@@ -0,0 +1,28 @@
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\Validator\Type;
13
14use Symfony\Component\Form\AbstractTypeExtension;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class SubmitTypeValidatorExtension extends AbstractTypeExtension
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function getExtendedType()
25 {
26 return 'submit';
27 }
28}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Util/ServerParams.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Util/ServerParams.php
new file mode 100644
index 00000000..fab6ac2a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Util/ServerParams.php
@@ -0,0 +1,64 @@
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\Validator\Util;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17class ServerParams
18{
19 /**
20 * Returns maximum post size in bytes.
21 *
22 * @return null|integer The maximum post size in bytes
23 */
24 public function getPostMaxSize()
25 {
26 $iniMax = $this->getNormalizedIniPostMaxSize();
27
28 if ('' === $iniMax) {
29 return null;
30 }
31
32 if (preg_match('#^\+?(0X?)?(.*?)([KMG]?)$#', $iniMax, $match)) {
33 $shifts = array('' => 0, 'K' => 10, 'M' => 20, 'G' => 30);
34 $bases = array('' => 10, '0' => 8, '0X' => 16);
35
36 return intval($match[2], $bases[$match[1]]) << $shifts[$match[3]];
37 }
38
39 return 0;
40 }
41
42 /**
43 * Returns the normalized "post_max_size" ini setting.
44 *
45 * @return string
46 */
47 public function getNormalizedIniPostMaxSize()
48 {
49 return strtoupper(trim(ini_get('post_max_size')));
50 }
51
52 /**
53 * Returns the content length of the request.
54 *
55 * @return mixed The request content length.
56 */
57 public function getContentLength()
58 {
59 return isset($_SERVER['CONTENT_LENGTH'])
60 ? (int) $_SERVER['CONTENT_LENGTH']
61 : null;
62 }
63
64}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php
new file mode 100644
index 00000000..9cff22a2
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php
@@ -0,0 +1,57 @@
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\Validator;
13
14use Symfony\Component\Form\Extension\Validator\Type;
15use Symfony\Component\Form\Extension\Validator\Constraints\Form;
16use Symfony\Component\Form\AbstractExtension;
17use Symfony\Component\Validator\ValidatorInterface;
18use Symfony\Component\Validator\Constraints\Valid;
19
20/**
21 * Extension supporting the Symfony2 Validator component in forms.
22 *
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25class ValidatorExtension extends AbstractExtension
26{
27 private $validator;
28
29 public function __construct(ValidatorInterface $validator)
30 {
31 $this->validator = $validator;
32
33 // Register the form constraints in the validator programmatically.
34 // This functionality is required when using the Form component without
35 // the DIC, where the XML file is loaded automatically. Thus the following
36 // code must be kept synchronized with validation.xml
37
38 /** @var \Symfony\Component\Validator\Mapping\ClassMetadata $metadata */
39 $metadata = $this->validator->getMetadataFactory()->getMetadataFor('Symfony\Component\Form\Form');
40 $metadata->addConstraint(new Form());
41 $metadata->addPropertyConstraint('children', new Valid());
42 }
43
44 public function loadTypeGuesser()
45 {
46 return new ValidatorTypeGuesser($this->validator->getMetadataFactory());
47 }
48
49 protected function loadTypeExtensions()
50 {
51 return array(
52 new Type\FormTypeValidatorExtension($this->validator),
53 new Type\RepeatedTypeValidatorExtension(),
54 new Type\SubmitTypeValidatorExtension(),
55 );
56 }
57}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php
new file mode 100644
index 00000000..dcd9cc55
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php
@@ -0,0 +1,286 @@
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\Validator;
13
14use Symfony\Component\Form\FormTypeGuesserInterface;
15use Symfony\Component\Form\Guess\Guess;
16use Symfony\Component\Form\Guess\TypeGuess;
17use Symfony\Component\Form\Guess\ValueGuess;
18use Symfony\Component\Validator\MetadataFactoryInterface;
19use Symfony\Component\Validator\Constraint;
20
21class ValidatorTypeGuesser implements FormTypeGuesserInterface
22{
23 private $metadataFactory;
24
25 public function __construct(MetadataFactoryInterface $metadataFactory)
26 {
27 $this->metadataFactory = $metadataFactory;
28 }
29
30 /**
31 * {@inheritDoc}
32 */
33 public function guessType($class, $property)
34 {
35 $guesser = $this;
36
37 return $this->guess($class, $property, function (Constraint $constraint) use ($guesser) {
38 return $guesser->guessTypeForConstraint($constraint);
39 });
40 }
41
42 /**
43 * {@inheritDoc}
44 */
45 public function guessRequired($class, $property)
46 {
47 $guesser = $this;
48
49 return $this->guess($class, $property, function (Constraint $constraint) use ($guesser) {
50 return $guesser->guessRequiredForConstraint($constraint);
51 // If we don't find any constraint telling otherwise, we can assume
52 // that a field is not required (with LOW_CONFIDENCE)
53 }, false);
54 }
55
56 /**
57 * {@inheritDoc}
58 */
59 public function guessMaxLength($class, $property)
60 {
61 $guesser = $this;
62
63 return $this->guess($class, $property, function (Constraint $constraint) use ($guesser) {
64 return $guesser->guessMaxLengthForConstraint($constraint);
65 });
66 }
67
68 /**
69 * {@inheritDoc}
70 */
71 public function guessPattern($class, $property)
72 {
73 $guesser = $this;
74
75 return $this->guess($class, $property, function (Constraint $constraint) use ($guesser) {
76 return $guesser->guessPatternForConstraint($constraint);
77 });
78 }
79
80 /**
81 * Guesses a field class name for a given constraint
82 *
83 * @param Constraint $constraint The constraint to guess for
84 *
85 * @return TypeGuess The guessed field class and options
86 */
87 public function guessTypeForConstraint(Constraint $constraint)
88 {
89 switch (get_class($constraint)) {
90 case 'Symfony\Component\Validator\Constraints\Type':
91 switch ($constraint->type) {
92 case 'array':
93 return new TypeGuess('collection', array(), Guess::MEDIUM_CONFIDENCE);
94 case 'boolean':
95 case 'bool':
96 return new TypeGuess('checkbox', array(), Guess::MEDIUM_CONFIDENCE);
97
98 case 'double':
99 case 'float':
100 case 'numeric':
101 case 'real':
102 return new TypeGuess('number', array(), Guess::MEDIUM_CONFIDENCE);
103
104 case 'integer':
105 case 'int':
106 case 'long':
107 return new TypeGuess('integer', array(), Guess::MEDIUM_CONFIDENCE);
108
109 case '\DateTime':
110 return new TypeGuess('date', array(), Guess::MEDIUM_CONFIDENCE);
111
112 case 'string':
113 return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE);
114 }
115 break;
116
117 case 'Symfony\Component\Validator\Constraints\Country':
118 return new TypeGuess('country', array(), Guess::HIGH_CONFIDENCE);
119
120 case 'Symfony\Component\Validator\Constraints\Date':
121 return new TypeGuess('date', array('input' => 'string'), Guess::HIGH_CONFIDENCE);
122
123 case 'Symfony\Component\Validator\Constraints\DateTime':
124 return new TypeGuess('datetime', array('input' => 'string'), Guess::HIGH_CONFIDENCE);
125
126 case 'Symfony\Component\Validator\Constraints\Email':
127 return new TypeGuess('email', array(), Guess::HIGH_CONFIDENCE);
128
129 case 'Symfony\Component\Validator\Constraints\File':
130 case 'Symfony\Component\Validator\Constraints\Image':
131 return new TypeGuess('file', array(), Guess::HIGH_CONFIDENCE);
132
133 case 'Symfony\Component\Validator\Constraints\Language':
134 return new TypeGuess('language', array(), Guess::HIGH_CONFIDENCE);
135
136 case 'Symfony\Component\Validator\Constraints\Locale':
137 return new TypeGuess('locale', array(), Guess::HIGH_CONFIDENCE);
138
139 case 'Symfony\Component\Validator\Constraints\Time':
140 return new TypeGuess('time', array('input' => 'string'), Guess::HIGH_CONFIDENCE);
141
142 case 'Symfony\Component\Validator\Constraints\Url':
143 return new TypeGuess('url', array(), Guess::HIGH_CONFIDENCE);
144
145 case 'Symfony\Component\Validator\Constraints\Ip':
146 return new TypeGuess('text', array(), Guess::MEDIUM_CONFIDENCE);
147
148 case 'Symfony\Component\Validator\Constraints\MaxLength':
149 case 'Symfony\Component\Validator\Constraints\MinLength':
150 case 'Symfony\Component\Validator\Constraints\Regex':
151 return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE);
152
153 case 'Symfony\Component\Validator\Constraints\Min':
154 case 'Symfony\Component\Validator\Constraints\Max':
155 return new TypeGuess('number', array(), Guess::LOW_CONFIDENCE);
156
157 case 'Symfony\Component\Validator\Constraints\MinCount':
158 case 'Symfony\Component\Validator\Constraints\MaxCount':
159 return new TypeGuess('collection', array(), Guess::LOW_CONFIDENCE);
160
161 case 'Symfony\Component\Validator\Constraints\True':
162 case 'Symfony\Component\Validator\Constraints\False':
163 return new TypeGuess('checkbox', array(), Guess::MEDIUM_CONFIDENCE);
164 }
165
166 return null;
167 }
168
169 /**
170 * Guesses whether a field is required based on the given constraint
171 *
172 * @param Constraint $constraint The constraint to guess for
173 *
174 * @return Guess The guess whether the field is required
175 */
176 public function guessRequiredForConstraint(Constraint $constraint)
177 {
178 switch (get_class($constraint)) {
179 case 'Symfony\Component\Validator\Constraints\NotNull':
180 case 'Symfony\Component\Validator\Constraints\NotBlank':
181 case 'Symfony\Component\Validator\Constraints\True':
182 return new ValueGuess(true, Guess::HIGH_CONFIDENCE);
183 }
184
185 return null;
186 }
187
188 /**
189 * Guesses a field's maximum length based on the given constraint
190 *
191 * @param Constraint $constraint The constraint to guess for
192 *
193 * @return Guess The guess for the maximum length
194 */
195 public function guessMaxLengthForConstraint(Constraint $constraint)
196 {
197 switch (get_class($constraint)) {
198 case 'Symfony\Component\Validator\Constraints\MaxLength':
199 return new ValueGuess($constraint->limit, Guess::HIGH_CONFIDENCE);
200
201 case 'Symfony\Component\Validator\Constraints\Type':
202 if (in_array($constraint->type, array('double', 'float', 'numeric', 'real'))) {
203 return new ValueGuess(null, Guess::MEDIUM_CONFIDENCE);
204 }
205 break;
206
207 case 'Symfony\Component\Validator\Constraints\Max':
208 return new ValueGuess(strlen((string) $constraint->limit), Guess::LOW_CONFIDENCE);
209 }
210
211 return null;
212 }
213
214 /**
215 * Guesses a field's pattern based on the given constraint
216 *
217 * @param Constraint $constraint The constraint to guess for
218 *
219 * @return Guess The guess for the pattern
220 */
221 public function guessPatternForConstraint(Constraint $constraint)
222 {
223 switch (get_class($constraint)) {
224 case 'Symfony\Component\Validator\Constraints\MinLength':
225 return new ValueGuess(sprintf('.{%s,}', (string) $constraint->limit), Guess::LOW_CONFIDENCE);
226
227 case 'Symfony\Component\Validator\Constraints\Regex':
228 $htmlPattern = $constraint->getHtmlPattern();
229
230 if (null !== $htmlPattern) {
231 return new ValueGuess($htmlPattern, Guess::HIGH_CONFIDENCE);
232 }
233 break;
234
235 case 'Symfony\Component\Validator\Constraints\Min':
236 return new ValueGuess(sprintf('.{%s,}', strlen((string) $constraint->limit)), Guess::LOW_CONFIDENCE);
237
238 case 'Symfony\Component\Validator\Constraints\Type':
239 if (in_array($constraint->type, array('double', 'float', 'numeric', 'real'))) {
240 return new ValueGuess(null, Guess::MEDIUM_CONFIDENCE);
241 }
242 break;
243 }
244
245 return null;
246 }
247
248 /**
249 * Iterates over the constraints of a property, executes a constraints on
250 * them and returns the best guess
251 *
252 * @param string $class The class to read the constraints from
253 * @param string $property The property for which to find constraints
254 * @param \Closure $closure The closure that returns a guess
255 * for a given constraint
256 * @param mixed $defaultValue The default value assumed if no other value
257 * can be guessed.
258 *
259 * @return Guess The guessed value with the highest confidence
260 */
261 protected function guess($class, $property, \Closure $closure, $defaultValue = null)
262 {
263 $guesses = array();
264 $classMetadata = $this->metadataFactory->getMetadataFor($class);
265
266 if ($classMetadata->hasMemberMetadatas($property)) {
267 $memberMetadatas = $classMetadata->getMemberMetadatas($property);
268
269 foreach ($memberMetadatas as $memberMetadata) {
270 $constraints = $memberMetadata->getConstraints();
271
272 foreach ($constraints as $constraint) {
273 if ($guess = $closure($constraint)) {
274 $guesses[] = $guess;
275 }
276 }
277 }
278
279 if (null !== $defaultValue) {
280 $guesses[] = new ValueGuess($defaultValue, Guess::LOW_CONFIDENCE);
281 }
282 }
283
284 return Guess::getBestGuess($guesses);
285 }
286}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php
new file mode 100644
index 00000000..7b96efb4
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php
@@ -0,0 +1,106 @@
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\Validator\ViolationMapper;
13
14use Symfony\Component\Form\FormInterface;
15use Symfony\Component\Form\Exception\ErrorMappingException;
16
17/**
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20class MappingRule
21{
22 /**
23 * @var FormInterface
24 */
25 private $origin;
26
27 /**
28 * @var string
29 */
30 private $propertyPath;
31
32 /**
33 * @var string
34 */
35 private $targetPath;
36
37 public function __construct(FormInterface $origin, $propertyPath, $targetPath)
38 {
39 $this->origin = $origin;
40 $this->propertyPath = $propertyPath;
41 $this->targetPath = $targetPath;
42 }
43
44 /**
45 * @return FormInterface
46 */
47 public function getOrigin()
48 {
49 return $this->origin;
50 }
51
52 /**
53 * Matches a property path against the rule path.
54 *
55 * If the rule matches, the form mapped by the rule is returned.
56 * Otherwise this method returns false.
57 *
58 * @param string $propertyPath The property path to match against the rule.
59 *
60 * @return null|FormInterface The mapped form or null.
61 */
62 public function match($propertyPath)
63 {
64 if ($propertyPath === (string) $this->propertyPath) {
65 return $this->getTarget();
66 }
67
68 return null;
69 }
70
71 /**
72 * Matches a property path against a prefix of the rule path.
73 *
74 * @param string $propertyPath The property path to match against the rule.
75 *
76 * @return Boolean Whether the property path is a prefix of the rule or not.
77 */
78 public function isPrefix($propertyPath)
79 {
80 $length = strlen($propertyPath);
81 $prefix = substr($this->propertyPath, 0, $length);
82 $next = isset($this->propertyPath[$length]) ? $this->propertyPath[$length] : null;
83
84 return $prefix === $propertyPath && ('[' === $next || '.' === $next);
85 }
86
87 /**
88 * @return FormInterface
89 *
90 * @throws ErrorMappingException
91 */
92 public function getTarget()
93 {
94 $childNames = explode('.', $this->targetPath);
95 $target = $this->origin;
96
97 foreach ($childNames as $childName) {
98 if (!$target->has($childName)) {
99 throw new ErrorMappingException(sprintf('The child "%s" of "%s" mapped by the rule "%s" in "%s" does not exist.', $childName, $target->getName(), $this->targetPath, $this->origin->getName()));
100 }
101 $target = $target->get($childName);
102 }
103
104 return $target;
105 }
106}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/RelativePath.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/RelativePath.php
new file mode 100644
index 00000000..ef5c9fad
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/RelativePath.php
@@ -0,0 +1,45 @@
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\Validator\ViolationMapper;
13
14use Symfony\Component\Form\FormInterface;
15use Symfony\Component\PropertyAccess\PropertyPath;
16
17/**
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20class RelativePath extends PropertyPath
21{
22 /**
23 * @var FormInterface
24 */
25 private $root;
26
27 /**
28 * @param FormInterface $root
29 * @param string $propertyPath
30 */
31 public function __construct(FormInterface $root, $propertyPath)
32 {
33 parent::__construct($propertyPath);
34
35 $this->root = $root;
36 }
37
38 /**
39 * @return FormInterface
40 */
41 public function getRoot()
42 {
43 return $this->root;
44 }
45}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php
new file mode 100644
index 00000000..8a7636c7
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php
@@ -0,0 +1,299 @@
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\Validator\ViolationMapper;
13
14use Symfony\Component\Form\FormInterface;
15use Symfony\Component\Form\Util\InheritDataAwareIterator;
16use Symfony\Component\PropertyAccess\PropertyPathIterator;
17use Symfony\Component\PropertyAccess\PropertyPathBuilder;
18use Symfony\Component\PropertyAccess\PropertyPathIteratorInterface;
19use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationPathIterator;
20use Symfony\Component\Form\FormError;
21use Symfony\Component\Validator\ConstraintViolation;
22
23/**
24 * @author Bernhard Schussek <bschussek@gmail.com>
25 */
26class ViolationMapper implements ViolationMapperInterface
27{
28 /**
29 * @var Boolean
30 */
31 private $allowNonSynchronized;
32
33 /**
34 * {@inheritdoc}
35 */
36 public function mapViolation(ConstraintViolation $violation, FormInterface $form, $allowNonSynchronized = false)
37 {
38 $this->allowNonSynchronized = $allowNonSynchronized;
39
40 // The scope is the currently found most specific form that
41 // an error should be mapped to. After setting the scope, the
42 // mapper will try to continue to find more specific matches in
43 // the children of scope. If it cannot, the error will be
44 // mapped to this scope.
45 $scope = null;
46
47 $violationPath = null;
48 $relativePath = null;
49 $match = false;
50
51 // Don't create a ViolationPath instance for empty property paths
52 if (strlen($violation->getPropertyPath()) > 0) {
53 $violationPath = new ViolationPath($violation->getPropertyPath());
54 $relativePath = $this->reconstructPath($violationPath, $form);
55 }
56
57 // This case happens if the violation path is empty and thus
58 // the violation should be mapped to the root form
59 if (null === $violationPath) {
60 $scope = $form;
61 }
62
63 // In general, mapping happens from the root form to the leaf forms
64 // First, the rules of the root form are applied to determine
65 // the subsequent descendant. The rules of this descendant are then
66 // applied to find the next and so on, until we have found the
67 // most specific form that matches the violation.
68
69 // If any of the forms found in this process is not synchronized,
70 // mapping is aborted. Non-synchronized forms could not reverse
71 // transform the value entered by the user, thus any further violations
72 // caused by the (invalid) reverse transformed value should be
73 // ignored.
74
75 if (null !== $relativePath) {
76 // Set the scope to the root of the relative path
77 // This root will usually be $form. If the path contains
78 // an unmapped form though, the last unmapped form found
79 // will be the root of the path.
80 $scope = $relativePath->getRoot();
81 $it = new PropertyPathIterator($relativePath);
82
83 while ($this->acceptsErrors($scope) && null !== ($child = $this->matchChild($scope, $it))) {
84 $scope = $child;
85 $it->next();
86 $match = true;
87 }
88 }
89
90 // This case happens if an error happened in the data under a
91 // form inheriting its parent data that does not match any of the
92 // children of that form.
93 if (null !== $violationPath && !$match) {
94 // If we could not map the error to anything more specific
95 // than the root element, map it to the innermost directly
96 // mapped form of the violation path
97 // e.g. "children[foo].children[bar].data.baz"
98 // Here the innermost directly mapped child is "bar"
99
100 $scope = $form;
101 $it = new ViolationPathIterator($violationPath);
102
103 // Note: acceptsErrors() will always return true for forms inheriting
104 // their parent data, because these forms can never be non-synchronized
105 // (they don't do any data transformation on their own)
106 while ($this->acceptsErrors($scope) && $it->valid() && $it->mapsForm()) {
107 if (!$scope->has($it->current())) {
108 // Break if we find a reference to a non-existing child
109 break;
110 }
111
112 $scope = $scope->get($it->current());
113 $it->next();
114 }
115 }
116
117 // Follow dot rules until we have the final target
118 $mapping = $scope->getConfig()->getOption('error_mapping');
119
120 while ($this->acceptsErrors($scope) && isset($mapping['.'])) {
121 $dotRule = new MappingRule($scope, '.', $mapping['.']);
122 $scope = $dotRule->getTarget();
123 $mapping = $scope->getConfig()->getOption('error_mapping');
124 }
125
126 // Only add the error if the form is synchronized
127 if ($this->acceptsErrors($scope)) {
128 $scope->addError(new FormError(
129 $violation->getMessage(),
130 $violation->getMessageTemplate(),
131 $violation->getMessageParameters(),
132 $violation->getMessagePluralization()
133 ));
134 }
135 }
136
137 /**
138 * Tries to match the beginning of the property path at the
139 * current position against the children of the scope.
140 *
141 * If a matching child is found, it is returned. Otherwise
142 * null is returned.
143 *
144 * @param FormInterface $form The form to search.
145 * @param PropertyPathIteratorInterface $it The iterator at its current position.
146 *
147 * @return null|FormInterface The found match or null.
148 */
149 private function matchChild(FormInterface $form, PropertyPathIteratorInterface $it)
150 {
151 // Remember at what property path underneath "data"
152 // we are looking. Check if there is a child with that
153 // path, otherwise increase path by one more piece
154 $chunk = '';
155 $foundChild = null;
156 $foundAtIndex = 0;
157
158 // Construct mapping rules for the given form
159 $rules = array();
160
161 foreach ($form->getConfig()->getOption('error_mapping') as $propertyPath => $targetPath) {
162 // Dot rules are considered at the very end
163 if ('.' !== $propertyPath) {
164 $rules[] = new MappingRule($form, $propertyPath, $targetPath);
165 }
166 }
167
168 // Skip forms inheriting their parent data when iterating the children
169 $childIterator = new \RecursiveIteratorIterator(
170 new InheritDataAwareIterator($form->all())
171 );
172
173 // Make the path longer until we find a matching child
174 while (true) {
175 if (!$it->valid()) {
176 return null;
177 }
178
179 if ($it->isIndex()) {
180 $chunk .= '['.$it->current().']';
181 } else {
182 $chunk .= ('' === $chunk ? '' : '.').$it->current();
183 }
184
185 // Test mapping rules as long as we have any
186 foreach ($rules as $key => $rule) {
187 /* @var MappingRule $rule */
188
189 // Mapping rule matches completely, terminate.
190 if (null !== ($form = $rule->match($chunk))) {
191 return $form;
192 }
193
194 // Keep only rules that have $chunk as prefix
195 if (!$rule->isPrefix($chunk)) {
196 unset($rules[$key]);
197 }
198 }
199
200 // Test children unless we already found one
201 if (null === $foundChild) {
202 foreach ($childIterator as $child) {
203 /* @var FormInterface $child */
204 $childPath = (string) $child->getPropertyPath();
205
206 // Child found, mark as return value
207 if ($chunk === $childPath) {
208 $foundChild = $child;
209 $foundAtIndex = $it->key();
210 }
211 }
212 }
213
214 // Add element to the chunk
215 $it->next();
216
217 // If we reached the end of the path or if there are no
218 // more matching mapping rules, return the found child
219 if (null !== $foundChild && (!$it->valid() || count($rules) === 0)) {
220 // Reset index in case we tried to find mapping
221 // rules further down the path
222 $it->seek($foundAtIndex);
223
224 return $foundChild;
225 }
226 }
227
228 return null;
229 }
230
231 /**
232 * Reconstructs a property path from a violation path and a form tree.
233 *
234 * @param ViolationPath $violationPath The violation path.
235 * @param FormInterface $origin The root form of the tree.
236 *
237 * @return RelativePath The reconstructed path.
238 */
239 private function reconstructPath(ViolationPath $violationPath, FormInterface $origin)
240 {
241 $propertyPathBuilder = new PropertyPathBuilder($violationPath);
242 $it = $violationPath->getIterator();
243 $scope = $origin;
244
245 // Remember the current index in the builder
246 $i = 0;
247
248 // Expand elements that map to a form (like "children[address]")
249 for ($it->rewind(); $it->valid() && $it->mapsForm(); $it->next()) {
250 if (!$scope->has($it->current())) {
251 // Scope relates to a form that does not exist
252 // Bail out
253 break;
254 }
255
256 // Process child form
257 $scope = $scope->get($it->current());
258
259 if ($scope->getConfig()->getInheritData()) {
260 // Form inherits its parent data
261 // Cut the piece out of the property path and proceed
262 $propertyPathBuilder->remove($i);
263 } elseif (!$scope->getConfig()->getMapped()) {
264 // Form is not mapped
265 // Set the form as new origin and strip everything
266 // we have so far in the path
267 $origin = $scope;
268 $propertyPathBuilder->remove(0, $i + 1);
269 $i = 0;
270 } else {
271 /* @var \Symfony\Component\PropertyAccess\PropertyPathInterface $propertyPath */
272 $propertyPath = $scope->getPropertyPath();
273
274 if (null === $propertyPath) {
275 // Property path of a mapped form is null
276 // Should not happen, bail out
277 break;
278 }
279
280 $propertyPathBuilder->replace($i, 1, $propertyPath);
281 $i += $propertyPath->getLength();
282 }
283 }
284
285 $finalPath = $propertyPathBuilder->getPropertyPath();
286
287 return null !== $finalPath ? new RelativePath($origin, $finalPath) : null;
288 }
289
290 /**
291 * @param FormInterface $form
292 *
293 * @return Boolean
294 */
295 private function acceptsErrors(FormInterface $form)
296 {
297 return $this->allowNonSynchronized || $form->isSynchronized();
298 }
299}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapperInterface.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapperInterface.php
new file mode 100644
index 00000000..eb8907f1
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapperInterface.php
@@ -0,0 +1,33 @@
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\Validator\ViolationMapper;
13
14use Symfony\Component\Form\FormInterface;
15use Symfony\Component\Validator\ConstraintViolation;
16
17/**
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20interface ViolationMapperInterface
21{
22 /**
23 * Maps a constraint violation to a form in the form tree under
24 * the given form.
25 *
26 * @param ConstraintViolation $violation The violation to map.
27 * @param FormInterface $form The root form of the tree
28 * to map it to.
29 * @param Boolean $allowNonSynchronized Whether to allow
30 * mapping to non-synchronized forms.
31 */
32 public function mapViolation(ConstraintViolation $violation, FormInterface $form, $allowNonSynchronized = false);
33}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPath.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPath.php
new file mode 100644
index 00000000..06d09195
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPath.php
@@ -0,0 +1,250 @@
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\Validator\ViolationMapper;
13
14use Symfony\Component\Form\Exception\OutOfBoundsException;
15use Symfony\Component\PropertyAccess\PropertyPath;
16use Symfony\Component\PropertyAccess\PropertyPathInterface;
17
18/**
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class ViolationPath implements \IteratorAggregate, PropertyPathInterface
22{
23 /**
24 * @var array
25 */
26 private $elements = array();
27
28 /**
29 * @var array
30 */
31 private $isIndex = array();
32
33 /**
34 * @var array
35 */
36 private $mapsForm = array();
37
38 /**
39 * @var string
40 */
41 private $pathAsString = '';
42
43 /**
44 * @var integer
45 */
46 private $length = 0;
47
48 /**
49 * Creates a new violation path from a string.
50 *
51 * @param string $violationPath The property path of a {@link ConstraintViolation}
52 * object.
53 */
54 public function __construct($violationPath)
55 {
56 $path = new PropertyPath($violationPath);
57 $elements = $path->getElements();
58 $data = false;
59
60 for ($i = 0, $l = count($elements); $i < $l; ++$i) {
61 if (!$data) {
62 // The element "data" has not yet been passed
63 if ('children' === $elements[$i] && $path->isProperty($i)) {
64 // Skip element "children"
65 ++$i;
66
67 // Next element must exist and must be an index
68 // Otherwise consider this the end of the path
69 if ($i >= $l || !$path->isIndex($i)) {
70 break;
71 }
72
73 $this->elements[] = $elements[$i];
74 $this->isIndex[] = true;
75 $this->mapsForm[] = true;
76 } elseif ('data' === $elements[$i] && $path->isProperty($i)) {
77 // Skip element "data"
78 ++$i;
79
80 // End of path
81 if ($i >= $l) {
82 break;
83 }
84
85 $this->elements[] = $elements[$i];
86 $this->isIndex[] = $path->isIndex($i);
87 $this->mapsForm[] = false;
88 $data = true;
89 } else {
90 // Neither "children" nor "data" property found
91 // Consider this the end of the path
92 break;
93 }
94 } else {
95 // Already after the "data" element
96 // Pick everything as is
97 $this->elements[] = $elements[$i];
98 $this->isIndex[] = $path->isIndex($i);
99 $this->mapsForm[] = false;
100 }
101 }
102
103 $this->length = count($this->elements);
104
105 $this->buildString();
106 }
107
108 /**
109 * {@inheritdoc}
110 */
111 public function __toString()
112 {
113 return $this->pathAsString;
114 }
115
116 /**
117 * {@inheritdoc}
118 */
119 public function getLength()
120 {
121 return $this->length;
122 }
123
124 /**
125 * {@inheritdoc}
126 */
127 public function getParent()
128 {
129 if ($this->length <= 1) {
130 return null;
131 }
132
133 $parent = clone $this;
134
135 --$parent->length;
136 array_pop($parent->elements);
137 array_pop($parent->isIndex);
138 array_pop($parent->mapsForm);
139
140 $parent->buildString();
141
142 return $parent;
143 }
144
145 /**
146 * {@inheritdoc}
147 */
148 public function getElements()
149 {
150 return $this->elements;
151 }
152
153 /**
154 * {@inheritdoc}
155 */
156 public function getElement($index)
157 {
158 if (!isset($this->elements[$index])) {
159 throw new OutOfBoundsException(sprintf('The index %s is not within the violation path', $index));
160 }
161
162 return $this->elements[$index];
163 }
164
165 /**
166 * {@inheritdoc}
167 */
168 public function isProperty($index)
169 {
170 if (!isset($this->isIndex[$index])) {
171 throw new OutOfBoundsException(sprintf('The index %s is not within the violation path', $index));
172 }
173
174 return !$this->isIndex[$index];
175 }
176
177 /**
178 * {@inheritdoc}
179 */
180 public function isIndex($index)
181 {
182 if (!isset($this->isIndex[$index])) {
183 throw new OutOfBoundsException(sprintf('The index %s is not within the violation path', $index));
184 }
185
186 return $this->isIndex[$index];
187 }
188
189 /**
190 * Returns whether an element maps directly to a form.
191 *
192 * Consider the following violation path:
193 *
194 * <code>
195 * children[address].children[office].data.street
196 * </code>
197 *
198 * In this example, "address" and "office" map to forms, while
199 * "street does not.
200 *
201 * @param integer $index The element index.
202 *
203 * @return Boolean Whether the element maps to a form.
204 *
205 * @throws OutOfBoundsException If the offset is invalid.
206 */
207 public function mapsForm($index)
208 {
209 if (!isset($this->mapsForm[$index])) {
210 throw new OutOfBoundsException(sprintf('The index %s is not within the violation path', $index));
211 }
212
213 return $this->mapsForm[$index];
214 }
215
216 /**
217 * Returns a new iterator for this path
218 *
219 * @return ViolationPathIterator
220 */
221 public function getIterator()
222 {
223 return new ViolationPathIterator($this);
224 }
225
226 /**
227 * Builds the string representation from the elements.
228 */
229 private function buildString()
230 {
231 $this->pathAsString = '';
232 $data = false;
233
234 foreach ($this->elements as $index => $element) {
235 if ($this->mapsForm[$index]) {
236 $this->pathAsString .= ".children[$element]";
237 } elseif (!$data) {
238 $this->pathAsString .= '.data'.($this->isIndex[$index] ? "[$element]" : ".$element");
239 $data = true;
240 } else {
241 $this->pathAsString .= $this->isIndex[$index] ? "[$element]" : ".$element";
242 }
243 }
244
245 if ('' !== $this->pathAsString) {
246 // remove leading dot
247 $this->pathAsString = substr($this->pathAsString, 1);
248 }
249 }
250}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPathIterator.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPathIterator.php
new file mode 100644
index 00000000..50baa453
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPathIterator.php
@@ -0,0 +1,30 @@
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\Validator\ViolationMapper;
13
14use Symfony\Component\PropertyAccess\PropertyPathIterator;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class ViolationPathIterator extends PropertyPathIterator
20{
21 public function __construct(ViolationPath $violationPath)
22 {
23 parent::__construct($violationPath);
24 }
25
26 public function mapsForm()
27 {
28 return $this->path->mapsForm($this->key());
29 }
30}