123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257 |
- <?php
- namespace Drupal\Core\Form;
- use Drupal\Component\Utility\NestedArray;
- use Drupal\Core\Url;
- use Symfony\Component\HttpFoundation\Response;
- /**
- * Stores information about the state of a form.
- */
- class FormState implements FormStateInterface {
- use FormStateValuesTrait;
- /**
- * Tracks if any errors have been set on any form.
- *
- * @var bool
- */
- protected static $anyErrors = FALSE;
- /**
- * The complete form structure.
- *
- * #process, #after_build, #element_validate, and other handlers being invoked
- * on a form element may use this reference to access other information in the
- * form the element is contained in.
- *
- * @see self::getCompleteForm()
- *
- * This property is uncacheable.
- *
- * @var array
- */
- protected $complete_form;
- /**
- * An associative array of information stored by Form API that is necessary to
- * build and rebuild the form from cache when the original context may no
- * longer be available:
- * - callback: The actual callback to be used to retrieve the form array.
- * Can be any callable. If none is provided $form_id is used as the name
- * of a function to call instead.
- * - args: A list of arguments to pass to the form constructor.
- * - files: An optional array defining include files that need to be loaded
- * for building the form. Each array entry may be the path to a file or
- * another array containing values for the parameters 'type', 'module' and
- * 'name' as needed by module_load_include(). The files listed here are
- * automatically loaded by \Drupal::formBuilder()->getCache(). By default
- * the current menu router item's 'file' definition is added, if any. Use
- * self::loadInclude() to add include files from a form constructor.
- * - form_id: Identification of the primary form being constructed and
- * processed.
- * - base_form_id: Identification for a base form, as declared in the form
- * class's \Drupal\Core\Form\BaseFormIdInterface::getBaseFormId() method.
- * - immutable: If this flag is set to TRUE, a new form build id is
- * generated when the form is loaded from the cache. If it is subsequently
- * saved to the cache again, it will have another cache id and therefore
- * the original form and form-state will remain unaltered. This is
- * important when page caching is enabled in order to prevent form state
- * from leaking between anonymous users.
- *
- * @var array
- */
- protected $build_info = [
- 'args' => [],
- 'files' => [],
- ];
- /**
- * Similar to self::$build_info, but pertaining to
- * \Drupal\Core\Form\FormBuilderInterface::rebuildForm().
- *
- * This property is uncacheable.
- *
- * @var array
- */
- protected $rebuild_info = [];
- /**
- * Normally, after the entire form processing is completed and submit handlers
- * have run, a form is considered to be done and
- * \Drupal\Core\Form\FormSubmitterInterface::redirectForm() will redirect the
- * user to a new page using a GET request (so a browser refresh does not
- * re-submit the form). However, if 'rebuild' has been set to TRUE, then a new
- * copy of the form is immediately built and sent to the browser, instead of a
- * redirect. This is used for multi-step forms, such as wizards and
- * confirmation forms. Normally, self::$rebuild is set by a submit handler,
- * since its is usually logic within a submit handler that determines whether
- * a form is done or requires another step. However, a validation handler may
- * already set self::$rebuild to cause the form processing to bypass submit
- * handlers and rebuild the form instead, even if there are no validation
- * errors.
- *
- * This property is uncacheable.
- *
- * @see self::setRebuild()
- *
- * @var bool
- */
- protected $rebuild = FALSE;
- /**
- * If set to TRUE the form will skip calling form element value callbacks,
- * except for a select list of callbacks provided by Drupal core that are
- * known to be safe.
- *
- * This property is uncacheable.
- *
- * @see self::setInvalidToken()
- *
- * @var bool
- */
- protected $invalidToken = FALSE;
- /**
- * Used when a form needs to return some kind of a
- * \Symfony\Component\HttpFoundation\Response object, e.g., a
- * \Symfony\Component\HttpFoundation\BinaryFileResponse when triggering a
- * file download. If you use self::setRedirect() or self::setRedirectUrl(),
- * it will be used to build a
- * \Symfony\Component\HttpFoundation\RedirectResponse and will populate this
- * key.
- *
- * @var \Symfony\Component\HttpFoundation\Response|null
- */
- protected $response;
- /**
- * Used to redirect the form on submission.
- *
- * @see self::getRedirect()
- *
- * This property is uncacheable.
- *
- * @var \Drupal\Core\Url|\Symfony\Component\HttpFoundation\RedirectResponse|null
- */
- protected $redirect;
- /**
- * If set to TRUE the form will NOT perform a redirect, even if
- * self::$redirect is set.
- *
- * This property is uncacheable.
- *
- * @var bool
- */
- protected $no_redirect;
- /**
- * The HTTP form method to use for finding the input for this form.
- *
- * May be 'POST' or 'GET'. Defaults to 'POST'. Note that 'GET' method forms do
- * not use form ids so are always considered to be submitted, which can have
- * unexpected effects. The 'GET' method should only be used on forms that do
- * not change data, as that is exclusively the domain of 'POST.'
- *
- * This property is uncacheable.
- *
- * @var string
- */
- protected $method = 'POST';
- /**
- * The HTTP method used by the request building or processing this form.
- *
- * May be any valid HTTP method. Defaults to 'GET', because even though
- * $method is 'POST' for most forms, the form's initial build is usually
- * performed as part of a GET request.
- *
- * This property is uncacheable.
- *
- * @var string
- */
- protected $requestMethod = 'GET';
- /**
- * If set to TRUE the original, unprocessed form structure will be cached,
- * which allows the entire form to be rebuilt from cache. A typical form
- * workflow involves two page requests; first, a form is built and rendered
- * for the user to fill in. Then, the user fills the form in and submits it,
- * triggering a second page request in which the form must be built and
- * processed. By default, $form and $form_state are built from scratch during
- * each of these page requests. Often, it is necessary or desired to persist
- * the $form and $form_state variables from the initial page request to the
- * one that processes the submission. 'cache' can be set to TRUE to do this.
- * A prominent example is an Ajax-enabled form, in which
- * \Drupal\Core\Render\Element\RenderElement::processAjaxForm()
- * enables form caching for all forms that include an element with the #ajax
- * property. (The Ajax handler has no way to build the form itself, so must
- * rely on the cached version.) Note that the persistence of $form and
- * $form_state happens automatically for (multi-step) forms having the
- * self::$rebuild flag set, regardless of the value for self::$cache.
- *
- * @var bool
- */
- protected $cache = FALSE;
- /**
- * If set to TRUE the form will NOT be cached, even if 'cache' is set.
- *
- * @var bool
- */
- protected $no_cache;
- /**
- * An associative array of values submitted to the form.
- *
- * The validation functions and submit functions use this array for nearly all
- * their decision making. (Note that #tree determines whether the values are a
- * flat array or an array whose structure parallels the $form array. See
- * \Drupal\Core\Render\Element\FormElement for more information.)
- *
- * This property is uncacheable.
- *
- * @var array
- */
- protected $values = [];
- /**
- * An associative array of form value keys to be removed by cleanValues().
- *
- * Any values that are temporary but must still be displayed as values in
- * the rendered form should be added to this array using addCleanValueKey().
- * Initialized with internal Form API values.
- *
- * This property is uncacheable.
- *
- * @var array
- */
- protected $cleanValueKeys = [
- 'form_id',
- 'form_token',
- 'form_build_id',
- 'op',
- ];
- /**
- * The array of values as they were submitted by the user.
- *
- * These are raw and unvalidated, so should not be used without a thorough
- * understanding of security implications. In almost all cases, code should
- * use the data in the 'values' array exclusively. The most common use of this
- * key is for multi-step forms that need to clear some of the user input when
- * setting 'rebuild'. The values correspond to \Drupal::request()->request or
- * \Drupal::request()->query, depending on the 'method' chosen.
- *
- * This property is uncacheable.
- *
- * @var array|null
- * The submitted user input array, or NULL if no input was submitted yet.
- */
- protected $input;
- /**
- * If TRUE and the method is GET, a form_id is not necessary.
- *
- * This property is uncacheable.
- *
- * @var bool
- */
- protected $always_process;
- /**
- * Ordinarily, a form is only validated once, but there are times when a form
- * is resubmitted internally and should be validated again. Setting this to
- * TRUE will force that to happen. This is most likely to occur during Ajax
- * operations.
- *
- * This property is uncacheable.
- *
- * @var bool
- */
- protected $must_validate;
- /**
- * If TRUE, the form was submitted programmatically, usually invoked via
- * \Drupal\Core\Form\FormBuilderInterface::submitForm(). Defaults to FALSE.
- *
- * @var bool
- */
- protected $programmed = FALSE;
- /**
- * If TRUE, programmatic form submissions are processed without taking #access
- * into account. Set this to FALSE when submitting a form programmatically
- * with values that may have been input by the user executing the current
- * request; this will cause #access to be respected as it would on a normal
- * form submission. Defaults to TRUE.
- *
- * @var bool
- */
- protected $programmed_bypass_access_check = TRUE;
- /**
- * TRUE signifies correct form submission. This is always TRUE for programmed
- * forms coming from \Drupal\Core\Form\FormBuilderInterface::submitForm() (see
- * 'programmed' key), or if the form_id coming from the
- * \Drupal::request()->request data is set and matches the current form_id.
- *
- * @var bool
- */
- protected $process_input;
- /**
- * If TRUE, the form has been submitted. Defaults to FALSE.
- *
- * This property is uncacheable.
- *
- * @var bool
- */
- protected $submitted = FALSE;
- /**
- * If TRUE, the form was submitted and has been processed and executed.
- *
- * This property is uncacheable.
- *
- * @var bool
- */
- protected $executed = FALSE;
- /**
- * The form element that triggered submission, which may or may not be a
- * button (in the case of Ajax forms). This key is often used to distinguish
- * between various buttons in a submit handler, and is also used in Ajax
- * handlers.
- *
- * This property is uncacheable.
- *
- * @var array|null
- */
- protected $triggering_element;
- /**
- * If TRUE, there is a file element and Form API will set the appropriate
- * 'enctype' HTML attribute on the form.
- *
- * @var bool
- */
- protected $has_file_element;
- /**
- * Contains references to details elements to render them within vertical tabs.
- *
- * This property is uncacheable.
- *
- * @var array
- */
- protected $groups = [];
- /**
- * This is not a special key, and no specific support is provided for it in
- * the Form API. By tradition it was the location where application-specific
- * data was stored for communication between the submit, validation, and form
- * builder functions, especially in a multi-step-style form. Form
- * implementations may use any key(s) within $form_state (other than the keys
- * listed here and other reserved ones used by Form API internals) for this
- * kind of storage. The recommended way to ensure that the chosen key doesn't
- * conflict with ones used by the Form API or other modules is to use the
- * module name as the key name or a prefix for the key name. For example, the
- * entity form classes use $this->entity in entity forms, or
- * $form_state->getFormObject()->getEntity() outside the controller, to store
- * information about the entity being edited, and this information stays
- * available across successive clicks of the "Preview" button (if available)
- * as well as when the "Save" button is finally clicked.
- *
- * @var array
- */
- protected $storage = [];
- /**
- * A list containing copies of all submit and button elements in the form.
- *
- * This property is uncacheable.
- *
- * @var array
- */
- protected $buttons = [];
- /**
- * Holds temporary data accessible during the current page request only.
- *
- * All $form_state properties that are not reserved keys (see
- * other properties marked as uncacheable) persist throughout a multistep form
- * sequence. Form API provides this key for modules to communicate information
- * across form-related functions during a single page request. It may be used
- * to temporarily save data that does not need to or should not be cached
- * during the whole form workflow; e.g., data that needs to be accessed during
- * the current form build process only. There is no use-case for this
- * functionality in Drupal core.
- *
- * This property is uncacheable.
- *
- * @var array
- */
- protected $temporary = [];
- /**
- * Tracks if the form has finished validation.
- *
- * This property is uncacheable.
- *
- * @var bool
- */
- protected $validation_complete = FALSE;
- /**
- * Contains errors for this form.
- *
- * This property is uncacheable.
- *
- * @var array
- */
- protected $errors = [];
- /**
- * Stores which errors should be limited during validation.
- *
- * An array of "sections" within which user input must be valid. If the
- * element is within one of these sections, the error must be recorded.
- * Otherwise, it can be suppressed. self::$limit_validation_errors can be an
- * empty array, in which case all errors are suppressed. For example, a
- * "Previous" button might want its submit action to be triggered even if none
- * of the submitted values are valid.
- *
- * This property is uncacheable.
- *
- * @var array|null
- */
- protected $limit_validation_errors;
- /**
- * Stores the gathered validation handlers.
- *
- * This property is uncacheable.
- *
- * @var array
- */
- protected $validate_handlers = [];
- /**
- * Stores the gathered submission handlers.
- *
- * This property is uncacheable.
- *
- * @var array
- */
- protected $submit_handlers = [];
- /**
- * {@inheritdoc}
- */
- public function setFormState(array $form_state_additions) {
- foreach ($form_state_additions as $key => $value) {
- if (property_exists($this, $key)) {
- $this->{$key} = $value;
- }
- else {
- $this->set($key, $value);
- }
- }
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function setAlwaysProcess($always_process = TRUE) {
- $this->always_process = (bool) $always_process;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getAlwaysProcess() {
- return $this->always_process;
- }
- /**
- * {@inheritdoc}
- */
- public function setButtons(array $buttons) {
- $this->buttons = $buttons;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getButtons() {
- return $this->buttons;
- }
- /**
- * {@inheritdoc}
- */
- public function setCached($cache = TRUE) {
- // Persisting $form_state is a side-effect disallowed during a "safe" HTTP
- // method.
- if ($cache && $this->isRequestMethodSafe()) {
- throw new \LogicException(sprintf('Form state caching on %s requests is not allowed.', $this->requestMethod));
- }
- $this->cache = (bool) $cache;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function isCached() {
- return empty($this->no_cache) && $this->cache;
- }
- /**
- * {@inheritdoc}
- */
- public function disableCache() {
- $this->no_cache = TRUE;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function setExecuted() {
- $this->executed = TRUE;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function isExecuted() {
- return $this->executed;
- }
- /**
- * {@inheritdoc}
- */
- public function setGroups(array $groups) {
- $this->groups = $groups;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function &getGroups() {
- return $this->groups;
- }
- /**
- * {@inheritdoc}
- */
- public function setHasFileElement($has_file_element = TRUE) {
- $this->has_file_element = (bool) $has_file_element;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function hasFileElement() {
- return $this->has_file_element;
- }
- /**
- * {@inheritdoc}
- */
- public function setLimitValidationErrors($limit_validation_errors) {
- $this->limit_validation_errors = $limit_validation_errors;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getLimitValidationErrors() {
- return $this->limit_validation_errors;
- }
- /**
- * {@inheritdoc}
- */
- public function setMethod($method) {
- $this->method = strtoupper($method);
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function isMethodType($method_type) {
- return $this->method === strtoupper($method_type);
- }
- /**
- * {@inheritdoc}
- */
- public function setRequestMethod($method) {
- $this->requestMethod = strtoupper($method);
- return $this;
- }
- /**
- * Checks whether the request method is a "safe" HTTP method.
- *
- * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1 defines
- * GET and HEAD as "safe" methods, meaning they SHOULD NOT have side-effects,
- * such as persisting $form_state changes.
- *
- * @return bool
- *
- * @see \Symfony\Component\HttpFoundation\Request::isMethodSafe()
- */
- protected function isRequestMethodSafe() {
- return in_array($this->requestMethod, ['GET', 'HEAD']);
- }
- /**
- * {@inheritdoc}
- */
- public function setValidationEnforced($must_validate = TRUE) {
- $this->must_validate = (bool) $must_validate;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function isValidationEnforced() {
- return $this->must_validate;
- }
- /**
- * {@inheritdoc}
- */
- public function disableRedirect($no_redirect = TRUE) {
- $this->no_redirect = (bool) $no_redirect;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function isRedirectDisabled() {
- return $this->no_redirect;
- }
- /**
- * {@inheritdoc}
- */
- public function setProcessInput($process_input = TRUE) {
- $this->process_input = (bool) $process_input;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function isProcessingInput() {
- return $this->process_input;
- }
- /**
- * {@inheritdoc}
- */
- public function setProgrammed($programmed = TRUE) {
- $this->programmed = (bool) $programmed;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function isProgrammed() {
- return $this->programmed;
- }
- /**
- * {@inheritdoc}
- */
- public function setProgrammedBypassAccessCheck($programmed_bypass_access_check = TRUE) {
- $this->programmed_bypass_access_check = (bool) $programmed_bypass_access_check;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function isBypassingProgrammedAccessChecks() {
- return $this->programmed_bypass_access_check;
- }
- /**
- * {@inheritdoc}
- */
- public function setRebuildInfo(array $rebuild_info) {
- $this->rebuild_info = $rebuild_info;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getRebuildInfo() {
- return $this->rebuild_info;
- }
- /**
- * {@inheritdoc}
- */
- public function addRebuildInfo($property, $value) {
- $rebuild_info = $this->getRebuildInfo();
- $rebuild_info[$property] = $value;
- $this->setRebuildInfo($rebuild_info);
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function setStorage(array $storage) {
- $this->storage = $storage;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function &getStorage() {
- return $this->storage;
- }
- /**
- * {@inheritdoc}
- */
- public function setSubmitHandlers(array $submit_handlers) {
- $this->submit_handlers = $submit_handlers;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getSubmitHandlers() {
- return $this->submit_handlers;
- }
- /**
- * {@inheritdoc}
- */
- public function setSubmitted() {
- $this->submitted = TRUE;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function isSubmitted() {
- return $this->submitted;
- }
- /**
- * {@inheritdoc}
- */
- public function setTemporary(array $temporary) {
- $this->temporary = $temporary;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getTemporary() {
- return $this->temporary;
- }
- /**
- * {@inheritdoc}
- */
- public function &getTemporaryValue($key) {
- $value = &NestedArray::getValue($this->temporary, (array) $key);
- return $value;
- }
- /**
- * {@inheritdoc}
- */
- public function setTemporaryValue($key, $value) {
- NestedArray::setValue($this->temporary, (array) $key, $value, TRUE);
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function hasTemporaryValue($key) {
- $exists = NULL;
- NestedArray::getValue($this->temporary, (array) $key, $exists);
- return $exists;
- }
- /**
- * {@inheritdoc}
- */
- public function setTriggeringElement($triggering_element) {
- $this->triggering_element = $triggering_element;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function &getTriggeringElement() {
- return $this->triggering_element;
- }
- /**
- * {@inheritdoc}
- */
- public function setValidateHandlers(array $validate_handlers) {
- $this->validate_handlers = $validate_handlers;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getValidateHandlers() {
- return $this->validate_handlers;
- }
- /**
- * {@inheritdoc}
- */
- public function setValidationComplete($validation_complete = TRUE) {
- $this->validation_complete = (bool) $validation_complete;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function isValidationComplete() {
- return $this->validation_complete;
- }
- /**
- * {@inheritdoc}
- */
- public function loadInclude($module, $type, $name = NULL) {
- if (!isset($name)) {
- $name = $module;
- }
- $build_info = $this->getBuildInfo();
- if (!isset($build_info['files']["$module:$name.$type"])) {
- // Only add successfully included files to the form state.
- if ($result = $this->moduleLoadInclude($module, $type, $name)) {
- $build_info['files']["$module:$name.$type"] = [
- 'type' => $type,
- 'module' => $module,
- 'name' => $name,
- ];
- $this->setBuildInfo($build_info);
- return $result;
- }
- }
- return FALSE;
- }
- /**
- * {@inheritdoc}
- */
- public function getCacheableArray() {
- return [
- 'build_info' => $this->getBuildInfo(),
- 'response' => $this->getResponse(),
- 'programmed' => $this->isProgrammed(),
- 'programmed_bypass_access_check' => $this->isBypassingProgrammedAccessChecks(),
- 'process_input' => $this->isProcessingInput(),
- 'has_file_element' => $this->hasFileElement(),
- 'storage' => $this->getStorage(),
- // Use the properties directly, since self::isCached() combines them and
- // cannot be relied upon.
- 'cache' => $this->cache,
- 'no_cache' => $this->no_cache,
- ];
- }
- /**
- * {@inheritdoc}
- */
- public function setCompleteForm(array &$complete_form) {
- $this->complete_form = &$complete_form;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function &getCompleteForm() {
- return $this->complete_form;
- }
- /**
- * {@inheritdoc}
- */
- public function &get($property) {
- $value = &NestedArray::getValue($this->storage, (array) $property);
- return $value;
- }
- /**
- * {@inheritdoc}
- */
- public function set($property, $value) {
- NestedArray::setValue($this->storage, (array) $property, $value, TRUE);
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function has($property) {
- $exists = NULL;
- NestedArray::getValue($this->storage, (array) $property, $exists);
- return $exists;
- }
- /**
- * {@inheritdoc}
- */
- public function setBuildInfo(array $build_info) {
- $this->build_info = $build_info;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getBuildInfo() {
- return $this->build_info;
- }
- /**
- * {@inheritdoc}
- */
- public function addBuildInfo($property, $value) {
- $build_info = $this->getBuildInfo();
- $build_info[$property] = $value;
- $this->setBuildInfo($build_info);
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function &getUserInput() {
- return $this->input;
- }
- /**
- * {@inheritdoc}
- */
- public function setUserInput(array $user_input) {
- $this->input = $user_input;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function &getValues() {
- return $this->values;
- }
- /**
- * {@inheritdoc}
- */
- public function setResponse(Response $response) {
- $this->response = $response;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getResponse() {
- return $this->response;
- }
- /**
- * {@inheritdoc}
- */
- public function setRedirect($route_name, array $route_parameters = [], array $options = []) {
- $url = new Url($route_name, $route_parameters, $options);
- return $this->setRedirectUrl($url);
- }
- /**
- * {@inheritdoc}
- */
- public function setRedirectUrl(Url $url) {
- $this->redirect = $url;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getRedirect() {
- // Skip redirection for form submissions invoked via
- // \Drupal\Core\Form\FormBuilderInterface::submitForm().
- if ($this->isProgrammed()) {
- return FALSE;
- }
- // Skip redirection if rebuild is activated.
- if ($this->isRebuilding()) {
- return FALSE;
- }
- // Skip redirection if it was explicitly disallowed.
- if ($this->isRedirectDisabled()) {
- return FALSE;
- }
- return $this->redirect;
- }
- /**
- * Sets the global status of errors.
- *
- * @param bool $errors
- * TRUE if any form has any errors, FALSE otherwise.
- */
- protected static function setAnyErrors($errors = TRUE) {
- static::$anyErrors = $errors;
- }
- /**
- * {@inheritdoc}
- */
- public static function hasAnyErrors() {
- return static::$anyErrors;
- }
- /**
- * {@inheritdoc}
- */
- public function setErrorByName($name, $message = '') {
- if ($this->isValidationComplete()) {
- throw new \LogicException('Form errors cannot be set after form validation has finished.');
- }
- $errors = $this->getErrors();
- if (!isset($errors[$name])) {
- $record = TRUE;
- $limit_validation_errors = $this->getLimitValidationErrors();
- if ($limit_validation_errors !== NULL) {
- $record = FALSE;
- foreach ($limit_validation_errors as $section) {
- // Exploding by '][' reconstructs the element's #parents. If the
- // reconstructed #parents begin with the same keys as the specified
- // section, then the element's values are within the part of
- // $form_state->getValues() that the clicked button requires to be
- // valid, so errors for this element must be recorded. As the exploded
- // array will all be strings, we need to cast every value of the
- // section array to string.
- if (array_slice(explode('][', $name), 0, count($section)) === array_map('strval', $section)) {
- $record = TRUE;
- break;
- }
- }
- }
- if ($record) {
- $errors[$name] = $message;
- $this->errors = $errors;
- static::setAnyErrors();
- }
- }
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function setError(array &$element, $message = '') {
- $this->setErrorByName(implode('][', $element['#parents']), $message);
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function clearErrors() {
- $this->errors = [];
- static::setAnyErrors(FALSE);
- }
- /**
- * {@inheritdoc}
- */
- public function getError(array $element) {
- if ($errors = $this->getErrors()) {
- $parents = [];
- foreach ($element['#parents'] as $parent) {
- $parents[] = $parent;
- $key = implode('][', $parents);
- if (isset($errors[$key])) {
- return $errors[$key];
- }
- }
- }
- }
- /**
- * {@inheritdoc}
- */
- public function getErrors() {
- return $this->errors;
- }
- /**
- * {@inheritdoc}
- */
- public function setRebuild($rebuild = TRUE) {
- $this->rebuild = $rebuild;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function isRebuilding() {
- return $this->rebuild;
- }
- /**
- * {@inheritdoc}
- */
- public function prepareCallback($callback) {
- if (is_string($callback) && substr($callback, 0, 2) == '::') {
- $callback = [$this->getFormObject(), substr($callback, 2)];
- }
- return $callback;
- }
- /**
- * {@inheritdoc}
- */
- public function setFormObject(FormInterface $form_object) {
- $this->addBuildInfo('callback_object', $form_object);
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getFormObject() {
- return $this->getBuildInfo()['callback_object'];
- }
- /**
- * {@inheritdoc}
- */
- public function getCleanValueKeys() {
- return $this->cleanValueKeys;
- }
- /**
- * {@inheritdoc}
- */
- public function setCleanValueKeys(array $cleanValueKeys) {
- $this->cleanValueKeys = $cleanValueKeys;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function addCleanValueKey($cleanValueKey) {
- $keys = $this->getCleanValueKeys();
- $this->setCleanValueKeys(array_merge((array) $keys, [$cleanValueKey]));
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function cleanValues() {
- foreach ($this->getCleanValueKeys() as $value) {
- $this->unsetValue($value);
- }
- // Remove button values.
- // \Drupal::formBuilder()->doBuildForm() collects all button elements in a
- // form. We remove the button value separately for each button element.
- foreach ($this->getButtons() as $button) {
- // Remove this button's value from the submitted form values by finding
- // the value corresponding to this button.
- // We iterate over the #parents of this button and move a reference to
- // each parent in self::getValues(). For example, if #parents is:
- // array('foo', 'bar', 'baz')
- // then the corresponding self::getValues() part will look like this:
- // array(
- // 'foo' => array(
- // 'bar' => array(
- // 'baz' => 'button_value',
- // ),
- // ),
- // )
- // We start by (re)moving 'baz' to $last_parent, so we are able unset it
- // at the end of the iteration. Initially, $values will contain a
- // reference to self::getValues(), but in the iteration we move the
- // reference to self::getValue('foo'), and finally to
- // self::getValue(array('foo', 'bar')), which is the level where we
- // can unset 'baz' (that is stored in $last_parent).
- $parents = $button['#parents'];
- $last_parent = array_pop($parents);
- $key_exists = NULL;
- $values = &NestedArray::getValue($this->getValues(), $parents, $key_exists);
- if ($key_exists && is_array($values)) {
- unset($values[$last_parent]);
- }
- }
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function setInvalidToken($invalid_token) {
- $this->invalidToken = (bool) $invalid_token;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function hasInvalidToken() {
- return $this->invalidToken;
- }
- /**
- * Wraps ModuleHandler::loadInclude().
- */
- protected function moduleLoadInclude($module, $type, $name = NULL) {
- return \Drupal::moduleHandler()->loadInclude($module, $type, $name);
- }
- }
|