]> git.immae.eu Git - github/wallabag/wallabag.git/blob - vendor/symfony/form/Symfony/Component/Form/FormConfigBuilder.php
1015da4f51829b64e999679240aa117b4b4fea0c
[github/wallabag/wallabag.git] / vendor / symfony / form / Symfony / Component / Form / FormConfigBuilder.php
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
12 namespace Symfony\Component\Form;
13
14 use Symfony\Component\Form\Exception\BadMethodCallException;
15 use Symfony\Component\Form\Exception\InvalidArgumentException;
16 use Symfony\Component\Form\Exception\UnexpectedTypeException;
17 use Symfony\Component\PropertyAccess\PropertyPath;
18 use Symfony\Component\PropertyAccess\PropertyPathInterface;
19 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
20 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
21 use Symfony\Component\EventDispatcher\ImmutableEventDispatcher;
22
23 /**
24 * A basic form configuration.
25 *
26 * @author Bernhard Schussek <bschussek@gmail.com>
27 */
28 class FormConfigBuilder implements FormConfigBuilderInterface
29 {
30 /**
31 * Caches a globally unique {@link NativeRequestHandler} instance.
32 *
33 * @var NativeRequestHandler
34 */
35 private static $nativeRequestProcessor;
36
37 /**
38 * The accepted request methods.
39 *
40 * @var array
41 */
42 private static $allowedMethods = array(
43 'GET',
44 'PUT',
45 'POST',
46 'DELETE',
47 'PATCH'
48 );
49
50 /**
51 * @var Boolean
52 */
53 protected $locked = false;
54
55 /**
56 * @var EventDispatcherInterface
57 */
58 private $dispatcher;
59
60 /**
61 * @var string
62 */
63 private $name;
64
65 /**
66 * @var PropertyPathInterface
67 */
68 private $propertyPath;
69
70 /**
71 * @var Boolean
72 */
73 private $mapped = true;
74
75 /**
76 * @var Boolean
77 */
78 private $byReference = true;
79
80 /**
81 * @var Boolean
82 */
83 private $inheritData = false;
84
85 /**
86 * @var Boolean
87 */
88 private $compound = false;
89
90 /**
91 * @var ResolvedFormTypeInterface
92 */
93 private $type;
94
95 /**
96 * @var array
97 */
98 private $viewTransformers = array();
99
100 /**
101 * @var array
102 */
103 private $modelTransformers = array();
104
105 /**
106 * @var DataMapperInterface
107 */
108 private $dataMapper;
109
110 /**
111 * @var Boolean
112 */
113 private $required = true;
114
115 /**
116 * @var Boolean
117 */
118 private $disabled = false;
119
120 /**
121 * @var Boolean
122 */
123 private $errorBubbling = false;
124
125 /**
126 * @var mixed
127 */
128 private $emptyData;
129
130 /**
131 * @var array
132 */
133 private $attributes = array();
134
135 /**
136 * @var mixed
137 */
138 private $data;
139
140 /**
141 * @var string
142 */
143 private $dataClass;
144
145 /**
146 * @var Boolean
147 */
148 private $dataLocked;
149
150 /**
151 * @var FormFactoryInterface
152 */
153 private $formFactory;
154
155 /**
156 * @var string
157 */
158 private $action;
159
160 /**
161 * @var string
162 */
163 private $method = 'POST';
164
165 /**
166 * @var RequestHandlerInterface
167 */
168 private $requestHandler;
169
170 /**
171 * @var Boolean
172 */
173 private $autoInitialize = false;
174
175 /**
176 * @var array
177 */
178 private $options;
179
180 /**
181 * Creates an empty form configuration.
182 *
183 * @param string|integer $name The form name
184 * @param string $dataClass The class of the form's data
185 * @param EventDispatcherInterface $dispatcher The event dispatcher
186 * @param array $options The form options
187 *
188 * @throws InvalidArgumentException If the data class is not a valid class or if
189 * the name contains invalid characters.
190 */
191 public function __construct($name, $dataClass, EventDispatcherInterface $dispatcher, array $options = array())
192 {
193 self::validateName($name);
194
195 if (null !== $dataClass && !class_exists($dataClass)) {
196 throw new InvalidArgumentException(sprintf('The data class "%s" is not a valid class.', $dataClass));
197 }
198
199 $this->name = (string) $name;
200 $this->dataClass = $dataClass;
201 $this->dispatcher = $dispatcher;
202 $this->options = $options;
203 }
204
205 /**
206 * {@inheritdoc}
207 */
208 public function addEventListener($eventName, $listener, $priority = 0)
209 {
210 if ($this->locked) {
211 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
212 }
213
214 $this->dispatcher->addListener($eventName, $listener, $priority);
215
216 return $this;
217 }
218
219 /**
220 * {@inheritdoc}
221 */
222 public function addEventSubscriber(EventSubscriberInterface $subscriber)
223 {
224 if ($this->locked) {
225 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
226 }
227
228 $this->dispatcher->addSubscriber($subscriber);
229
230 return $this;
231 }
232
233 /**
234 * {@inheritdoc}
235 */
236 public function addViewTransformer(DataTransformerInterface $viewTransformer, $forcePrepend = false)
237 {
238 if ($this->locked) {
239 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
240 }
241
242 if ($forcePrepend) {
243 array_unshift($this->viewTransformers, $viewTransformer);
244 } else {
245 $this->viewTransformers[] = $viewTransformer;
246 }
247
248 return $this;
249 }
250
251 /**
252 * {@inheritdoc}
253 */
254 public function resetViewTransformers()
255 {
256 if ($this->locked) {
257 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
258 }
259
260 $this->viewTransformers = array();
261
262 return $this;
263 }
264
265 /**
266 * {@inheritdoc}
267 */
268 public function addModelTransformer(DataTransformerInterface $modelTransformer, $forceAppend = false)
269 {
270 if ($this->locked) {
271 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
272 }
273
274 if ($forceAppend) {
275 $this->modelTransformers[] = $modelTransformer;
276 } else {
277 array_unshift($this->modelTransformers, $modelTransformer);
278 }
279
280 return $this;
281 }
282
283 /**
284 * {@inheritdoc}
285 */
286 public function resetModelTransformers()
287 {
288 if ($this->locked) {
289 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
290 }
291
292 $this->modelTransformers = array();
293
294 return $this;
295 }
296
297 /**
298 * {@inheritdoc}
299 */
300 public function getEventDispatcher()
301 {
302 if ($this->locked && !$this->dispatcher instanceof ImmutableEventDispatcher) {
303 $this->dispatcher = new ImmutableEventDispatcher($this->dispatcher);
304 }
305
306 return $this->dispatcher;
307 }
308
309 /**
310 * {@inheritdoc}
311 */
312 public function getName()
313 {
314 return $this->name;
315 }
316
317 /**
318 * {@inheritdoc}
319 */
320 public function getPropertyPath()
321 {
322 return $this->propertyPath;
323 }
324
325 /**
326 * {@inheritdoc}
327 */
328 public function getMapped()
329 {
330 return $this->mapped;
331 }
332
333 /**
334 * {@inheritdoc}
335 */
336 public function getByReference()
337 {
338 return $this->byReference;
339 }
340
341 /**
342 * {@inheritdoc}
343 */
344 public function getInheritData()
345 {
346 return $this->inheritData;
347 }
348
349 /**
350 * Alias of {@link getInheritData()}.
351 *
352 * @return FormConfigBuilder The configuration object.
353 *
354 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
355 * {@link getInheritData()} instead.
356 */
357 public function getVirtual()
358 {
359 // Uncomment this as soon as the deprecation note should be shown
360 // trigger_error('getVirtual() is deprecated since version 2.3 and will be removed in 3.0. Use getInheritData() instead.', E_USER_DEPRECATED);
361 return $this->getInheritData();
362 }
363
364 /**
365 * {@inheritdoc}
366 */
367 public function getCompound()
368 {
369 return $this->compound;
370 }
371
372 /**
373 * {@inheritdoc}
374 */
375 public function getType()
376 {
377 return $this->type;
378 }
379
380 /**
381 * {@inheritdoc}
382 */
383 public function getViewTransformers()
384 {
385 return $this->viewTransformers;
386 }
387
388 /**
389 * {@inheritdoc}
390 */
391 public function getModelTransformers()
392 {
393 return $this->modelTransformers;
394 }
395
396 /**
397 * {@inheritdoc}
398 */
399 public function getDataMapper()
400 {
401 return $this->dataMapper;
402 }
403
404 /**
405 * {@inheritdoc}
406 */
407 public function getRequired()
408 {
409 return $this->required;
410 }
411
412 /**
413 * {@inheritdoc}
414 */
415 public function getDisabled()
416 {
417 return $this->disabled;
418 }
419
420 /**
421 * {@inheritdoc}
422 */
423 public function getErrorBubbling()
424 {
425 return $this->errorBubbling;
426 }
427
428 /**
429 * {@inheritdoc}
430 */
431 public function getEmptyData()
432 {
433 return $this->emptyData;
434 }
435
436 /**
437 * {@inheritdoc}
438 */
439 public function getAttributes()
440 {
441 return $this->attributes;
442 }
443
444 /**
445 * {@inheritdoc}
446 */
447 public function hasAttribute($name)
448 {
449 return array_key_exists($name, $this->attributes);
450 }
451
452 /**
453 * {@inheritdoc}
454 */
455 public function getAttribute($name, $default = null)
456 {
457 return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default;
458 }
459
460 /**
461 * {@inheritdoc}
462 */
463 public function getData()
464 {
465 return $this->data;
466 }
467
468 /**
469 * {@inheritdoc}
470 */
471 public function getDataClass()
472 {
473 return $this->dataClass;
474 }
475
476 /**
477 * {@inheritdoc}
478 */
479 public function getDataLocked()
480 {
481 return $this->dataLocked;
482 }
483
484 /**
485 * {@inheritdoc}
486 */
487 public function getFormFactory()
488 {
489 return $this->formFactory;
490 }
491
492 /**
493 * {@inheritdoc}
494 */
495 public function getAction()
496 {
497 return $this->action;
498 }
499
500 /**
501 * {@inheritdoc}
502 */
503 public function getMethod()
504 {
505 return $this->method;
506 }
507
508 /**
509 * {@inheritdoc}
510 */
511 public function getRequestHandler()
512 {
513 if (null === $this->requestHandler) {
514 if (null === self::$nativeRequestProcessor) {
515 self::$nativeRequestProcessor = new NativeRequestHandler();
516 }
517 $this->requestHandler = self::$nativeRequestProcessor;
518 }
519
520 return $this->requestHandler;
521 }
522
523 /**
524 * {@inheritdoc}
525 */
526 public function getAutoInitialize()
527 {
528 return $this->autoInitialize;
529 }
530
531 /**
532 * {@inheritdoc}
533 */
534 public function getOptions()
535 {
536 return $this->options;
537 }
538
539 /**
540 * {@inheritdoc}
541 */
542 public function hasOption($name)
543 {
544 return array_key_exists($name, $this->options);
545 }
546
547 /**
548 * {@inheritdoc}
549 */
550 public function getOption($name, $default = null)
551 {
552 return array_key_exists($name, $this->options) ? $this->options[$name] : $default;
553 }
554
555 /**
556 * {@inheritdoc}
557 */
558 public function setAttribute($name, $value)
559 {
560 if ($this->locked) {
561 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
562 }
563
564 $this->attributes[$name] = $value;
565
566 return $this;
567 }
568
569 /**
570 * {@inheritdoc}
571 */
572 public function setAttributes(array $attributes)
573 {
574 if ($this->locked) {
575 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
576 }
577
578 $this->attributes = $attributes;
579
580 return $this;
581 }
582
583 /**
584 * {@inheritdoc}
585 */
586 public function setDataMapper(DataMapperInterface $dataMapper = null)
587 {
588 if ($this->locked) {
589 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
590 }
591
592 $this->dataMapper = $dataMapper;
593
594 return $this;
595 }
596
597 /**
598 * {@inheritdoc}
599 */
600 public function setDisabled($disabled)
601 {
602 if ($this->locked) {
603 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
604 }
605
606 $this->disabled = (Boolean) $disabled;
607
608 return $this;
609 }
610
611 /**
612 * {@inheritdoc}
613 */
614 public function setEmptyData($emptyData)
615 {
616 if ($this->locked) {
617 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
618 }
619
620 $this->emptyData = $emptyData;
621
622 return $this;
623 }
624
625 /**
626 * {@inheritdoc}
627 */
628 public function setErrorBubbling($errorBubbling)
629 {
630 if ($this->locked) {
631 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
632 }
633
634 $this->errorBubbling = null === $errorBubbling ? null : (Boolean) $errorBubbling;
635
636 return $this;
637 }
638
639 /**
640 * {@inheritdoc}
641 */
642 public function setRequired($required)
643 {
644 if ($this->locked) {
645 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
646 }
647
648 $this->required = (Boolean) $required;
649
650 return $this;
651 }
652
653 /**
654 * {@inheritdoc}
655 */
656 public function setPropertyPath($propertyPath)
657 {
658 if ($this->locked) {
659 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
660 }
661
662 if (null !== $propertyPath && !$propertyPath instanceof PropertyPathInterface) {
663 $propertyPath = new PropertyPath($propertyPath);
664 }
665
666 $this->propertyPath = $propertyPath;
667
668 return $this;
669 }
670
671 /**
672 * {@inheritdoc}
673 */
674 public function setMapped($mapped)
675 {
676 if ($this->locked) {
677 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
678 }
679
680 $this->mapped = $mapped;
681
682 return $this;
683 }
684
685 /**
686 * {@inheritdoc}
687 */
688 public function setByReference($byReference)
689 {
690 if ($this->locked) {
691 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
692 }
693
694 $this->byReference = $byReference;
695
696 return $this;
697 }
698
699 /**
700 * {@inheritdoc}
701 */
702 public function setInheritData($inheritData)
703 {
704 if ($this->locked) {
705 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
706 }
707
708 $this->inheritData = $inheritData;
709
710 return $this;
711 }
712
713 /**
714 * Alias of {@link setInheritData()}.
715 *
716 * @param Boolean $inheritData Whether the form should inherit its parent's data.
717 *
718 * @return FormConfigBuilder The configuration object.
719 *
720 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
721 * {@link setInheritData()} instead.
722 */
723 public function setVirtual($inheritData)
724 {
725 // Uncomment this as soon as the deprecation note should be shown
726 // trigger_error('setVirtual() is deprecated since version 2.3 and will be removed in 3.0. Use setInheritData() instead.', E_USER_DEPRECATED);
727
728 $this->setInheritData($inheritData);
729 }
730
731 /**
732 * {@inheritdoc}
733 */
734 public function setCompound($compound)
735 {
736 if ($this->locked) {
737 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
738 }
739
740 $this->compound = $compound;
741
742 return $this;
743 }
744
745 /**
746 * {@inheritdoc}
747 */
748 public function setType(ResolvedFormTypeInterface $type)
749 {
750 if ($this->locked) {
751 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
752 }
753
754 $this->type = $type;
755
756 return $this;
757 }
758
759 /**
760 * {@inheritdoc}
761 */
762 public function setData($data)
763 {
764 if ($this->locked) {
765 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
766 }
767
768 $this->data = $data;
769
770 return $this;
771 }
772
773 /**
774 * {@inheritdoc}
775 */
776 public function setDataLocked($locked)
777 {
778 if ($this->locked) {
779 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
780 }
781
782 $this->dataLocked = $locked;
783
784 return $this;
785 }
786
787 /**
788 * {@inheritdoc}
789 */
790 public function setFormFactory(FormFactoryInterface $formFactory)
791 {
792 if ($this->locked) {
793 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
794 }
795
796 $this->formFactory = $formFactory;
797
798 return $this;
799 }
800
801 /**
802 * {@inheritdoc}
803 */
804 public function setAction($action)
805 {
806 if ($this->locked) {
807 throw new BadMethodCallException('The config builder cannot be modified anymore.');
808 }
809
810 $this->action = $action;
811
812 return $this;
813 }
814
815 /**
816 * {@inheritdoc}
817 */
818 public function setMethod($method)
819 {
820 if ($this->locked) {
821 throw new BadMethodCallException('The config builder cannot be modified anymore.');
822 }
823
824 $upperCaseMethod = strtoupper($method);
825
826 if (!in_array($upperCaseMethod, self::$allowedMethods)) {
827 throw new InvalidArgumentException(sprintf(
828 'The form method is "%s", but should be one of "%s".',
829 $method,
830 implode('", "', self::$allowedMethods)
831 ));
832 }
833
834 $this->method = $upperCaseMethod;
835
836 return $this;
837 }
838
839 /**
840 * {@inheritdoc}
841 */
842 public function setRequestHandler(RequestHandlerInterface $requestHandler)
843 {
844 if ($this->locked) {
845 throw new BadMethodCallException('The config builder cannot be modified anymore.');
846 }
847
848 $this->requestHandler = $requestHandler;
849
850 return $this;
851 }
852
853 /**
854 * {@inheritdoc}
855 */
856 public function setAutoInitialize($initialize)
857 {
858 $this->autoInitialize = (Boolean) $initialize;
859
860 return $this;
861 }
862
863 /**
864 * {@inheritdoc}
865 */
866 public function getFormConfig()
867 {
868 if ($this->locked) {
869 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
870 }
871
872 // This method should be idempotent, so clone the builder
873 $config = clone $this;
874 $config->locked = true;
875
876 return $config;
877 }
878
879 /**
880 * Validates whether the given variable is a valid form name.
881 *
882 * @param string|integer $name The tested form name.
883 *
884 * @throws UnexpectedTypeException If the name is not a string or an integer.
885 * @throws InvalidArgumentException If the name contains invalid characters.
886 */
887 public static function validateName($name)
888 {
889 if (null !== $name && !is_string($name) && !is_int($name)) {
890 throw new UnexpectedTypeException($name, 'string, integer or null');
891 }
892
893 if (!self::isValidName($name)) {
894 throw new InvalidArgumentException(sprintf(
895 'The name "%s" contains illegal characters. Names should start with a letter, digit or underscore and only contain letters, digits, numbers, underscores ("_"), hyphens ("-") and colons (":").',
896 $name
897 ));
898 }
899 }
900
901 /**
902 * Returns whether the given variable contains a valid form name.
903 *
904 * A name is accepted if it
905 *
906 * * is empty
907 * * starts with a letter, digit or underscore
908 * * contains only letters, digits, numbers, underscores ("_"),
909 * hyphens ("-") and colons (":")
910 *
911 * @param string $name The tested form name.
912 *
913 * @return Boolean Whether the name is valid.
914 */
915 public static function isValidName($name)
916 {
917 return '' === $name || null === $name || preg_match('/^[a-zA-Z0-9_][a-zA-Z0-9_\-:]*$/D', $name);
918 }
919 }