5585a76234e60796cea0452b29d418c43f54a252
[yaffs-website] / web / core / lib / Drupal / Core / Form / FormState.php
1 <?php
2
3 namespace Drupal\Core\Form;
4
5 use Drupal\Component\Utility\NestedArray;
6 use Drupal\Core\Url;
7 use Symfony\Component\HttpFoundation\Response;
8
9 /**
10  * Stores information about the state of a form.
11  */
12 class FormState implements FormStateInterface {
13
14   use FormStateValuesTrait;
15
16   /**
17    * Tracks if any errors have been set on any form.
18    *
19    * @var bool
20    */
21   protected static $anyErrors = FALSE;
22
23   /**
24    * The complete form structure.
25    *
26    * #process, #after_build, #element_validate, and other handlers being invoked
27    * on a form element may use this reference to access other information in the
28    * form the element is contained in.
29    *
30    * @see self::getCompleteForm()
31    *
32    * This property is uncacheable.
33    *
34    * @var array
35    */
36   protected $complete_form;
37
38   /**
39    * An associative array of information stored by Form API that is necessary to
40    * build and rebuild the form from cache when the original context may no
41    * longer be available:
42    *   - callback: The actual callback to be used to retrieve the form array.
43    *     Can be any callable. If none is provided $form_id is used as the name
44    *     of a function to call instead.
45    *   - args: A list of arguments to pass to the form constructor.
46    *   - files: An optional array defining include files that need to be loaded
47    *     for building the form. Each array entry may be the path to a file or
48    *     another array containing values for the parameters 'type', 'module' and
49    *     'name' as needed by module_load_include(). The files listed here are
50    *     automatically loaded by \Drupal::formBuilder()->getCache(). By default
51    *     the current menu router item's 'file' definition is added, if any. Use
52    *     self::loadInclude() to add include files from a form constructor.
53    *   - form_id: Identification of the primary form being constructed and
54    *     processed.
55    *   - base_form_id: Identification for a base form, as declared in the form
56    *     class's \Drupal\Core\Form\BaseFormIdInterface::getBaseFormId() method.
57    *   - immutable: If this flag is set to TRUE, a new form build id is
58    *     generated when the form is loaded from the cache. If it is subsequently
59    *     saved to the cache again, it will have another cache id and therefore
60    *     the original form and form-state will remain unaltered. This is
61    *     important when page caching is enabled in order to prevent form state
62    *     from leaking between anonymous users.
63    *
64    * @var array
65    */
66   protected $build_info = [
67     'args' => [],
68     'files' => [],
69   ];
70
71   /**
72    * Similar to self::$build_info, but pertaining to
73    * \Drupal\Core\Form\FormBuilderInterface::rebuildForm().
74    *
75    * This property is uncacheable.
76    *
77    * @var array
78    */
79   protected $rebuild_info = [];
80
81   /**
82    * Normally, after the entire form processing is completed and submit handlers
83    * have run, a form is considered to be done and
84    * \Drupal\Core\Form\FormSubmitterInterface::redirectForm() will redirect the
85    * user to a new page using a GET request (so a browser refresh does not
86    * re-submit the form). However, if 'rebuild' has been set to TRUE, then a new
87    * copy of the form is immediately built and sent to the browser, instead of a
88    * redirect. This is used for multi-step forms, such as wizards and
89    * confirmation forms. Normally, self::$rebuild is set by a submit handler,
90    * since its is usually logic within a submit handler that determines whether
91    * a form is done or requires another step. However, a validation handler may
92    * already set self::$rebuild to cause the form processing to bypass submit
93    * handlers and rebuild the form instead, even if there are no validation
94    * errors.
95    *
96    * This property is uncacheable.
97    *
98    * @see self::setRebuild()
99    *
100    * @var bool
101    */
102   protected $rebuild = FALSE;
103
104   /**
105    * If set to TRUE the form will skip calling form element value callbacks,
106    * except for a select list of callbacks provided by Drupal core that are
107    * known to be safe.
108    *
109    * This property is uncacheable.
110    *
111    * @see self::setInvalidToken()
112    *
113    * @var bool
114    */
115   protected $invalidToken = FALSE;
116
117   /**
118    * Used when a form needs to return some kind of a
119    * \Symfony\Component\HttpFoundation\Response object, e.g., a
120    * \Symfony\Component\HttpFoundation\BinaryFileResponse when triggering a
121    * file download. If you use self::setRedirect() or self::setRedirectUrl(),
122    * it will be used to build a
123    * \Symfony\Component\HttpFoundation\RedirectResponse and will populate this
124    * key.
125    *
126    * @var \Symfony\Component\HttpFoundation\Response|null
127    */
128   protected $response;
129
130   /**
131    * Used to redirect the form on submission.
132    *
133    * @see self::getRedirect()
134    *
135    * This property is uncacheable.
136    *
137    * @var \Drupal\Core\Url|\Symfony\Component\HttpFoundation\RedirectResponse|null
138    */
139   protected $redirect;
140
141   /**
142    * If set to TRUE the form will NOT perform a redirect, even if
143    * self::$redirect is set.
144    *
145    * This property is uncacheable.
146    *
147    * @var bool
148    */
149   protected $no_redirect;
150
151   /**
152    * The HTTP form method to use for finding the input for this form.
153    *
154    * May be 'POST' or 'GET'. Defaults to 'POST'. Note that 'GET' method forms do
155    * not use form ids so are always considered to be submitted, which can have
156    * unexpected effects. The 'GET' method should only be used on forms that do
157    * not change data, as that is exclusively the domain of 'POST.'
158    *
159    * This property is uncacheable.
160    *
161    * @var string
162    */
163   protected $method = 'POST';
164
165   /**
166    * The HTTP method used by the request building or processing this form.
167    *
168    * May be any valid HTTP method. Defaults to 'GET', because even though
169    * $method is 'POST' for most forms, the form's initial build is usually
170    * performed as part of a GET request.
171    *
172    * This property is uncacheable.
173    *
174    * @var string
175    */
176   protected $requestMethod = 'GET';
177
178   /**
179    * If set to TRUE the original, unprocessed form structure will be cached,
180    * which allows the entire form to be rebuilt from cache. A typical form
181    * workflow involves two page requests; first, a form is built and rendered
182    * for the user to fill in. Then, the user fills the form in and submits it,
183    * triggering a second page request in which the form must be built and
184    * processed. By default, $form and $form_state are built from scratch during
185    * each of these page requests. Often, it is necessary or desired to persist
186    * the $form and $form_state variables from the initial page request to the
187    * one that processes the submission. 'cache' can be set to TRUE to do this.
188    * A prominent example is an Ajax-enabled form, in which
189    * \Drupal\Core\Render\Element\RenderElement::processAjaxForm()
190    * enables form caching for all forms that include an element with the #ajax
191    * property. (The Ajax handler has no way to build the form itself, so must
192    * rely on the cached version.) Note that the persistence of $form and
193    * $form_state happens automatically for (multi-step) forms having the
194    * self::$rebuild flag set, regardless of the value for self::$cache.
195    *
196    * @var bool
197    */
198   protected $cache = FALSE;
199
200   /**
201    * If set to TRUE the form will NOT be cached, even if 'cache' is set.
202    *
203    * @var bool
204    */
205   protected $no_cache;
206
207   /**
208    * An associative array of values submitted to the form.
209    *
210    * The validation functions and submit functions use this array for nearly all
211    * their decision making. (Note that #tree determines whether the values are a
212    * flat array or an array whose structure parallels the $form array. See
213    * \Drupal\Core\Render\Element\FormElement for more information.)
214    *
215    * This property is uncacheable.
216    *
217    * @var array
218    */
219   protected $values = [];
220
221   /**
222    * An associative array of form value keys to be removed by cleanValues().
223    *
224    * Any values that are temporary but must still be displayed as values in
225    * the rendered form should be added to this array using addCleanValueKey().
226    * Initialized with internal Form API values.
227    *
228    * This property is uncacheable.
229    *
230    * @var array
231    */
232   protected $cleanValueKeys = [
233     'form_id',
234     'form_token',
235     'form_build_id',
236     'op',
237   ];
238
239   /**
240    * The array of values as they were submitted by the user.
241    *
242    * These are raw and unvalidated, so should not be used without a thorough
243    * understanding of security implications. In almost all cases, code should
244    * use the data in the 'values' array exclusively. The most common use of this
245    * key is for multi-step forms that need to clear some of the user input when
246    * setting 'rebuild'. The values correspond to \Drupal::request()->request or
247    * \Drupal::request()->query, depending on the 'method' chosen.
248    *
249    * This property is uncacheable.
250    *
251    * @var array|null
252    *   The submitted user input array, or NULL if no input was submitted yet.
253    */
254   protected $input;
255
256   /**
257    * If TRUE and the method is GET, a form_id is not necessary.
258    *
259    * This property is uncacheable.
260    *
261    * @var bool
262    */
263   protected $always_process;
264
265   /**
266    * Ordinarily, a form is only validated once, but there are times when a form
267    * is resubmitted internally and should be validated again. Setting this to
268    * TRUE will force that to happen. This is most likely to occur during Ajax
269    * operations.
270    *
271    * This property is uncacheable.
272    *
273    * @var bool
274    */
275   protected $must_validate;
276
277   /**
278    * If TRUE, the form was submitted programmatically, usually invoked via
279    * \Drupal\Core\Form\FormBuilderInterface::submitForm(). Defaults to FALSE.
280    *
281    * @var bool
282    */
283   protected $programmed = FALSE;
284
285   /**
286    * If TRUE, programmatic form submissions are processed without taking #access
287    * into account. Set this to FALSE when submitting a form programmatically
288    * with values that may have been input by the user executing the current
289    * request; this will cause #access to be respected as it would on a normal
290    * form submission. Defaults to TRUE.
291    *
292    * @var bool
293    */
294   protected $programmed_bypass_access_check = TRUE;
295
296   /**
297    * TRUE signifies correct form submission. This is always TRUE for programmed
298    * forms coming from \Drupal\Core\Form\FormBuilderInterface::submitForm() (see
299    * 'programmed' key), or if the form_id coming from the
300    * \Drupal::request()->request data is set and matches the current form_id.
301    *
302    * @var bool
303    */
304   protected $process_input;
305
306   /**
307    * If TRUE, the form has been submitted. Defaults to FALSE.
308    *
309    * This property is uncacheable.
310    *
311    * @var bool
312    */
313   protected $submitted = FALSE;
314
315   /**
316    * If TRUE, the form was submitted and has been processed and executed.
317    *
318    * This property is uncacheable.
319    *
320    * @var bool
321    */
322   protected $executed = FALSE;
323
324   /**
325    * The form element that triggered submission, which may or may not be a
326    * button (in the case of Ajax forms). This key is often used to distinguish
327    * between various buttons in a submit handler, and is also used in Ajax
328    * handlers.
329    *
330    * This property is uncacheable.
331    *
332    * @var array|null
333    */
334   protected $triggering_element;
335
336   /**
337    * If TRUE, there is a file element and Form API will set the appropriate
338    * 'enctype' HTML attribute on the form.
339    *
340    * @var bool
341    */
342   protected $has_file_element;
343
344   /**
345    * Contains references to details elements to render them within vertical tabs.
346    *
347    * This property is uncacheable.
348    *
349    * @var array
350    */
351   protected $groups = [];
352
353   /**
354    * This is not a special key, and no specific support is provided for it in
355    * the Form API. By tradition it was the location where application-specific
356    * data was stored for communication between the submit, validation, and form
357    * builder functions, especially in a multi-step-style form. Form
358    * implementations may use any key(s) within $form_state (other than the keys
359    * listed here and other reserved ones used by Form API internals) for this
360    * kind of storage. The recommended way to ensure that the chosen key doesn't
361    * conflict with ones used by the Form API or other modules is to use the
362    * module name as the key name or a prefix for the key name. For example, the
363    * entity form classes use $this->entity in entity forms, or
364    * $form_state->getFormObject()->getEntity() outside the controller, to store
365    * information about the entity being edited, and this information stays
366    * available across successive clicks of the "Preview" button (if available)
367    * as well as when the "Save" button is finally clicked.
368    *
369    * @var array
370    */
371   protected $storage = [];
372
373   /**
374    * A list containing copies of all submit and button elements in the form.
375    *
376    * This property is uncacheable.
377    *
378    * @var array
379    */
380   protected $buttons = [];
381
382   /**
383    * Holds temporary data accessible during the current page request only.
384    *
385    * All $form_state properties that are not reserved keys (see
386    * other properties marked as uncacheable) persist throughout a multistep form
387    * sequence. Form API provides this key for modules to communicate information
388    * across form-related functions during a single page request. It may be used
389    * to temporarily save data that does not need to or should not be cached
390    * during the whole form workflow; e.g., data that needs to be accessed during
391    * the current form build process only. There is no use-case for this
392    * functionality in Drupal core.
393    *
394    * This property is uncacheable.
395    *
396    * @var array
397    */
398   protected $temporary = [];
399
400   /**
401    * Tracks if the form has finished validation.
402    *
403    * This property is uncacheable.
404    *
405    * @var bool
406    */
407   protected $validation_complete = FALSE;
408
409   /**
410    * Contains errors for this form.
411    *
412    * This property is uncacheable.
413    *
414    * @var array
415    */
416   protected $errors = [];
417
418   /**
419    * Stores which errors should be limited during validation.
420    *
421    * An array of "sections" within which user input must be valid. If the
422    * element is within one of these sections, the error must be recorded.
423    * Otherwise, it can be suppressed. self::$limit_validation_errors can be an
424    * empty array, in which case all errors are suppressed. For example, a
425    * "Previous" button might want its submit action to be triggered even if none
426    * of the submitted values are valid.
427    *
428    * This property is uncacheable.
429    *
430    * @var array|null
431    */
432   protected $limit_validation_errors;
433
434   /**
435    * Stores the gathered validation handlers.
436    *
437    * This property is uncacheable.
438    *
439    * @var array
440    */
441   protected $validate_handlers = [];
442
443   /**
444    * Stores the gathered submission handlers.
445    *
446    * This property is uncacheable.
447    *
448    * @var array
449    */
450   protected $submit_handlers = [];
451
452   /**
453    * {@inheritdoc}
454    */
455   public function setFormState(array $form_state_additions) {
456     foreach ($form_state_additions as $key => $value) {
457       if (property_exists($this, $key)) {
458         $this->{$key} = $value;
459       }
460       else {
461         $this->set($key, $value);
462       }
463     }
464     return $this;
465   }
466
467   /**
468    * {@inheritdoc}
469    */
470   public function setAlwaysProcess($always_process = TRUE) {
471     $this->always_process = (bool) $always_process;
472     return $this;
473   }
474
475   /**
476    * {@inheritdoc}
477    */
478   public function getAlwaysProcess() {
479     return $this->always_process;
480   }
481
482   /**
483    * {@inheritdoc}
484    */
485   public function setButtons(array $buttons) {
486     $this->buttons = $buttons;
487     return $this;
488   }
489
490   /**
491    * {@inheritdoc}
492    */
493   public function getButtons() {
494     return $this->buttons;
495   }
496
497   /**
498    * {@inheritdoc}
499    */
500   public function setCached($cache = TRUE) {
501     // Persisting $form_state is a side-effect disallowed during a "safe" HTTP
502     // method.
503     if ($cache && $this->isRequestMethodSafe()) {
504       throw new \LogicException(sprintf('Form state caching on %s requests is not allowed.', $this->requestMethod));
505     }
506
507     $this->cache = (bool) $cache;
508     return $this;
509   }
510
511   /**
512    * {@inheritdoc}
513    */
514   public function isCached() {
515     return empty($this->no_cache) && $this->cache;
516   }
517
518   /**
519    * {@inheritdoc}
520    */
521   public function disableCache() {
522     $this->no_cache = TRUE;
523     return $this;
524   }
525
526   /**
527    * {@inheritdoc}
528    */
529   public function setExecuted() {
530     $this->executed = TRUE;
531     return $this;
532   }
533
534   /**
535    * {@inheritdoc}
536    */
537   public function isExecuted() {
538     return $this->executed;
539   }
540
541   /**
542    * {@inheritdoc}
543    */
544   public function setGroups(array $groups) {
545     $this->groups = $groups;
546     return $this;
547   }
548
549   /**
550    * {@inheritdoc}
551    */
552   public function &getGroups() {
553     return $this->groups;
554   }
555
556   /**
557    * {@inheritdoc}
558    */
559   public function setHasFileElement($has_file_element = TRUE) {
560     $this->has_file_element = (bool) $has_file_element;
561     return $this;
562   }
563
564   /**
565    * {@inheritdoc}
566    */
567   public function hasFileElement() {
568     return $this->has_file_element;
569   }
570
571   /**
572    * {@inheritdoc}
573    */
574   public function setLimitValidationErrors($limit_validation_errors) {
575     $this->limit_validation_errors = $limit_validation_errors;
576     return $this;
577   }
578
579   /**
580    * {@inheritdoc}
581    */
582   public function getLimitValidationErrors() {
583     return $this->limit_validation_errors;
584   }
585
586   /**
587    * {@inheritdoc}
588    */
589   public function setMethod($method) {
590     $this->method = strtoupper($method);
591     return $this;
592   }
593
594   /**
595    * {@inheritdoc}
596    */
597   public function isMethodType($method_type) {
598     return $this->method === strtoupper($method_type);
599   }
600
601   /**
602    * {@inheritdoc}
603    */
604   public function setRequestMethod($method) {
605     $this->requestMethod = strtoupper($method);
606     return $this;
607   }
608
609   /**
610    * Checks whether the request method is a "safe" HTTP method.
611    *
612    * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1 defines
613    * GET and HEAD as "safe" methods, meaning they SHOULD NOT have side-effects,
614    * such as persisting $form_state changes.
615    *
616    * @return bool
617    *
618    * @see \Symfony\Component\HttpFoundation\Request::isMethodSafe()
619    */
620   protected function isRequestMethodSafe() {
621     return in_array($this->requestMethod, ['GET', 'HEAD']);
622   }
623
624   /**
625    * {@inheritdoc}
626    */
627   public function setValidationEnforced($must_validate = TRUE) {
628     $this->must_validate = (bool) $must_validate;
629     return $this;
630   }
631
632   /**
633    * {@inheritdoc}
634    */
635   public function isValidationEnforced() {
636     return $this->must_validate;
637   }
638
639   /**
640    * {@inheritdoc}
641    */
642   public function disableRedirect($no_redirect = TRUE) {
643     $this->no_redirect = (bool) $no_redirect;
644     return $this;
645   }
646
647   /**
648    * {@inheritdoc}
649    */
650   public function isRedirectDisabled() {
651     return $this->no_redirect;
652   }
653
654   /**
655    * {@inheritdoc}
656    */
657   public function setProcessInput($process_input = TRUE) {
658     $this->process_input = (bool) $process_input;
659     return $this;
660   }
661
662   /**
663    * {@inheritdoc}
664    */
665   public function isProcessingInput() {
666     return $this->process_input;
667   }
668
669   /**
670    * {@inheritdoc}
671    */
672   public function setProgrammed($programmed = TRUE) {
673     $this->programmed = (bool) $programmed;
674     return $this;
675   }
676
677   /**
678    * {@inheritdoc}
679    */
680   public function isProgrammed() {
681     return $this->programmed;
682   }
683
684   /**
685    * {@inheritdoc}
686    */
687   public function setProgrammedBypassAccessCheck($programmed_bypass_access_check = TRUE) {
688     $this->programmed_bypass_access_check = (bool) $programmed_bypass_access_check;
689     return $this;
690   }
691
692   /**
693    * {@inheritdoc}
694    */
695   public function isBypassingProgrammedAccessChecks() {
696     return $this->programmed_bypass_access_check;
697   }
698
699   /**
700    * {@inheritdoc}
701    */
702   public function setRebuildInfo(array $rebuild_info) {
703     $this->rebuild_info = $rebuild_info;
704     return $this;
705   }
706
707   /**
708    * {@inheritdoc}
709    */
710   public function getRebuildInfo() {
711     return $this->rebuild_info;
712   }
713
714   /**
715    * {@inheritdoc}
716    */
717   public function addRebuildInfo($property, $value) {
718     $rebuild_info = $this->getRebuildInfo();
719     $rebuild_info[$property] = $value;
720     $this->setRebuildInfo($rebuild_info);
721     return $this;
722   }
723
724   /**
725    * {@inheritdoc}
726    */
727   public function setStorage(array $storage) {
728     $this->storage = $storage;
729     return $this;
730   }
731
732   /**
733    * {@inheritdoc}
734    */
735   public function &getStorage() {
736     return $this->storage;
737   }
738
739   /**
740    * {@inheritdoc}
741    */
742   public function setSubmitHandlers(array $submit_handlers) {
743     $this->submit_handlers = $submit_handlers;
744     return $this;
745   }
746
747   /**
748    * {@inheritdoc}
749    */
750   public function getSubmitHandlers() {
751     return $this->submit_handlers;
752   }
753
754   /**
755    * {@inheritdoc}
756    */
757   public function setSubmitted() {
758     $this->submitted = TRUE;
759     return $this;
760   }
761
762   /**
763    * {@inheritdoc}
764    */
765   public function isSubmitted() {
766     return $this->submitted;
767   }
768
769   /**
770    * {@inheritdoc}
771    */
772   public function setTemporary(array $temporary) {
773     $this->temporary = $temporary;
774     return $this;
775   }
776
777   /**
778    * {@inheritdoc}
779    */
780   public function getTemporary() {
781     return $this->temporary;
782   }
783
784   /**
785    * {@inheritdoc}
786    */
787   public function &getTemporaryValue($key) {
788     $value = &NestedArray::getValue($this->temporary, (array) $key);
789     return $value;
790   }
791
792   /**
793    * {@inheritdoc}
794    */
795   public function setTemporaryValue($key, $value) {
796     NestedArray::setValue($this->temporary, (array) $key, $value, TRUE);
797     return $this;
798   }
799
800   /**
801    * {@inheritdoc}
802    */
803   public function hasTemporaryValue($key) {
804     $exists = NULL;
805     NestedArray::getValue($this->temporary, (array) $key, $exists);
806     return $exists;
807   }
808
809   /**
810    * {@inheritdoc}
811    */
812   public function setTriggeringElement($triggering_element) {
813     $this->triggering_element = $triggering_element;
814     return $this;
815   }
816
817   /**
818    * {@inheritdoc}
819    */
820   public function &getTriggeringElement() {
821     return $this->triggering_element;
822   }
823
824   /**
825    * {@inheritdoc}
826    */
827   public function setValidateHandlers(array $validate_handlers) {
828     $this->validate_handlers = $validate_handlers;
829     return $this;
830   }
831
832   /**
833    * {@inheritdoc}
834    */
835   public function getValidateHandlers() {
836     return $this->validate_handlers;
837   }
838
839   /**
840    * {@inheritdoc}
841    */
842   public function setValidationComplete($validation_complete = TRUE) {
843     $this->validation_complete = (bool) $validation_complete;
844     return $this;
845   }
846
847   /**
848    * {@inheritdoc}
849    */
850   public function isValidationComplete() {
851     return $this->validation_complete;
852   }
853
854   /**
855    * {@inheritdoc}
856    */
857   public function loadInclude($module, $type, $name = NULL) {
858     if (!isset($name)) {
859       $name = $module;
860     }
861     $build_info = $this->getBuildInfo();
862     if (!isset($build_info['files']["$module:$name.$type"])) {
863       // Only add successfully included files to the form state.
864       if ($result = $this->moduleLoadInclude($module, $type, $name)) {
865         $build_info['files']["$module:$name.$type"] = [
866           'type' => $type,
867           'module' => $module,
868           'name' => $name,
869         ];
870         $this->setBuildInfo($build_info);
871         return $result;
872       }
873     }
874     return FALSE;
875   }
876
877   /**
878    * {@inheritdoc}
879    */
880   public function getCacheableArray() {
881     return [
882       'build_info' => $this->getBuildInfo(),
883       'response' => $this->getResponse(),
884       'programmed' => $this->isProgrammed(),
885       'programmed_bypass_access_check' => $this->isBypassingProgrammedAccessChecks(),
886       'process_input' => $this->isProcessingInput(),
887       'has_file_element' => $this->hasFileElement(),
888       'storage' => $this->getStorage(),
889       // Use the properties directly, since self::isCached() combines them and
890       // cannot be relied upon.
891       'cache' => $this->cache,
892       'no_cache' => $this->no_cache,
893     ];
894   }
895
896   /**
897    * {@inheritdoc}
898    */
899   public function setCompleteForm(array &$complete_form) {
900     $this->complete_form = &$complete_form;
901     return $this;
902   }
903
904   /**
905    * {@inheritdoc}
906    */
907   public function &getCompleteForm() {
908     return $this->complete_form;
909   }
910
911   /**
912    * {@inheritdoc}
913    */
914   public function &get($property) {
915     $value = &NestedArray::getValue($this->storage, (array) $property);
916     return $value;
917   }
918
919   /**
920    * {@inheritdoc}
921    */
922   public function set($property, $value) {
923     NestedArray::setValue($this->storage, (array) $property, $value, TRUE);
924     return $this;
925   }
926
927   /**
928    * {@inheritdoc}
929    */
930   public function has($property) {
931     $exists = NULL;
932     NestedArray::getValue($this->storage, (array) $property, $exists);
933     return $exists;
934   }
935
936   /**
937    * {@inheritdoc}
938    */
939   public function setBuildInfo(array $build_info) {
940     $this->build_info = $build_info;
941     return $this;
942   }
943
944   /**
945    * {@inheritdoc}
946    */
947   public function getBuildInfo() {
948     return $this->build_info;
949   }
950
951   /**
952    * {@inheritdoc}
953    */
954   public function addBuildInfo($property, $value) {
955     $build_info = $this->getBuildInfo();
956     $build_info[$property] = $value;
957     $this->setBuildInfo($build_info);
958     return $this;
959   }
960
961   /**
962    * {@inheritdoc}
963    */
964   public function &getUserInput() {
965     return $this->input;
966   }
967
968   /**
969    * {@inheritdoc}
970    */
971   public function setUserInput(array $user_input) {
972     $this->input = $user_input;
973     return $this;
974   }
975
976   /**
977    * {@inheritdoc}
978    */
979   public function &getValues() {
980     return $this->values;
981   }
982
983   /**
984    * {@inheritdoc}
985    */
986   public function setResponse(Response $response) {
987     $this->response = $response;
988     return $this;
989   }
990
991   /**
992    * {@inheritdoc}
993    */
994   public function getResponse() {
995     return $this->response;
996   }
997
998   /**
999    * {@inheritdoc}
1000    */
1001   public function setRedirect($route_name, array $route_parameters = [], array $options = []) {
1002     $url = new Url($route_name, $route_parameters, $options);
1003     return $this->setRedirectUrl($url);
1004   }
1005
1006   /**
1007    * {@inheritdoc}
1008    */
1009   public function setRedirectUrl(Url $url) {
1010     $this->redirect = $url;
1011     return $this;
1012   }
1013
1014   /**
1015    * {@inheritdoc}
1016    */
1017   public function getRedirect() {
1018     // Skip redirection for form submissions invoked via
1019     // \Drupal\Core\Form\FormBuilderInterface::submitForm().
1020     if ($this->isProgrammed()) {
1021       return FALSE;
1022     }
1023     // Skip redirection if rebuild is activated.
1024     if ($this->isRebuilding()) {
1025       return FALSE;
1026     }
1027     // Skip redirection if it was explicitly disallowed.
1028     if ($this->isRedirectDisabled()) {
1029       return FALSE;
1030     }
1031
1032     return $this->redirect;
1033   }
1034
1035   /**
1036    * Sets the global status of errors.
1037    *
1038    * @param bool $errors
1039    *   TRUE if any form has any errors, FALSE otherwise.
1040    */
1041   protected static function setAnyErrors($errors = TRUE) {
1042     static::$anyErrors = $errors;
1043   }
1044
1045   /**
1046    * {@inheritdoc}
1047    */
1048   public static function hasAnyErrors() {
1049     return static::$anyErrors;
1050   }
1051
1052   /**
1053    * {@inheritdoc}
1054    */
1055   public function setErrorByName($name, $message = '') {
1056     if ($this->isValidationComplete()) {
1057       throw new \LogicException('Form errors cannot be set after form validation has finished.');
1058     }
1059
1060     $errors = $this->getErrors();
1061     if (!isset($errors[$name])) {
1062       $record = TRUE;
1063       $limit_validation_errors = $this->getLimitValidationErrors();
1064       if ($limit_validation_errors !== NULL) {
1065         $record = FALSE;
1066         foreach ($limit_validation_errors as $section) {
1067           // Exploding by '][' reconstructs the element's #parents. If the
1068           // reconstructed #parents begin with the same keys as the specified
1069           // section, then the element's values are within the part of
1070           // $form_state->getValues() that the clicked button requires to be
1071           // valid, so errors for this element must be recorded. As the exploded
1072           // array will all be strings, we need to cast every value of the
1073           // section array to string.
1074           if (array_slice(explode('][', $name), 0, count($section)) === array_map('strval', $section)) {
1075             $record = TRUE;
1076             break;
1077           }
1078         }
1079       }
1080       if ($record) {
1081         $errors[$name] = $message;
1082         $this->errors = $errors;
1083         static::setAnyErrors();
1084       }
1085     }
1086
1087     return $this;
1088   }
1089
1090   /**
1091    * {@inheritdoc}
1092    */
1093   public function setError(array &$element, $message = '') {
1094     $this->setErrorByName(implode('][', $element['#parents']), $message);
1095     return $this;
1096   }
1097
1098   /**
1099    * {@inheritdoc}
1100    */
1101   public function clearErrors() {
1102     $this->errors = [];
1103     static::setAnyErrors(FALSE);
1104   }
1105
1106   /**
1107    * {@inheritdoc}
1108    */
1109   public function getError(array $element) {
1110     if ($errors = $this->getErrors()) {
1111       $parents = [];
1112       foreach ($element['#parents'] as $parent) {
1113         $parents[] = $parent;
1114         $key = implode('][', $parents);
1115         if (isset($errors[$key])) {
1116           return $errors[$key];
1117         }
1118       }
1119     }
1120   }
1121
1122   /**
1123    * {@inheritdoc}
1124    */
1125   public function getErrors() {
1126     return $this->errors;
1127   }
1128
1129   /**
1130    * {@inheritdoc}
1131    */
1132   public function setRebuild($rebuild = TRUE) {
1133     $this->rebuild = $rebuild;
1134     return $this;
1135   }
1136
1137   /**
1138    * {@inheritdoc}
1139    */
1140   public function isRebuilding() {
1141     return $this->rebuild;
1142   }
1143
1144   /**
1145    * {@inheritdoc}
1146    */
1147   public function prepareCallback($callback) {
1148     if (is_string($callback) && substr($callback, 0, 2) == '::') {
1149       $callback = [$this->getFormObject(), substr($callback, 2)];
1150     }
1151     return $callback;
1152   }
1153
1154   /**
1155    * {@inheritdoc}
1156    */
1157   public function setFormObject(FormInterface $form_object) {
1158     $this->addBuildInfo('callback_object', $form_object);
1159     return $this;
1160   }
1161
1162   /**
1163    * {@inheritdoc}
1164    */
1165   public function getFormObject() {
1166     return $this->getBuildInfo()['callback_object'];
1167   }
1168
1169   /**
1170    * {@inheritdoc}
1171    */
1172   public function getCleanValueKeys() {
1173     return $this->cleanValueKeys;
1174   }
1175
1176   /**
1177    * {@inheritdoc}
1178    */
1179   public function setCleanValueKeys(array $cleanValueKeys) {
1180     $this->cleanValueKeys = $cleanValueKeys;
1181     return $this;
1182   }
1183
1184   /**
1185    * {@inheritdoc}
1186    */
1187   public function addCleanValueKey($cleanValueKey) {
1188     $keys = $this->getCleanValueKeys();
1189     $this->setCleanValueKeys(array_merge((array) $keys, [$cleanValueKey]));
1190     return $this;
1191   }
1192
1193   /**
1194    * {@inheritdoc}
1195    */
1196   public function cleanValues() {
1197     foreach ($this->getCleanValueKeys() as $value) {
1198       $this->unsetValue($value);
1199     }
1200
1201     // Remove button values.
1202     // \Drupal::formBuilder()->doBuildForm() collects all button elements in a
1203     // form. We remove the button value separately for each button element.
1204     foreach ($this->getButtons() as $button) {
1205       // Remove this button's value from the submitted form values by finding
1206       // the value corresponding to this button.
1207       // We iterate over the #parents of this button and move a reference to
1208       // each parent in self::getValues(). For example, if #parents is:
1209       //   array('foo', 'bar', 'baz')
1210       // then the corresponding self::getValues() part will look like this:
1211       // array(
1212       //   'foo' => array(
1213       //     'bar' => array(
1214       //       'baz' => 'button_value',
1215       //     ),
1216       //   ),
1217       // )
1218       // We start by (re)moving 'baz' to $last_parent, so we are able unset it
1219       // at the end of the iteration. Initially, $values will contain a
1220       // reference to self::getValues(), but in the iteration we move the
1221       // reference to self::getValue('foo'), and finally to
1222       // self::getValue(array('foo', 'bar')), which is the level where we
1223       // can unset 'baz' (that is stored in $last_parent).
1224       $parents = $button['#parents'];
1225       $last_parent = array_pop($parents);
1226       $key_exists = NULL;
1227       $values = &NestedArray::getValue($this->getValues(), $parents, $key_exists);
1228       if ($key_exists && is_array($values)) {
1229         unset($values[$last_parent]);
1230       }
1231     }
1232     return $this;
1233   }
1234
1235   /**
1236    * {@inheritdoc}
1237    */
1238   public function setInvalidToken($invalid_token) {
1239     $this->invalidToken = (bool) $invalid_token;
1240     return $this;
1241   }
1242
1243   /**
1244    * {@inheritdoc}
1245    */
1246   public function hasInvalidToken() {
1247     return $this->invalidToken;
1248   }
1249
1250   /**
1251    * Wraps ModuleHandler::loadInclude().
1252    */
1253   protected function moduleLoadInclude($module, $type, $name = NULL) {
1254     return \Drupal::moduleHandler()->loadInclude($module, $type, $name);
1255   }
1256
1257 }