From ee6ddbe8acc85103ad210ef0259fbe279067e0b5 Mon Sep 17 00:00:00 2001 From: Alex Pott <alex.a.pott@googlemail.com> Date: Wed, 10 Sep 2014 09:53:11 +0100 Subject: [PATCH] Issue #2332389 by tim.plunkett: Finish adding methods to FormStateInterface. --- core/includes/install.core.inc | 11 +- core/lib/Drupal/Core/Block/BlockBase.php | 10 +- .../Drupal/Core/Entity/EntityFormBuilder.php | 6 +- .../Drupal/Core/Form/BaseFormIdInterface.php | 2 +- core/lib/Drupal/Core/Form/FormBuilder.php | 146 ++--- .../Drupal/Core/Form/FormBuilderInterface.php | 22 +- core/lib/Drupal/Core/Form/FormCache.php | 12 +- core/lib/Drupal/Core/Form/FormState.php | 561 ++++++++++++++---- .../Drupal/Core/Form/FormStateInterface.php | 518 +++++++++++++++- core/lib/Drupal/Core/Form/FormSubmitter.php | 19 +- core/lib/Drupal/Core/Form/FormValidator.php | 47 +- .../Core/Form/FormValidatorInterface.php | 2 +- .../AggregatorPluginSettingsBaseTest.php | 5 +- core/modules/block/src/BlockForm.php | 8 +- .../src/Form/ConfigSingleExportForm.php | 4 +- .../image/src/Form/ImageEffectFormBase.php | 8 +- core/modules/menu_ui/src/MenuForm.php | 5 +- .../quickedit/src/QuickEditController.php | 11 +- .../src/Form/SimpletestResultsForm.php | 2 +- .../src/Tests/Element/PathElementFormTest.php | 21 +- .../Tests/Form/FormDefaultHandlersTest.php | 2 +- .../src/Tests/Form/ProgrammaticTest.php | 6 +- .../Tests/System/SystemConfigFormTestBase.php | 2 +- .../src/Controller/BatchTestController.php | 6 +- core/modules/views/includes/ajax.inc | 14 +- .../exposed_form/ExposedFormPluginBase.php | 17 +- .../Tests/Wizard/WizardPluginBaseUnitTest.php | 4 +- .../views_ui/src/Form/Ajax/ViewsFormBase.php | 24 +- .../Tests/Core/Form/FormBuilderTest.php | 35 +- .../Drupal/Tests/Core/Form/FormCacheTest.php | 2 +- .../Drupal/Tests/Core/Form/FormStateTest.php | 143 ++++- .../Tests/Core/Form/FormSubmitterTest.php | 28 +- .../Drupal/Tests/Core/Form/FormTestBase.php | 17 +- .../Tests/Core/Form/FormValidatorTest.php | 28 +- 34 files changed, 1323 insertions(+), 425 deletions(-) diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 67b7dffd1555..7d23bb9223bb 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -806,12 +806,9 @@ function install_tasks_to_display($install_state) { function install_get_form($form_id, array &$install_state) { // Ensure the form will not redirect, since install_run_tasks() uses a custom // redirection logic. - $form_state = new FormState(array( - 'build_info' => array( - 'args' => array(&$install_state), - ), - 'no_redirect' => TRUE, - )); + $form_state = (new FormState()) + ->addBuildInfo('args', [&$install_state]) + ->disableRedirect(); $form_builder = \Drupal::formBuilder(); if ($install_state['interactive']) { $form = $form_builder->buildForm($form_id, $form_state); @@ -827,7 +824,7 @@ function install_get_form($form_id, array &$install_state) { // values taken from the installation state. $install_form_id = $form_builder->getFormId($form_id, $form_state); if (!empty($install_state['forms'][$install_form_id])) { - $form_state->set('values', $install_state['forms'][$install_form_id]); + $form_state->setValues($install_state['forms'][$install_form_id]); } $form_builder->submitForm($form_id, $form_state); diff --git a/core/lib/Drupal/Core/Block/BlockBase.php b/core/lib/Drupal/Core/Block/BlockBase.php index 7d66cf4cac0d..c9db77a2054f 100644 --- a/core/lib/Drupal/Core/Block/BlockBase.php +++ b/core/lib/Drupal/Core/Block/BlockBase.php @@ -356,9 +356,8 @@ public function validateConfigurationForm(array &$form, FormStateInterface $form foreach ($this->getVisibilityConditions() as $condition_id => $condition) { // Allow the condition to validate the form. - $condition_values = new FormState(array( - 'values' => $form_state->getValue(array('visibility', $condition_id)), - )); + $condition_values = (new FormState()) + ->setValues($form_state->getValue(['visibility', $condition_id])); $condition->validateConfigurationForm($form, $condition_values); // Update the original form values. $form_state->setValue(array('visibility', $condition_id), $condition_values['values']); @@ -389,9 +388,8 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s $this->configuration['cache'] = $form_state->getValue('cache'); foreach ($this->getVisibilityConditions() as $condition_id => $condition) { // Allow the condition to submit the form. - $condition_values = new FormState(array( - 'values' => $form_state->getValue(array('visibility', $condition_id)), - )); + $condition_values = (new FormState()) + ->setValues($form_state->getValue(['visibility', $condition_id])); $condition->submitConfigurationForm($form, $condition_values); // Update the original form values. $form_state->setValue(array('visibility', $condition_id), $condition_values['values']); diff --git a/core/lib/Drupal/Core/Entity/EntityFormBuilder.php b/core/lib/Drupal/Core/Entity/EntityFormBuilder.php index 3a825be7b1ab..e12d27905c07 100644 --- a/core/lib/Drupal/Core/Entity/EntityFormBuilder.php +++ b/core/lib/Drupal/Core/Entity/EntityFormBuilder.php @@ -49,11 +49,7 @@ public function getForm(EntityInterface $entity, $operation = 'default', array $ $form_object = $this->entityManager->getFormObject($entity->getEntityTypeId(), $operation); $form_object->setEntity($entity); - $form_state = new FormState($form_state_additions); - $form_state['build_info']['callback_object'] = $form_object; - $form_state['build_info']['base_form_id'] = $form_object->getBaseFormID(); - $form_state['build_info'] += array('args' => array()); - + $form_state = (new FormState())->setFormState($form_state_additions); return $this->formBuilder->buildForm($form_object, $form_state); } diff --git a/core/lib/Drupal/Core/Form/BaseFormIdInterface.php b/core/lib/Drupal/Core/Form/BaseFormIdInterface.php index 3576758e84d3..c6710c2119da 100644 --- a/core/lib/Drupal/Core/Form/BaseFormIdInterface.php +++ b/core/lib/Drupal/Core/Form/BaseFormIdInterface.php @@ -10,7 +10,7 @@ /** * Provides an interface for a Form that has a base form ID. * - * This will become the $form_state['build_info']['base_form_id'] used to + * This will become the $form_state->getBaseInfo()['base_form_id'] used to * generate the name of hook_form_BASE_FORM_ID_alter(). */ interface BaseFormIdInterface extends FormInterface { diff --git a/core/lib/Drupal/Core/Form/FormBuilder.php b/core/lib/Drupal/Core/Form/FormBuilder.php index 3417549bb284..9fb4112b4cac 100644 --- a/core/lib/Drupal/Core/Form/FormBuilder.php +++ b/core/lib/Drupal/Core/Form/FormBuilder.php @@ -157,7 +157,7 @@ public function getFormId($form_arg, FormStateInterface &$form_state) { } // Add the $form_arg as the callback object and determine the form ID. - $form_state->addBuildInfo('callback_object', $form_arg); + $form_state->setFormObject($form_arg); if ($form_arg instanceof BaseFormIdInterface) { $form_state->addBuildInfo('base_form_id', $form_arg->getBaseFormID()); } @@ -188,7 +188,7 @@ public function buildForm($form_id, FormStateInterface &$form_state) { $input = $form_state->getUserInput(); if (!isset($input)) { $request = $this->requestStack->getCurrentRequest(); - $input = $form_state['method'] == 'get' ? $request->query->all() : $request->request->all(); + $input = $form_state->isMethodType('get') ? $request->query->all() : $request->request->all(); $form_state->setUserInput($input); } @@ -227,7 +227,7 @@ public function buildForm($form_id, FormStateInterface &$form_state) { // self::setCache() removes uncacheable $form_state keys (see properties // in \Drupal\Core\Form\FormState) in order for multi-step forms to work // properly. This means that form processing logic for single-step forms - // using $form_state['cache'] may depend on data stored in those keys + // using $form_state->isCached() may depend on data stored in those keys // during self::retrieveForm()/self::prepareForm(), but form processing // should not depend on whether the form is cached or not, so $form_state // is adjusted to match what it would be after a @@ -239,7 +239,9 @@ public function buildForm($form_id, FormStateInterface &$form_state) { // - temporary: Any assigned data is expected to survives within the same // page request. if ($check_cache) { - $cache_form_state = $form_state->getCacheableArray(array('always_process', 'temporary')); + $cache_form_state = $form_state->getCacheableArray(); + $cache_form_state['always_process'] = $form_state->getAlwaysProcess(); + $cache_form_state['temporary'] = $form_state->getTemporary(); $form_state = $form_state_before_retrieval; $form_state->setFormState($cache_form_state); } @@ -280,6 +282,8 @@ public function buildForm($form_id, FormStateInterface &$form_state) { */ public function rebuildForm($form_id, FormStateInterface &$form_state, $old_form = NULL) { $form = $this->retrieveForm($form_id, $form_state); + // All rebuilt forms will be cached. + $form_state->setCached(); // If only parts of the form will be returned to the browser (e.g., Ajax or // RIA clients), re-use the old #build_id to not require client-side code to @@ -288,7 +292,8 @@ public function rebuildForm($form_id, FormStateInterface &$form_state, $old_form // build's data in the form cache; also allowing the user to go back to an // earlier build, make changes, and re-submit. // @see self::prepareForm() - if (isset($old_form['#build_id']) && !empty($form_state['rebuild_info']['copy']['#build_id'])) { + $rebuild_info = $form_state->getRebuildInfo(); + if (isset($old_form['#build_id']) && !empty($rebuild_info['copy']['#build_id'])) { $form['#build_id'] = $old_form['#build_id']; } else { @@ -298,7 +303,7 @@ public function rebuildForm($form_id, FormStateInterface &$form_state, $old_form // #action defaults to request_uri(), but in case of Ajax and other partial // rebuilds, the form is submitted to an alternate URL, and the original // #action needs to be retained. - if (isset($old_form['#action']) && !empty($form_state['rebuild_info']['copy']['#action'])) { + if (isset($old_form['#action']) && !empty($rebuild_info['copy']['#action'])) { $form['#action'] = $old_form['#action']; } @@ -308,13 +313,13 @@ public function rebuildForm($form_id, FormStateInterface &$form_state, $old_form // cached is the $form structure before it passes through // self::doBuildForm(), so we need to do it here. // @todo For Drupal 8, find a way to avoid this code duplication. - if (empty($form_state['no_cache'])) { + if ($form_state->isCached()) { $this->setCache($form['#build_id'], $form, $form_state); } // Clear out all group associations as these might be different when // re-rendering the form. - $form_state->set('groups', array()); + $form_state->setGroups([]); // Return a fully built form that is ready for rendering. return $this->doBuildForm($form_id, $form, $form_state); @@ -338,7 +343,8 @@ public function setCache($form_build_id, $form, FormStateInterface $form_state) * {@inheritdoc} */ public function submitForm($form_arg, FormStateInterface &$form_state) { - if (!isset($form_state['build_info']['args'])) { + $build_info = $form_state->getBuildInfo(); + if (empty($build_info['args'])) { $args = func_get_args(); // Remove $form and $form_state from the arguments. unset($args[0], $args[1]); @@ -351,15 +357,15 @@ public function submitForm($form_arg, FormStateInterface &$form_state) { // there). $form_state->setUserInput($form_state->getValues()); - $form_state->set('programmed', TRUE); + $form_state->setProgrammed(); $form_id = $this->getFormId($form_arg, $form_state); $form = $this->retrieveForm($form_id, $form_state); // Programmed forms are always submitted. - $form_state->set('submitted', TRUE); + $form_state->setSubmitted(); // Reset form validation. - $form_state->set('must_validate', TRUE); + $form_state->setValidationEnforced(); $form_state->clearErrors(); $this->prepareForm($form_id, $form, $form_state); @@ -376,9 +382,10 @@ public function retrieveForm($form_id, FormStateInterface &$form_state) { // We save two copies of the incoming arguments: one for modules to use // when mapping form ids to constructor functions, and another to pass to // the constructor function itself. - $args = $form_state['build_info']['args']; + $build_info = $form_state->getBuildInfo(); + $args = $build_info['args']; - $callback = array($form_state['build_info']['callback_object'], 'buildForm'); + $callback = [$form_state->getFormObject(), 'buildForm']; $form = array(); // Assign a default CSS class name based on $form_id. @@ -386,8 +393,8 @@ public function retrieveForm($form_id, FormStateInterface &$form_state) { // form constructor function to override or remove the default class. $form['#attributes']['class'][] = Html::getClass($form_id); // Same for the base form ID, if any. - if (isset($form_state['build_info']['base_form_id'])) { - $form['#attributes']['class'][] = Html::getClass($form_state['build_info']['base_form_id']); + if (isset($build_info['base_form_id'])) { + $form['#attributes']['class'][] = Html::getClass($build_info['base_form_id']); } // We need to pass $form_state by reference in order for forms to modify it, @@ -410,10 +417,10 @@ public function retrieveForm($form_id, FormStateInterface &$form_state) { * {@inheritdoc} */ public function processForm($form_id, &$form, FormStateInterface &$form_state) { - $form_state->set('values', array()); + $form_state->setValues([]); // With GET, these forms are always submitted if requested. - if ($form_state['method'] == 'get' && !empty($form_state['always_process'])) { + if ($form_state->isMethodType('get') && $form_state->getAlwaysProcess()) { $input = $form_state->getUserInput(); if (!isset($input['form_build_id'])) { $input['form_build_id'] = $form['#build_id']; @@ -435,7 +442,7 @@ public function processForm($form_id, &$form, FormStateInterface &$form_state) { $form = $this->doBuildForm($form_id, $form, $form_state); // Only process the input if we have a correct form submission. - if ($form_state['process_input']) { + if ($form_state->isProcessingInput()) { // Form constructors may explicitly set #token to FALSE when cross site // request forgery is irrelevant to the form, such as search forms. if (isset($form['#token']) && $form['#token'] === FALSE) { @@ -447,8 +454,9 @@ public function processForm($form_id, &$form, FormStateInterface &$form_state) { // submit button is not taken account. Therefore, check whether there is // exactly one submit button in the form, and if so, automatically use it // as triggering_element. - if ($form_state['programmed'] && !isset($form_state['triggering_element']) && count($form_state['buttons']) == 1) { - $form_state->set('triggering_element', reset($form_state['buttons'])); + $buttons = $form_state->getButtons(); + if ($form_state->isProgrammed() && !$form_state->getTriggeringElement() && count($buttons) == 1) { + $form_state->setTriggeringElement(reset($buttons)); } $this->formValidator->validateForm($form_id, $form, $form_state); @@ -462,35 +470,35 @@ public function processForm($form_id, &$form, FormStateInterface &$form_state) { Html::resetSeenIds(); } - if (!$form_state['rebuild'] && !FormState::hasAnyErrors()) { + if (!$form_state->isRebuilding() && !FormState::hasAnyErrors()) { if ($submit_response = $this->formSubmitter->doSubmitForm($form, $form_state)) { return $submit_response; } } // Don't rebuild or cache form submissions invoked via self::submitForm(). - if (!empty($form_state['programmed'])) { + if ($form_state->isProgrammed()) { return; } - // If $form_state['rebuild'] has been set and input has been processed + // If $form_state->isRebuilding() has been set and input has been processed // without validation errors, we are in a multi-step workflow that is not // yet complete. A new $form needs to be constructed based on the changes // made to $form_state during this request. Normally, a submit handler - // sets $form_state['rebuild'] if a fully executed form requires another - // step. However, for forms that have not been fully executed (e.g., Ajax - // submissions triggered by non-buttons), there is no submit handler to - // set $form_state['rebuild']. It would not make sense to redisplay the - // identical form without an error for the user to correct, so we also - // rebuild error-free non-executed forms, regardless of - // $form_state['rebuild']. + // sets $form_state->isRebuilding() if a fully executed form requires + // another step. However, for forms that have not been fully executed + // (e.g., Ajax submissions triggered by non-buttons), there is no submit + // handler to set $form_state->isRebuilding(). It would not make sense to + // redisplay the identical form without an error for the user to correct, + // so we also rebuild error-free non-executed forms, regardless of + // $form_state->isRebuilding(). // @todo Simplify this logic; considering Ajax and non-HTML front-ends, // along with element-level #submit properties, it makes no sense to // have divergent form execution based on whether the triggering element // has #executes_submit_callback set to TRUE. - if (($form_state['rebuild'] || !$form_state['executed']) && !FormState::hasAnyErrors()) { + if (($form_state->isRebuilding() || !$form_state->isExecuted()) && !FormState::hasAnyErrors()) { // Form building functions (e.g., self::handleInputElement()) may use - // $form_state['rebuild'] to determine if they are running in the + // $form_state->isRebuilding() to determine if they are running in the // context of a rebuild, so ensure it is set. $form_state->setRebuild(); $form = $this->rebuildForm($form_id, $form_state, $form); @@ -498,13 +506,13 @@ public function processForm($form_id, &$form, FormStateInterface &$form_state) { } // After processing the form, the form builder or a #process callback may - // have set $form_state['cache'] to indicate that the form and form state - // shall be cached. But the form may only be cached if the 'no_cache' - // property is not set to TRUE. Only cache $form as it was prior to - // self::doBuildForm(), because self::doBuildForm() must run for each - // request to accommodate new user input. Rebuilt forms are not cached here, - // because self::rebuildForm() already takes care of that. - if (!$form_state['rebuild'] && $form_state['cache'] && empty($form_state['no_cache'])) { + // have called $form_state->setCached() to indicate that the form and form + // state shall be cached. But the form may only be cached if + // $form_state->disableCache() is not called. Only cache $form as it was + // prior to self::doBuildForm(), because self::doBuildForm() must run for + // each request to accommodate new user input. Rebuilt forms are not cached + // here, because self::rebuildForm() already takes care of that. + if (!$form_state->isRebuilding() && $form_state->isCached()) { $this->setCache($form['#build_id'], $unprocessed_form, $form_state); } } @@ -516,10 +524,9 @@ public function prepareForm($form_id, &$form, FormStateInterface &$form_state) { $user = $this->currentUser(); $form['#type'] = 'form'; - $form_state->set('programmed', isset($form_state['programmed']) ? $form_state['programmed'] : FALSE); // Fix the form method, if it is 'get' in $form_state, but not in $form. - if ($form_state->get('method') == 'get' && !isset($form['#method'])) { + if ($form_state->isMethodType('get') && !isset($form['#method'])) { $form['#method'] = 'get'; } @@ -551,7 +558,7 @@ public function prepareForm($form_id, &$form, FormStateInterface &$form_state) { // since tokens are session-bound and forms displayed to anonymous users are // very likely cached, we cannot assign a token for them. // During installation, there is no $user yet. - if ($user && $user->isAuthenticated() && !$form_state['programmed']) { + if ($user && $user->isAuthenticated() && !$form_state->isProgrammed()) { // Form constructors may explicitly set #token to FALSE when cross site // request forgery is irrelevant to the form, such as search forms. if (isset($form['#token']) && $form['#token'] === FALSE) { @@ -592,22 +599,23 @@ public function prepareForm($form_id, &$form, FormStateInterface &$form_state) { $form['#validate'][] = '::validateForm'; $form['#submit'][] = '::submitForm'; + $build_info = $form_state->getBuildInfo(); // If no #theme has been set, automatically apply theme suggestions. // theme_form() itself is in #theme_wrappers and not #theme. Therefore, the // #theme function only has to care for rendering the inner form elements, // not the form itself. if (!isset($form['#theme'])) { $form['#theme'] = array($form_id); - if (isset($form_state['build_info']['base_form_id'])) { - $form['#theme'][] = $form_state['build_info']['base_form_id']; + if (isset($build_info['base_form_id'])) { + $form['#theme'][] = $build_info['base_form_id']; } } // Invoke hook_form_alter(), hook_form_BASE_FORM_ID_alter(), and // hook_form_FORM_ID_alter() implementations. $hooks = array('form'); - if (isset($form_state['build_info']['base_form_id'])) { - $hooks[] = 'form_' . $form_state['build_info']['base_form_id']; + if (isset($build_info['base_form_id'])) { + $hooks[] = 'form_' . $build_info['base_form_id']; } $hooks[] = 'form_' . $form_id; $this->moduleHandler->alter($hooks, $form, $form_state, $form_id); @@ -690,11 +698,11 @@ public function doBuildForm($form_id, &$element, FormStateInterface &$form_state // for programmed forms coming from self::submitForm(), or if the form_id // coming from the POST data is set and matches the current form_id. $input = $form_state->getUserInput(); - if ($form_state['programmed'] || (!empty($input) && (isset($input['form_id']) && ($input['form_id'] == $form_id)))) { - $form_state->set('process_input', TRUE); + if ($form_state->isProgrammed() || (!empty($input) && (isset($input['form_id']) && ($input['form_id'] == $form_id)))) { + $form_state->setProcessInput(); } else { - $form_state->set('process_input', FALSE); + $form_state->setProcessInput(FALSE); } // All form elements should have an #array_parents property. @@ -791,14 +799,14 @@ public function doBuildForm($form_id, &$element, FormStateInterface &$form_state // If there is a file element, we need to flip a flag so later the // form encoding can be set. if (isset($element['#type']) && $element['#type'] == 'file') { - $form_state->set('has_file_element', TRUE); + $form_state->setHasFileElement(); } // Final tasks for the form element after self::doBuildForm() has run for // all other elements. if (isset($element['#type']) && $element['#type'] == 'form') { // If there is a file element, we set the form encoding. - if (isset($form_state['has_file_element'])) { + if ($form_state->hasFileElement()) { $element['#attributes']['enctype'] = 'multipart/form-data'; } @@ -808,24 +816,26 @@ public function doBuildForm($form_id, &$element, FormStateInterface &$form_state // though the user clicked the first button. Therefore, to be as // consistent as we can be across browsers, if no 'triggering_element' has // been identified yet, default it to the first button. - if (!$form_state['programmed'] && !isset($form_state['triggering_element']) && !empty($form_state['buttons'])) { - $form_state->set('triggering_element', $form_state['buttons'][0]); + $buttons = $form_state->getButtons(); + if (!$form_state->isProgrammed() && !$form_state->getTriggeringElement() && !empty($buttons)) { + $form_state->setTriggeringElement($buttons[0]); } - $triggering_element = $form_state->get('triggering_element'); + $triggering_element = $form_state->getTriggeringElement(); // If the triggering element specifies "button-level" validation and // submit handlers to run instead of the default form-level ones, then add // those to the form state. - foreach (array('validate', 'submit') as $type) { - if (isset($triggering_element['#' . $type])) { - $form_state->set($type . '_handlers', $triggering_element['#' . $type]); - } + if (isset($triggering_element['#validate'])) { + $form_state->setValidateHandlers($triggering_element['#validate']); + } + if (isset($triggering_element['#submit'])) { + $form_state->setSubmitHandlers($triggering_element['#submit']); } // If the triggering element executes submit handlers, then set the form // state key that's needed for those handlers to run. if (!empty($triggering_element['#executes_submit_callback'])) { - $form_state->set('submitted', TRUE); + $form_state->setSubmitted(); } // Special processing if the triggering element is a button. @@ -899,7 +909,7 @@ protected function handleInputElement($form_id, &$element, FormStateInterface &$ // #access=FALSE on an element usually allow access for some users, so forms // submitted with self::submitForm() may bypass access restriction and be // treated as high-privilege users instead. - $process_input = empty($element['#disabled']) && (($form_state['programmed'] && $form_state['programmed_bypass_access_check']) || ($form_state['process_input'] && (!isset($element['#access']) || $element['#access']))); + $process_input = empty($element['#disabled']) && (($form_state->isProgrammed() && $form_state->isBypassingProgrammedAccessChecks()) || ($form_state->isProcessingInput() && (!isset($element['#access']) || $element['#access']))); // Set the element's #value property. if (!isset($element['#value']) && !array_key_exists('#value', $element)) { @@ -925,7 +935,7 @@ protected function handleInputElement($form_id, &$element, FormStateInterface &$ // use default values for the latter, if required. Programmatically // submitted forms can submit explicit NULL values when calling // self::submitForm() so we do not modify FormState::$input for them. - if (!$input_exists && !$form_state['rebuild'] && !$form_state['programmed']) { + if (!$input_exists && !$form_state->isRebuilding() && !$form_state->isProgrammed()) { // Add the necessary parent keys to FormState::$input and sets the // element's input value to NULL. NestedArray::setValue($form_state->getUserInput(), $element['#parents'], NULL); @@ -967,7 +977,7 @@ protected function handleInputElement($form_id, &$element, FormStateInterface &$ if ($process_input) { // Detect if the element triggered the submission via Ajax. if ($this->elementTriggeredScriptedSubmission($element, $form_state)) { - $form_state->set('triggering_element', $element); + $form_state->setTriggeringElement($element); } // If the form was submitted by the browser rather than via Ajax, then it @@ -979,11 +989,11 @@ protected function handleInputElement($form_id, &$element, FormStateInterface &$ // form_state_values_clean() and for the self::doBuildForm() code that // handles a form submission containing no button information in // \Drupal::request()->request. - $buttons = $form_state->get('buttons'); + $buttons = $form_state->getButtons(); $buttons[] = $element; - $form_state->set('buttons', $buttons); + $form_state->setButtons($buttons); if ($this->buttonWasClicked($element, $form_state)) { - $form_state->set('triggering_element', $element); + $form_state->setTriggeringElement($element); } } } @@ -1031,10 +1041,10 @@ protected function elementTriggeredScriptedSubmission($element, FormStateInterfa * textfield (self::doBuildForm() has extra code for that). * * Because this function contains only part of the logic needed to determine - * $form_state['triggering_element'], it should not be called from anywhere + * $form_state->getTriggeringElement(), it should not be called from anywhere * other than within the Form API. Form validation and submit handlers needing * to know which button was clicked should get that information from - * $form_state['triggering_element']. + * $form_state->getTriggeringElement(). */ protected function buttonWasClicked($element, FormStateInterface &$form_state) { // First detect normal 'vanilla' button clicks. Traditionally, all standard diff --git a/core/lib/Drupal/Core/Form/FormBuilderInterface.php b/core/lib/Drupal/Core/Form/FormBuilderInterface.php index 3e97b495e867..43d2e9fcfcc9 100644 --- a/core/lib/Drupal/Core/Form/FormBuilderInterface.php +++ b/core/lib/Drupal/Core/Form/FormBuilderInterface.php @@ -42,7 +42,7 @@ public function getFormId($form_arg, FormStateInterface &$form_state); * function. For example, the node_edit form requires that a node object is * passed in here when it is called. These are available to implementations * of hook_form_alter() and hook_form_FORM_ID_alter() as the array - * $form_state['build_info']['args']. + * $form_state->getBuildInfo()['args']. * * @return array * The form array. @@ -79,10 +79,10 @@ public function buildForm($form_id, FormStateInterface &$form_state); * This is the key function for making multi-step forms advance from step to * step. It is called by self::processForm() when all user input processing, * including calling validation and submission handlers, for the request is - * finished. If a validate or submit handler set $form_state['rebuild'] to - * TRUE, and if other conditions don't preempt a rebuild from happening, then - * this function is called to generate a new $form, the next step in the form - * workflow, to be returned for rendering. + * finished. If a validate or submit handler set $form_state->isRebuilding() + * to TRUE, and if other conditions don't preempt a rebuild from happening, + * then this function is called to generate a new $form, the next step in the + * form workflow, to be returned for rendering. * * Ajax form submissions are almost always multi-step workflows, so that is * one common use-case during which form rebuilding occurs. See @@ -98,7 +98,7 @@ public function buildForm($form_id, FormStateInterface &$form_state); * (optional) A previously built $form. Used to retain the #build_id and * #action properties in Ajax callbacks and similar partial form rebuilds. * The only properties copied from $old_form are the ones which both exist - * in $old_form and for which $form_state['rebuild_info']['copy'][PROPERTY] + * in $old_form and for which $form_state->getRebuildInfo()['copy'][PROPERTY] * is TRUE. If $old_form is not passed, the entire $form is rebuilt freshly. * 'rebuild_info' needs to be a separate top-level property next to * 'build_info', since the contained data must not be cached. @@ -148,8 +148,8 @@ public function rebuildForm($form_id, FormStateInterface &$form_state, $old_form * @endcode * would be called via self::submitForm() as follows: * @code - * $form_state->set('values', $my_form_values); - * $form_state['build_info']['args'] = array(&$object); + * $form_state->setValues($my_form_values); + * $form_state->addBuildInfo('args', [&$object]); * drupal_form_submit('mymodule_form', $form_state); * @endcode * For example: @@ -161,7 +161,7 @@ public function rebuildForm($form_id, FormStateInterface &$form_state, $old_form * $values['pass']['pass1'] = 'password'; * $values['pass']['pass2'] = 'password'; * $values['op'] = t('Create new account'); - * $form_state->set('values', $values); + * $form_state->setValues($values); * drupal_form_submit('user_register_form', $form_state); * @endcode */ @@ -293,8 +293,8 @@ public function prepareForm($form_id, &$form, FormStateInterface &$form_state); * the next submission needs to be processed, a multi-step workflow is * needed. This is most commonly implemented with a submit handler setting * persistent data within $form_state based on *validated* values in - * $form_state->getValues() and setting $form_state['rebuild']. The form - * building functions must then be implemented to use the $form_state data + * $form_state->getValues() and checking $form_state->isRebuilding(). The + * form building functions must then be implemented to use the $form_state * to rebuild the form with the structure appropriate for the new state. * - Where user input must affect the rendering of the form without affecting * its structure, the necessary conditional rendering logic should reside diff --git a/core/lib/Drupal/Core/Form/FormCache.php b/core/lib/Drupal/Core/Form/FormCache.php index 9ba893de278a..93da48c45702 100644 --- a/core/lib/Drupal/Core/Form/FormCache.php +++ b/core/lib/Drupal/Core/Form/FormCache.php @@ -95,8 +95,9 @@ protected function loadCachedFormState($form_build_id, FormStateInterface $form_ // If the original form is contained in include files, load the files. // @see \Drupal\Core\Form\FormStateInterface::loadInclude() - $form_state['build_info'] += array('files' => array()); - foreach ($form_state['build_info']['files'] as $file) { + $build_info = $form_state->getBuildInfo(); + $build_info += ['files' => []]; + foreach ($build_info['files'] as $file) { if (is_array($file)) { $file += array('type' => 'inc', 'name' => $file['module']); $this->moduleHandler->loadInclude($file['module'], $file['type'], $file['name']); @@ -109,9 +110,10 @@ protected function loadCachedFormState($form_build_id, FormStateInterface $form_ // for this request. // @todo Ensure we are not storing an excessively large string list // in: https://www.drupal.org/node/2295823 - $form_state['build_info'] += array('safe_strings' => array()); - SafeMarkup::setMultiple($form_state['build_info']['safe_strings']); - unset($form_state['build_info']['safe_strings']); + $build_info += ['safe_strings' => []]; + SafeMarkup::setMultiple($build_info['safe_strings']); + unset($build_info['safe_strings']); + $form_state->setBuildInfo($build_info); } } diff --git a/core/lib/Drupal/Core/Form/FormState.php b/core/lib/Drupal/Core/Form/FormState.php index 5bed64a8070d..557ac0f7a7f8 100644 --- a/core/lib/Drupal/Core/Form/FormState.php +++ b/core/lib/Drupal/Core/Form/FormState.php @@ -25,13 +25,6 @@ class FormState implements FormStateInterface, \ArrayAccess { */ protected static $anyErrors = FALSE; - /** - * The internal storage of the form state. - * - * @var array - */ - protected $internalStorage = array(); - /** * The complete form structure. * @@ -92,12 +85,12 @@ class FormState implements FormStateInterface, \ArrayAccess { * 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, $form_state['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 $form_state['rebuild'] to cause the form processing - * to bypass submit handlers and rebuild the form instead, even if there are - * no validation errors. + * 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. * @@ -217,10 +210,6 @@ class FormState implements FormStateInterface, \ArrayAccess { /** * If TRUE and the method is GET, a form_id is not necessary. * - * This should only be used on RESTful GET forms that do NOT write data, as - * this could lead to security issues. It is useful so that searches do not - * need to have a form_id in their query arguments to trigger the search. - * * This property is uncacheable. * * @var bool @@ -383,6 +372,13 @@ class FormState implements FormStateInterface, \ArrayAccess { /** * 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 @@ -394,41 +390,367 @@ class FormState implements FormStateInterface, \ArrayAccess { * * This property is uncacheable. * - * @var array|null + * @var array */ - protected $validate_handlers; + protected $validate_handlers = []; /** * Stores the gathered submission handlers. * * This property is uncacheable. * - * @var array|null + * @var array */ - protected $submit_handlers; + protected $submit_handlers = []; /** - * Constructs a \Drupal\Core\Form\FormState object. - * - * @param array $form_state_additions - * (optional) An associative array used to build the current state of the - * form. Use this to pass additional information to the form, such as the - * langcode. Defaults to an empty array. + * {@inheritdoc} */ - public function __construct(array $form_state_additions = array()) { - $this->setFormState($form_state_additions); + 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 setFormState(array $form_state_additions) { - foreach ($form_state_additions as $key => $value) { - $this->set($key, $value); - } + 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) { + $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 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 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} */ @@ -436,7 +758,7 @@ public function loadInclude($module, $type, $name = NULL) { if (!isset($name)) { $name = $module; } - $build_info = $this->get('build_info'); + $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)) { @@ -445,7 +767,7 @@ public function loadInclude($module, $type, $name = NULL) { 'module' => $module, 'name' => $name, ); - $this->set('build_info', $build_info); + $this->setBuildInfo($build_info); return $result; } } @@ -455,22 +777,20 @@ public function loadInclude($module, $type, $name = NULL) { /** * {@inheritdoc} */ - public function getCacheableArray($allowed_keys = array()) { - $cacheable_array = array( - 'build_info' => $this->build_info, - 'response' => $this->response, + 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, - 'programmed' => $this->programmed, - 'programmed_bypass_access_check' => $this->programmed_bypass_access_check, - 'process_input' => $this->process_input, - 'has_file_element' => $this->has_file_element, - 'storage' => $this->storage, - ) + $this->internalStorage; - foreach ($allowed_keys as $allowed_key) { - $cacheable_array[$allowed_key] = $this->get($allowed_key); - } - return $cacheable_array; + ]; } /** @@ -494,7 +814,7 @@ public function &getCompleteForm() { * @deprecated in Drupal 8.0.x, might be removed before Drupal 8.0.0. */ public function offsetExists($offset) { - return isset($this->{$offset}) || isset($this->internalStorage[$offset]); + return isset($this->{$offset}) || isset($this->storage[$offset]); } /** @@ -503,7 +823,15 @@ public function offsetExists($offset) { * @deprecated in Drupal 8.0.x, might be removed before Drupal 8.0.0. */ public function &offsetGet($offset) { - $value = &$this->get($offset); + if (property_exists($this, $offset)) { + $value = &$this->{$offset}; + } + else { + if (!isset($this->storage[$offset])) { + $this->storage[$offset] = NULL; + } + $value = &$this->get($offset); + } return $value; } @@ -513,7 +841,12 @@ public function &offsetGet($offset) { * @deprecated in Drupal 8.0.x, might be removed before Drupal 8.0.0. */ public function offsetSet($offset, $value) { - $this->set($offset, $value); + if (property_exists($this, $offset)) { + $this->{$offset} = $value; + } + else { + $this->set($offset, $value); + } } /** @@ -525,65 +858,58 @@ public function offsetUnset($offset) { if (property_exists($this, $offset)) { $this->{$offset} = NULL; } - unset($this->internalStorage[$offset]); + else { + unset($this->storage[$offset]); + } } /** * {@inheritdoc} */ - public function setIfNotExists($property, $value) { - if (!$this->has($property)) { - $this->set($property, $value); - } + 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 &get($property) { - if (property_exists($this, $property)) { - return $this->{$property}; - } - else { - if (!isset($this->internalStorage[$property])) { - $this->internalStorage[$property] = NULL; - } - return $this->internalStorage[$property]; - } + public function has($property) { + $exists = NULL; + NestedArray::getValue($this->storage, (array) $property, $exists); + return $exists; } /** * {@inheritdoc} */ - public function set($property, $value) { - if (property_exists($this, $property)) { - $this->{$property} = $value; - } - else { - $this->internalStorage[$property] = $value; - } + public function setBuildInfo(array $build_info) { + $this->build_info = $build_info; return $this; } /** * {@inheritdoc} */ - public function has($property) { - if (property_exists($this, $property)) { - return $this->{$property} !== NULL; - } - - return array_key_exists($property, $this->internalStorage); + public function getBuildInfo() { + return $this->build_info; } /** * {@inheritdoc} */ public function addBuildInfo($property, $value) { - $build_info = $this->get('build_info'); + $build_info = $this->getBuildInfo(); $build_info[$property] = $value; - $this->set('build_info', $build_info); + $this->setBuildInfo($build_info); return $this; } @@ -621,6 +947,14 @@ public function &getValue($key, $default = NULL) { return $value; } + /** + * {@inheritdoc} + */ + public function setValues(array $values) { + $this->values = $values; + return $this; + } + /** * {@inheritdoc} */ @@ -658,7 +992,7 @@ public function isValueEmpty($key) { /** * {@inheritdoc} */ - public function setValueForElement($element, $value) { + public function setValueForElement(array $element, $value) { return $this->setValue($element['#parents'], $value); } @@ -666,10 +1000,17 @@ public function setValueForElement($element, $value) { * {@inheritdoc} */ public function setResponse(Response $response) { - $this->set('response', $response); + $this->response = $response; return $this; } + /** + * {@inheritdoc} + */ + public function getResponse() { + return $this->response; + } + /** * {@inheritdoc} */ @@ -682,7 +1023,7 @@ public function setRedirect($route_name, array $route_parameters = array(), arra * {@inheritdoc} */ public function setRedirectUrl(Url $url) { - $this->set('redirect', $url); + $this->redirect = $url; return $this; } @@ -692,19 +1033,19 @@ public function setRedirectUrl(Url $url) { public function getRedirect() { // Skip redirection for form submissions invoked via // \Drupal\Core\Form\FormBuilderInterface::submitForm(). - if ($this->get('programmed')) { + if ($this->isProgrammed()) { return FALSE; } // Skip redirection if rebuild is activated. - if ($this->get('rebuild')) { + if ($this->isRebuilding()) { return FALSE; } // Skip redirection if it was explicitly disallowed. - if ($this->get('no_redirect')) { + if ($this->isRedirectDisabled()) { return FALSE; } - return $this->get('redirect'); + return $this->redirect; } /** @@ -728,22 +1069,15 @@ public static function hasAnyErrors() { * {@inheritdoc} */ public function setErrorByName($name, $message = '') { - if ($this->get('validation_complete')) { + 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->get('limit_validation_errors'); + $limit_validation_errors = $this->getLimitValidationErrors(); if ($limit_validation_errors !== NULL) { - // #limit_validation_errors is 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. - // #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. $record = FALSE; foreach ($limit_validation_errors as $section) { // Exploding by '][' reconstructs the element's #parents. If the @@ -761,7 +1095,7 @@ public function setErrorByName($name, $message = '') { } if ($record) { $errors[$name] = $message; - $this->set('errors', $errors); + $this->errors = $errors; static::setAnyErrors(); if ($message) { $this->drupalSetMessage($message, 'error'); @@ -775,7 +1109,7 @@ public function setErrorByName($name, $message = '') { /** * {@inheritdoc} */ - public function setError(&$element, $message = '') { + public function setError(array &$element, $message = '') { $this->setErrorByName(implode('][', $element['#parents']), $message); return $this; } @@ -784,14 +1118,14 @@ public function setError(&$element, $message = '') { * {@inheritdoc} */ public function clearErrors() { - $this->set('errors', array()); + $this->errors = []; static::setAnyErrors(FALSE); } /** * {@inheritdoc} */ - public function getError($element) { + public function getError(array $element) { if ($errors = $this->getErrors($this)) { $parents = array(); foreach ($element['#parents'] as $parent) { @@ -808,34 +1142,47 @@ public function getError($element) { * {@inheritdoc} */ public function getErrors() { - return $this->get('errors'); + return $this->errors; } /** * {@inheritdoc} */ public function setRebuild($rebuild = TRUE) { - $this->set('rebuild', $rebuild); + $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 = array($this->get('build_info')['callback_object'], substr($callback, 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() { - $build_info = $this->get('build_info'); - return $build_info['callback_object']; + return $this->getBuildInfo()['callback_object']; } /** diff --git a/core/lib/Drupal/Core/Form/FormStateInterface.php b/core/lib/Drupal/Core/Form/FormStateInterface.php index fe8fc91ea474..fd37fcddef0f 100644 --- a/core/lib/Drupal/Core/Form/FormStateInterface.php +++ b/core/lib/Drupal/Core/Form/FormStateInterface.php @@ -95,18 +95,6 @@ public function getCacheableArray(); */ public function setFormState(array $form_state_additions); - /** - * Sets a value to an arbitrary property if it does not exist yet. - * - * @param string $property - * The property to use for the value. - * @param mixed $value - * The data to store. - * - * @return $this - */ - public function setIfNotExists($property, $value); - /** * Sets a response for this form. * @@ -120,6 +108,17 @@ public function setIfNotExists($property, $value); */ public function setResponse(Response $response); + /** + * Gets a response for this form. + * + * If a response is set, it will be used during processing and returned + * directly. The form will not be rebuilt or redirected. + * + * @return \Symfony\Component\HttpFoundation\Response|null + * The response to return, or NULL. + */ + public function getResponse(); + /** * Sets the redirect for the form. * @@ -164,11 +163,32 @@ public function setRedirectUrl(Url $url); */ public function getRedirect(); + /** + * Sets the entire set of arbitrary data. + * + * @param array $storage + * The entire set of arbitrary data to store for this form. + * + * @return $this + */ + public function setStorage(array $storage); + + /** + * Returns the entire set of arbitrary data. + * + * @return array + * The entire set of arbitrary data to store for this form. + */ + public function &getStorage(); + /** * Gets any arbitrary property. * - * @param string $property - * The property to retrieve. + * @param string|array $property + * Properties are often stored as multi-dimensional associative arrays. If + * $property is a string, it will return $storage[$property]. If $property + * is an array, each element of the array will be used as a nested key. If + * $property = ['foo', 'bar'] it will return $storage['foo']['bar']. * * @return mixed * A reference to the value for that property, or NULL if the property does @@ -179,8 +199,12 @@ public function &get($property); /** * Sets a value to an arbitrary property. * - * @param string $property - * The property to use for the value. + * @param string|array $property + * Properties are often stored as multi-dimensional associative arrays. If + * $property is a string, it will use $storage[$property] = $value. If + * $property is an array, each element of the array will be used as a nested + * key. If $property = ['foo', 'bar'] it will use + * $storage['foo']['bar'] = $value. * @param mixed $value * The value to set. * @@ -189,11 +213,39 @@ public function &get($property); public function set($property, $value); /** + * Determines if an arbitrary property is present. + * * @param string $property - * The property to use for the value. + * Properties are often stored as multi-dimensional associative arrays. If + * $property is a string, it will return isset($storage[$property]). If + * $property is an array, each element of the array will be used as a nested + * key. If $property = ['foo', 'bar'] it will return + * isset($storage['foo']['bar']). */ public function has($property); + /** + * Sets the build info for the form. + * + * @param array $build_info + * An array of build info. + * + * @return $this + * + * @see \Drupal\Core\Form\FormState::$build_info + */ + public function setBuildInfo(array $build_info); + + /** + * Returns the build info for the form. + * + * @return array + * An array of build info. + * + * @see \Drupal\Core\Form\FormState::$build_info + */ + public function getBuildInfo(); + /** * Adds a value to the build info. * @@ -252,6 +304,19 @@ public function &getValues(); */ public function &getValue($key, $default = NULL); + /** + * Sets the submitted form values. + * + * This should be avoided, since these values have been validated already. Use + * self::setUserInput() instead. + * + * @param array $values + * The multi-dimensional associative array of form values. + * + * @return $this + */ + public function setValues(array $values); + /** * Sets the submitted form value for a specific key. * @@ -335,7 +400,7 @@ public function isValueEmpty($key); * * @return $this */ - public function setValueForElement($element, $value); + public function setValueForElement(array $element, $value); /** * Determines if any forms have any errors. @@ -448,7 +513,7 @@ public function setErrorByName($name, $message = ''); * * @return $this */ - public function setError(&$element, $message = ''); + public function setError(array &$element, $message = ''); /** * Clears all errors against all form elements made by self::setErrorByName(). @@ -475,7 +540,7 @@ public function getErrors(); * @return string|null * Either the error message for this element or NULL if there are no errors. */ - public function getError($element); + public function getError(array $element); /** * Sets the form to be rebuilt after processing. @@ -487,6 +552,14 @@ public function getError($element); */ public function setRebuild($rebuild = TRUE); + /** + * Determines if the form should be rebuilt after processing. + * + * @return bool + * TRUE if the form should be rebuilt, FALSE otherwise. + */ + public function isRebuilding(); + /** * Converts support notations for a form callback to a valid callable. * @@ -509,4 +582,409 @@ public function prepareCallback($callback); */ public function getFormObject(); + /** + * Sets the form object that is responsible for building this form. + * + * @param \Drupal\Core\Form\FormInterface $form_object + * The form object. + * + * @return $this + */ + public function setFormObject(FormInterface $form_object); + + /** + * Sets this form to always be processed. + * + * This should only be used on RESTful GET forms that do NOT write data, as + * this could lead to security issues. It is useful so that searches do not + * need to have a form_id in their query arguments to trigger the search. + * + * @param bool $always_process + * TRUE if the form should always be processed, FALSE otherwise. + * + * @return $this + */ + public function setAlwaysProcess($always_process = TRUE); + + /** + * Determines if this form should always be processed. + * + * @return bool + * TRUE if the form should always be processed, FALSE otherwise. + */ + public function getAlwaysProcess(); + + /** + * Stores the submit and button elements for the form. + * + * @param array $buttons + * The submit and button elements. + * + * @return $this + */ + public function setButtons(array $buttons); + + /** + * Returns the submit and button elements for the form. + * + * @return array + * The submit and button elements. + */ + public function getButtons(); + + /** + * Sets this form to be cached. + * + * @param bool $cache + * TRUE if the form should be cached, FALSE otherwise. + * + * @return $this + */ + public function setCached($cache = TRUE); + + /** + * Determines if the form should be cached. + * + * @return bool + * TRUE if the form should be cached, FALSE otherwise. + */ + public function isCached(); + + /** + * Prevents the form from being cached. + * + * @return $this + */ + public function disableCache(); + + /** + * Sets that the form was submitted and has been processed and executed. + * + * @return $this + */ + public function setExecuted(); + + /** + * Determines if the form was submitted and has been processed and executed. + * + * @return bool + * TRUE if the form was submitted and has been processed and executed. + */ + public function isExecuted(); + + /** + * Sets references to details elements to render them within vertical tabs. + * + * @param array $groups + * References to details elements to render them within vertical tabs. + * + * @return $this + */ + public function setGroups(array $groups); + + /** + * Returns references to details elements to render them within vertical tabs. + * + * @return array + */ + public function getGroups(); + + /** + * Sets that this form has a file element. + * + * @param bool $has_file_element + * Whether this form has a file element. + * + * @return $this + */ + public function setHasFileElement($has_file_element = TRUE); + + /** + * Returns whether this form has a file element. + * + * @return bool + * Whether this form has a file element. + */ + public function hasFileElement(); + + /** + * Sets the limited validation error sections. + * + * @param array|null $limit_validation_errors + * The limited validation error sections. + * + * @return $this + * + * @see \Drupal\Core\Form\FormState::$limit_validation_errors + */ + public function setLimitValidationErrors($limit_validation_errors); + + /** + * Retrieves the limited validation error sections. + * + * @return array|null + * The limited validation error sections. + * + * @see \Drupal\Core\Form\FormState::$limit_validation_errors + */ + public function getLimitValidationErrors(); + + /** + * Sets the HTTP form method. + * + * @param string $method + * The HTTP form method. + * + * @see \Drupal\Core\Form\FormState::$method + * + * @return $this + */ + public function setMethod($method); + + /** + * Returns the HTTP form method. + * + * @param string + * The HTTP form method. + * + * @return bool + * TRUE if the HTTP form method matches. + * + * @see \Drupal\Core\Form\FormState::$method + */ + public function isMethodType($method_type); + + /** + * Enforces that validation is run. + * + * @param bool $must_validate + * If TRUE, validation will always be run. + * + * @return $this + */ + public function setValidationEnforced($must_validate = TRUE); + + /** + * Checks if validation is enforced. + * + * @return bool + * If TRUE, validation will always be run. + */ + public function isValidationEnforced(); + + /** + * Prevents the form from redirecting. + * + * @param bool $no_redirect + * If TRUE, the form will not redirect. + * + * @return $this + */ + public function disableRedirect($no_redirect = TRUE); + + /** + * Determines if redirecting has been prevented. + * + * @return bool + * If TRUE, the form will not redirect. + */ + public function isRedirectDisabled(); + + /** + * Sets that the form should process input. + * + * @param bool $process_input + * If TRUE, the form input will be processed. + * + * @return $this + */ + public function setProcessInput($process_input = TRUE); + + /** + * Determines if the form input will be processed. + * + * @return bool + * If TRUE, the form input will be processed. + */ + public function isProcessingInput(); + + /** + * Sets that this form was submitted programmatically. + * + * @param bool $programmed + * If TRUE, the form was submitted programmatically. + * + * @return $this + */ + public function setProgrammed($programmed = TRUE); + + /** + * Returns if this form was submitted programmatically. + * + * @return bool + * If TRUE, the form was submitted programmatically. + */ + public function isProgrammed(); + + /** + * Sets if this form submission should bypass #access. + * + * @param bool $programmed_bypass_access_check + * If TRUE, programmatic form submissions are processed without taking + * #access into account. + * + * @return $this + * + * @see \Drupal\Core\Form\FormState::$programmed_bypass_access_check + */ + public function setProgrammedBypassAccessCheck($programmed_bypass_access_check = TRUE); + + /** + * Determines if this form submission should bypass #access. + * + * @return bool + * + * @see \Drupal\Core\Form\FormState::$programmed_bypass_access_check + */ + public function isBypassingProgrammedAccessChecks(); + + /** + * Sets the rebuild info. + * + * @param array $rebuild_info + * The rebuild info. + * + * @return $this + * + * @see \Drupal\Core\Form\FormState::$rebuild_info + */ + public function setRebuildInfo(array $rebuild_info); + + /** + * Gets the rebuild info. + * + * @return array + * The rebuild info. + * + * @see \Drupal\Core\Form\FormState::$rebuild_info + */ + public function getRebuildInfo(); + + /** + * Adds a value to the rebuild info. + * + * @param string $property + * The property to use for the value. + * @param mixed $value + * The value to set. + * + * @return $this + */ + public function addRebuildInfo($property, $value); + + /** + * Sets the submit handlers. + * + * @param array $submit_handlers + * An array of submit handlers. + * + * @return $this + */ + public function setSubmitHandlers(array $submit_handlers); + + /** + * Gets the submit handlers. + * + * @return array + * An array of submit handlers. + */ + public function getSubmitHandlers(); + + /** + * Sets that the form has been submitted. + * + * @return $this + */ + public function setSubmitted(); + + /** + * Determines if the form has been submitted. + * + * @return bool + * TRUE if the form has been submitted, FALSE otherwise. + */ + public function isSubmitted(); + + /** + * Sets temporary data. + * + * @param array $temporary + * Temporary data accessible during the current page request only. + * + * @return $this + */ + public function setTemporary(array $temporary); + + /** + * Gets temporary data. + * + * @return array + * Temporary data accessible during the current page request only. + */ + public function getTemporary(); + + /** + * Sets the form element that triggered submission. + * + * @param array|null $triggering_element + * The form element that triggered submission, of NULL if there is none. + * + * @return $this + */ + public function setTriggeringElement($triggering_element); + + /** + * Gets the form element that triggered submission. + * + * @return array|null + * The form element that triggered submission, of NULL if there is none. + */ + public function &getTriggeringElement(); + + /** + * Sets the validate handlers. + * + * @param array $validate_handlers + * An array of validate handlers. + * + * @return $this + */ + public function setValidateHandlers(array $validate_handlers); + + /** + * Gets the validate handlers. + * + * @return array + * An array of validate handlers. + */ + public function getValidateHandlers(); + + /** + * Sets that validation has been completed. + * + * @param bool $validation_complete + * TRUE if validation is complete, FALSE otherwise. + * + * @return $this + */ + public function setValidationComplete($validation_complete = TRUE); + + /** + * Determines if validation has been completed. + * + * @return bool + * TRUE if validation is complete, FALSE otherwise. + */ + public function isValidationComplete(); + } diff --git a/core/lib/Drupal/Core/Form/FormSubmitter.php b/core/lib/Drupal/Core/Form/FormSubmitter.php index ab7e76ef4249..b975a70a5076 100644 --- a/core/lib/Drupal/Core/Form/FormSubmitter.php +++ b/core/lib/Drupal/Core/Form/FormSubmitter.php @@ -48,7 +48,7 @@ public function __construct(RequestStack $request_stack, UrlGeneratorInterface $ * {@inheritdoc} */ public function doSubmitForm(&$form, FormStateInterface &$form_state) { - if (!$form_state['submitted']) { + if (!$form_state->isSubmitted()) { return; } @@ -63,7 +63,7 @@ public function doSubmitForm(&$form, FormStateInterface &$form_state) { // Store $form_state information in the batch definition. $batch['form_state'] = $form_state; - $batch['progressive'] = !$form_state['programmed']; + $batch['progressive'] = !$form_state->isProgrammed(); $response = batch_process(); if ($batch['progressive']) { return $response; @@ -76,15 +76,15 @@ public function doSubmitForm(&$form, FormStateInterface &$form_state) { } // Set a flag to indicate the the form has been processed and executed. - $form_state['executed'] = TRUE; + $form_state->setExecuted(); // If no response has been set, process the form redirect. - if (!$form_state->has('response') && $redirect = $this->redirectForm($form_state)) { + if (!$form_state->getResponse() && $redirect = $this->redirectForm($form_state)) { $form_state->setResponse($redirect); } // If there is a response was set, return it instead of continuing. - if (($response = $form_state->get('response')) && $response instanceof Response) { + if (($response = $form_state->getResponse()) && $response instanceof Response) { return $response; } } @@ -94,16 +94,11 @@ public function doSubmitForm(&$form, FormStateInterface &$form_state) { */ public function executeSubmitHandlers(&$form, FormStateInterface &$form_state) { // If there was a button pressed, use its handlers. - if (!empty($form_state['submit_handlers'])) { - $handlers = $form_state['submit_handlers']; - } + $handlers = $form_state->getSubmitHandlers(); // Otherwise, check for a form-level handler. - elseif (!empty($form['#submit'])) { + if (!$handlers && !empty($form['#submit'])) { $handlers = $form['#submit']; } - else { - $handlers = array(); - } foreach ($handlers as $callback) { // Check if a previous _submit handler has set a batch, but make sure we diff --git a/core/lib/Drupal/Core/Form/FormValidator.php b/core/lib/Drupal/Core/Form/FormValidator.php index 5efedb089d60..504a606507e3 100644 --- a/core/lib/Drupal/Core/Form/FormValidator.php +++ b/core/lib/Drupal/Core/Form/FormValidator.php @@ -68,16 +68,11 @@ public function __construct(RequestStack $request_stack, TranslationInterface $s */ public function executeValidateHandlers(&$form, FormStateInterface &$form_state) { // If there was a button pressed, use its handlers. - if (isset($form_state['validate_handlers'])) { - $handlers = $form_state['validate_handlers']; - } + $handlers = $form_state->getValidateHandlers(); // Otherwise, check for a form-level handler. - elseif (isset($form['#validate'])) { + if (!$handlers && isset($form['#validate'])) { $handlers = $form['#validate']; } - else { - $handlers = array(); - } foreach ($handlers as $callback) { call_user_func_array($form_state->prepareCallback($callback), array(&$form, &$form_state)); @@ -90,12 +85,12 @@ public function executeValidateHandlers(&$form, FormStateInterface &$form_state) public function validateForm($form_id, &$form, FormStateInterface &$form_state) { // If this form is flagged to always validate, ensure that previous runs of // validation are ignored. - if (!empty($form_state['must_validate'])) { - $form_state['validation_complete'] = FALSE; + if ($form_state->isValidationEnforced()) { + $form_state->setValidationComplete(FALSE); } // If this form has completed validation, do not validate again. - if (!empty($form_state['validation_complete'])) { + if ($form_state->isValidationComplete()) { return; } @@ -138,9 +133,10 @@ public function validateForm($form_id, &$form, FormStateInterface &$form_state) protected function handleErrorsWithLimitedValidation(&$form, FormStateInterface &$form_state, $form_id) { // If validation errors are limited then remove any non validated form values, // so that only values that passed validation are left for submit callbacks. - if (isset($form_state['triggering_element']['#limit_validation_errors']) && $form_state['triggering_element']['#limit_validation_errors'] !== FALSE) { + $triggering_element = $form_state->getTriggeringElement(); + if (isset($triggering_element['#limit_validation_errors']) && $triggering_element['#limit_validation_errors'] !== FALSE) { $values = array(); - foreach ($form_state['triggering_element']['#limit_validation_errors'] as $section) { + foreach ($triggering_element['#limit_validation_errors'] as $section) { // If the section exists within $form_state->getValues(), even if the // value is NULL, copy it to $values. $section_exists = NULL; @@ -153,13 +149,13 @@ protected function handleErrorsWithLimitedValidation(&$form, FormStateInterface // allow the value of the clicked button to be retained in its normal // $form_state->getValues() locations, even if these locations are not // included in #limit_validation_errors. - if (!empty($form_state['triggering_element']['#is_button'])) { - $button_value = $form_state['triggering_element']['#value']; + if (!empty($triggering_element['#is_button'])) { + $button_value = $triggering_element['#value']; // Like all input controls, the button value may be in the location // dictated by #parents. If it is, copy it to $values, but do not // override what may already be in $values. - $parents = $form_state['triggering_element']['#parents']; + $parents = $triggering_element['#parents']; if (!NestedArray::keyExists($values, $parents) && NestedArray::getValue($form_state->getValues(), $parents) === $button_value) { NestedArray::setValue($values, $parents, $button_value); } @@ -168,12 +164,12 @@ protected function handleErrorsWithLimitedValidation(&$form, FormStateInterface // $form_state->getValue(BUTTON_NAME). If it's still there, after // validation handlers have run, copy it to $values, but do not override // what may already be in $values. - $name = $form_state['triggering_element']['#name']; + $name = $triggering_element['#name']; if (!isset($values[$name]) && $form_state->getValue($name) === $button_value) { $values[$name] = $button_value; } } - $form_state->set('values', $values); + $form_state->setValues($values); } } @@ -191,7 +187,7 @@ protected function finalizeValidation(&$form, FormStateInterface &$form_state, $ // After validation, loop through and assign each element its errors. $this->setElementErrorsFromFormState($form, $form_state); // Mark this form as validated. - $form_state['validation_complete'] = TRUE; + $form_state->setValidationComplete(); } /** @@ -209,7 +205,7 @@ protected function finalizeValidation(&$form, FormStateInterface &$form_state, $ * an explicit copy of the values for the sake of simplicity. Validation * handlers can also $form_state to pass information on to submit handlers. * For example: - * $form_state['data_for_submission'] = $data; + * $form_state->set('data_for_submission', $data); * This technique is useful when validation requires file parsing, * web service requests, or other expensive requests that should * not be repeated in the submission step. @@ -233,7 +229,7 @@ protected function doValidateForm(&$elements, FormStateInterface &$form_state, $ } // Set up the limited validation for errors. - $form_state['limit_validation_errors'] = $this->determineLimitValidationErrors($form_state); + $form_state->setLimitValidationErrors($this->determineLimitValidationErrors($form_state)); // Make sure a value is passed when the field is required. if (isset($elements['#needs_validation']) && $elements['#required']) { @@ -293,7 +289,7 @@ protected function doValidateForm(&$elements, FormStateInterface &$form_state, $ // Done validating this element, so turn off error suppression. // self::doValidateForm() turns it on again when starting on the next // element, if it's still appropriate to do so. - $form_state['limit_validation_errors'] = NULL; + $form_state->setLimitValidationErrors(NULL); } /** @@ -307,7 +303,7 @@ protected function doValidateForm(&$elements, FormStateInterface &$form_state, $ * an explicit copy of the values for the sake of simplicity. Validation * handlers can also $form_state to pass information on to submit handlers. * For example: - * $form_state['data_for_submission'] = $data; + * $form_state->set('data_for_submission', $data); * This technique is useful when validation requires file parsing, * web service requests, or other expensive requests that should * not be repeated in the submission step. @@ -374,8 +370,9 @@ protected function determineLimitValidationErrors(FormStateInterface &$form_stat // is ignored if submit handlers will run, but the element doesn't have a // #submit property, because it's too large a security risk to have any // invalid user input when executing form-level submit handlers. - if (isset($form_state['triggering_element']['#limit_validation_errors']) && ($form_state['triggering_element']['#limit_validation_errors'] !== FALSE) && !($form_state['submitted'] && !isset($form_state['triggering_element']['#submit']))) { - return $form_state['triggering_element']['#limit_validation_errors']; + $triggering_element = $form_state->getTriggeringElement(); + if (isset($triggering_element['#limit_validation_errors']) && ($triggering_element['#limit_validation_errors'] !== FALSE) && !($form_state->isSubmitted() && !isset($triggering_element['#submit']))) { + return $triggering_element['#limit_validation_errors']; } // If submit handlers won't run (due to the submission having been // triggered by an element whose #executes_submit_callback property isn't @@ -386,7 +383,7 @@ protected function determineLimitValidationErrors(FormStateInterface &$form_stat // types, #limit_validation_errors defaults to FALSE (via // system_element_info()), so that full validation is their default // behavior. - elseif (isset($form_state['triggering_element']) && !isset($form_state['triggering_element']['#limit_validation_errors']) && !$form_state['submitted']) { + elseif ($triggering_element && !isset($triggering_element['#limit_validation_errors']) && !$form_state->isSubmitted()) { return array(); } // As an extra security measure, explicitly turn off error suppression if diff --git a/core/lib/Drupal/Core/Form/FormValidatorInterface.php b/core/lib/Drupal/Core/Form/FormValidatorInterface.php index 061cf9395c56..6f1cc5289de6 100644 --- a/core/lib/Drupal/Core/Form/FormValidatorInterface.php +++ b/core/lib/Drupal/Core/Form/FormValidatorInterface.php @@ -47,7 +47,7 @@ public function executeValidateHandlers(&$form, FormStateInterface &$form_state) * an explicit copy of the values for the sake of simplicity. Validation * handlers can also use $form_state to pass information on to submit * handlers. For example: - * $form_state['data_for_submission'] = $data; + * $form_state->set('data_for_submission', $data); * This technique is useful when validation requires file parsing, * web service requests, or other expensive requests that should * not be repeated in the submission step. diff --git a/core/modules/aggregator/tests/src/Unit/Plugin/AggregatorPluginSettingsBaseTest.php b/core/modules/aggregator/tests/src/Unit/Plugin/AggregatorPluginSettingsBaseTest.php index c10d3adb8fcb..ed5e0b8835cc 100644 --- a/core/modules/aggregator/tests/src/Unit/Plugin/AggregatorPluginSettingsBaseTest.php +++ b/core/modules/aggregator/tests/src/Unit/Plugin/AggregatorPluginSettingsBaseTest.php @@ -74,7 +74,10 @@ protected function setUp() { */ public function testSettingsForm() { // Emulate a form state of a sumbitted form. - $form_state = new FormState(array('values' => array('dummy_length' => '', 'aggregator_allowed_html_tags' => ''))); + $form_state = (new FormState())->setValues([ + 'dummy_length' => '', + 'aggregator_allowed_html_tags' => '', + ]); $test_processor = $this->getMock( 'Drupal\aggregator_test\Plugin\aggregator\processor\TestProcessor', diff --git a/core/modules/block/src/BlockForm.php b/core/modules/block/src/BlockForm.php index bda93320cd77..128abe1db608 100644 --- a/core/modules/block/src/BlockForm.php +++ b/core/modules/block/src/BlockForm.php @@ -149,9 +149,7 @@ public function validate(array $form, FormStateInterface $form_state) { // The Block Entity form puts all block plugin form elements in the // settings form element, so just pass that to the block for validation. - $settings = new FormState(array( - 'values' => $form_state->getValue('settings') - )); + $settings = (new FormState())->setValues($form_state->getValue('settings')); // Call the plugin validate handler. $this->entity->getPlugin()->validateConfigurationForm($form, $settings); // Update the original form values. @@ -168,9 +166,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { // The Block Entity form puts all block plugin form elements in the // settings form element, so just pass that to the block for submission. // @todo Find a way to avoid this manipulation. - $settings = new FormState(array( - 'values' => $form_state->getValue('settings'), - )); + $settings = (new FormState())->setValues($form_state->getValue('settings')); // Call the plugin submit handler. $entity->getPlugin()->submitConfigurationForm($form, $settings); diff --git a/core/modules/config/src/Form/ConfigSingleExportForm.php b/core/modules/config/src/Form/ConfigSingleExportForm.php index 6a22b1685416..8e30e6fd121b 100644 --- a/core/modules/config/src/Form/ConfigSingleExportForm.php +++ b/core/modules/config/src/Form/ConfigSingleExportForm.php @@ -123,10 +123,10 @@ public function buildForm(array $form, FormStateInterface $form_state, $config_t '#suffix' => '</div>', ); if ($config_type && $config_name) { - $fake_form_state = new FormState(array('values' => array( + $fake_form_state = (new FormState())->setValues([ 'config_type' => $config_type, 'config_name' => $config_name, - ))); + ]); $form['export'] = $this->updateExport($form, $fake_form_state); } return $form; diff --git a/core/modules/image/src/Form/ImageEffectFormBase.php b/core/modules/image/src/Form/ImageEffectFormBase.php index 008e0a550c91..910c781effe2 100644 --- a/core/modules/image/src/Form/ImageEffectFormBase.php +++ b/core/modules/image/src/Form/ImageEffectFormBase.php @@ -106,9 +106,7 @@ public function buildForm(array $form, FormStateInterface $form_state, ImageStyl public function validateForm(array &$form, FormStateInterface $form_state) { // The image effect configuration is stored in the 'data' key in the form, // pass that through for validation. - $effect_data = new FormState(array( - 'values' => $form_state->getValue('data'), - )); + $effect_data = (new FormState())->setValues($form_state->getValue('data')); $this->imageEffect->validateConfigurationForm($form, $effect_data); // Update the original form values. $form_state->setValue('data', $effect_data['values']); @@ -122,9 +120,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { // The image effect configuration is stored in the 'data' key in the form, // pass that through for submission. - $effect_data = new FormState(array( - 'values' => $form_state->getValue('data'), - )); + $effect_data = (new FormState())->setValues($form_state->getValue('data')); $this->imageEffect->submitConfigurationForm($form, $effect_data); // Update the original form values. $form_state->setValue('data', $effect_data['values']); diff --git a/core/modules/menu_ui/src/MenuForm.php b/core/modules/menu_ui/src/MenuForm.php index fde70bb06514..8684e5950134 100644 --- a/core/modules/menu_ui/src/MenuForm.php +++ b/core/modules/menu_ui/src/MenuForm.php @@ -214,7 +214,10 @@ protected function buildOverviewForm(array &$form, FormStateInterface $form_stat // section. $form['#tree'] = TRUE; $form['#theme'] = 'menu_overview_form'; - $form_state->setIfNotExists('menu_overview_form_parents', array()); + + if (!$form_state->has('menu_overview_form_parents')) { + $form_state->set('menu_overview_form_parents', []); + } $form['#attached']['css'] = array(drupal_get_path('module', 'menu') . '/css/menu.admin.css'); diff --git a/core/modules/quickedit/src/QuickEditController.php b/core/modules/quickedit/src/QuickEditController.php index c17e4e766c4e..1ccf969ce883 100644 --- a/core/modules/quickedit/src/QuickEditController.php +++ b/core/modules/quickedit/src/QuickEditController.php @@ -178,13 +178,10 @@ public function fieldForm(EntityInterface $entity, $field_name, $langcode, $view $this->tempStoreFactory->get('quickedit')->set($entity->uuid(), $entity); } - $form_state = new FormState(array( - 'langcode' => $langcode, - 'no_redirect' => TRUE, - 'build_info' => array( - 'args' => array($entity, $field_name), - ), - )); + $form_state = (new FormState()) + ->set('langcode', $langcode) + ->disableRedirect() + ->addBuildInfo('args', [$entity, $field_name]); $form = $this->formBuilder()->buildForm('Drupal\quickedit\Form\QuickEditFieldForm', $form_state); if (!empty($form_state['executed'])) { diff --git a/core/modules/simpletest/src/Form/SimpletestResultsForm.php b/core/modules/simpletest/src/Form/SimpletestResultsForm.php index ead1767a3dbe..7f85f65f84b9 100644 --- a/core/modules/simpletest/src/Form/SimpletestResultsForm.php +++ b/core/modules/simpletest/src/Form/SimpletestResultsForm.php @@ -271,7 +271,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { } $form_execute = array(); - $form_state_execute = new FormState(array('values' => array())); + $form_state_execute = new FormState(); foreach ($classes as $class) { $form_state_execute['values']['tests'][$class] = $class; } diff --git a/core/modules/system/src/Tests/Element/PathElementFormTest.php b/core/modules/system/src/Tests/Element/PathElementFormTest.php index 0683b97b1098..dce7df6362f4 100644 --- a/core/modules/system/src/Tests/Element/PathElementFormTest.php +++ b/core/modules/system/src/Tests/Element/PathElementFormTest.php @@ -147,14 +147,13 @@ public function validateForm(array &$form, FormStateInterface $form_state) {} * Tests that default handlers are added even if custom are specified. */ public function testPathElement() { - $form_state = new FormState(array( - 'values' => array( + $form_state = (new FormState()) + ->setValues([ 'required_validate' => 'user/' . $this->testUser->id(), 'required_non_validate' => 'magic-ponies', 'required_validate_route' => 'user/' . $this->testUser->id(), 'required_validate_url' => 'user/' . $this->testUser->id(), - ), - )); + ]); $form_builder = $this->container->get('form_builder'); $form_builder->submitForm($this, $form_state); @@ -175,13 +174,12 @@ public function testPathElement() { )); // Test #required. - $form_state = new FormState(array( - 'values' => array( + $form_state = (new FormState()) + ->setValues([ 'required_non_validate' => 'magic-ponies', 'required_validate_route' => 'user/' . $this->testUser->id(), 'required_validate_url' => 'user/' . $this->testUser->id(), - ), - )); + ]); $form_builder->submitForm($this, $form_state); $errors = $form_state->getErrors(); // Should be missing 'required_validate' field. @@ -189,14 +187,13 @@ public function testPathElement() { $this->assertEqual($errors, array('required_validate' => t('!name field is required.', array('!name' => 'required_validate')))); // Test invalid parameters. - $form_state = new FormState(array( - 'values' => array( + $form_state = (new FormState()) + ->setValues([ 'required_validate' => 'user/74', 'required_non_validate' => 'magic-ponies', 'required_validate_route' => 'user/74', 'required_validate_url' => 'user/74', - ), - )); + ]); $form_builder = $this->container->get('form_builder'); $form_builder->submitForm($this, $form_state); diff --git a/core/modules/system/src/Tests/Form/FormDefaultHandlersTest.php b/core/modules/system/src/Tests/Form/FormDefaultHandlersTest.php index 51c79f85212c..d51cc1aa814f 100644 --- a/core/modules/system/src/Tests/Form/FormDefaultHandlersTest.php +++ b/core/modules/system/src/Tests/Form/FormDefaultHandlersTest.php @@ -75,7 +75,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { * Tests that default handlers are added even if custom are specified. */ function testDefaultAndCustomHandlers() { - $form_state = new FormState(array('values' => array())); + $form_state = new FormState(); $form_builder = $this->container->get('form_builder'); $form_builder->submitForm($this, $form_state); diff --git a/core/modules/system/src/Tests/Form/ProgrammaticTest.php b/core/modules/system/src/Tests/Form/ProgrammaticTest.php index cfe9cb232d30..9b0234ad742b 100644 --- a/core/modules/system/src/Tests/Form/ProgrammaticTest.php +++ b/core/modules/system/src/Tests/Form/ProgrammaticTest.php @@ -72,7 +72,7 @@ function testSubmissionWorkflow() { */ private function submitForm($values, $valid_input) { // Programmatically submit the given values. - $form_state = new FormState(array('values' => $values)); + $form_state = (new FormState())->setValues($values); \Drupal::formBuilder()->submitForm('\Drupal\form_test\Form\FormTestProgrammaticForm', $form_state); // Check that the form returns an error when expected, and vice versa. @@ -99,10 +99,10 @@ private function submitForm($values, $valid_input) { * Test the programmed_bypass_access_check flag. */ public function testProgrammaticAccessBypass() { - $form_state = new FormState(array('values' => array( + $form_state = (new FormState())->setValues([ 'textfield' => 'dummy value', 'field_restricted' => 'dummy value' - ))); + ]); // Programmatically submit the form with a value for the restricted field. // Since programmed_bypass_access_check is set to TRUE by default, the diff --git a/core/modules/system/src/Tests/System/SystemConfigFormTestBase.php b/core/modules/system/src/Tests/System/SystemConfigFormTestBase.php index 388977ac43f3..a9f17c0483ce 100644 --- a/core/modules/system/src/Tests/System/SystemConfigFormTestBase.php +++ b/core/modules/system/src/Tests/System/SystemConfigFormTestBase.php @@ -52,7 +52,7 @@ public function testConfigForm() { foreach ($this->values as $form_key => $data) { $values[$form_key] = $data['#value']; } - $form_state = new FormState(array('values' => $values)); + $form_state = (new FormState())->setValues($values); \Drupal::formBuilder()->submitForm($this->form, $form_state); // Check that the form returns an error when expected, and vice versa. diff --git a/core/modules/system/tests/modules/batch_test/src/Controller/BatchTestController.php b/core/modules/system/tests/modules/batch_test/src/Controller/BatchTestController.php index fcd9b010f53a..d6829fad0e08 100644 --- a/core/modules/system/tests/modules/batch_test/src/Controller/BatchTestController.php +++ b/core/modules/system/tests/modules/batch_test/src/Controller/BatchTestController.php @@ -85,9 +85,9 @@ public function testNoForm() { * Render array containing markup. */ function testProgrammatic($value = 1) { - $form_state = new FormState(array( - 'values' => array('value' => $value) - )); + $form_state = (new FormState())->setValues([ + 'value' => $value, + ]); \Drupal::formBuilder()->submitForm('Drupal\batch_test\Form\BatchTestChainedForm', $form_state); return array( 'success' => array( diff --git a/core/modules/views/includes/ajax.inc b/core/modules/views/includes/ajax.inc index da57333aaf76..c6daa7147623 100644 --- a/core/modules/views/includes/ajax.inc +++ b/core/modules/views/includes/ajax.inc @@ -17,12 +17,14 @@ */ function views_ajax_form_wrapper($form_class, FormStateInterface &$form_state) { // This won't override settings already in. - $form_state->setIfNotExists('rerender', FALSE); - $form_state->setIfNotExists('no_redirect', !empty($form_state['ajax'])); - $form_state->setIfNotExists('no_cache', TRUE); - $form_state->setIfNotExists('build_info', array( - 'args' => array(), - )); + if (!$form_state->has('rerender')) { + $form_state->set('rerender', FALSE); + } + // Do not overwrite if the redirect has been disabled. + if (!$form_state->isRedirectDisabled()) { + $form_state->disableRedirect(!empty($form_state['ajax'])); + } + $form_state->disableCache(); $form = \Drupal::formBuilder()->buildForm($form_class, $form_state); $output = drupal_render($form); diff --git a/core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php b/core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php index 211a388b2c0f..4f30943468a3 100644 --- a/core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php +++ b/core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php @@ -129,14 +129,15 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { */ public function renderExposedForm($block = FALSE) { // Deal with any exposed filters we may have, before building. - $form_state = new FormState(array( - 'view' => &$this->view, - 'display' => &$this->view->display_handler->display, - 'method' => 'get', - 'rerender' => TRUE, - 'no_redirect' => TRUE, - 'always_process' => TRUE, - )); + $form_state = (new FormState()) + ->setStorage([ + 'view' => $this->view, + 'display' => &$this->view->display_handler->display, + 'rerender' => TRUE, + ]) + ->setMethod('get') + ->setAlwaysProcess() + ->disableRedirect(); // Some types of displays (eg. attachments) may wish to use the exposed // filters of their parent displays instead of showing an additional diff --git a/core/modules/views/src/Tests/Wizard/WizardPluginBaseUnitTest.php b/core/modules/views/src/Tests/Wizard/WizardPluginBaseUnitTest.php index 72a8823065ca..07d0783fda44 100644 --- a/core/modules/views/src/Tests/Wizard/WizardPluginBaseUnitTest.php +++ b/core/modules/views/src/Tests/Wizard/WizardPluginBaseUnitTest.php @@ -63,12 +63,12 @@ public function testCreateView() { )); language_save($language); - $form_state->set('values', array( + $form_state->setValues([ 'id' => $random_id, 'label' => $random_label, 'description' => $random_description, 'base_table' => 'views_test_data', - )); + ]); $this->wizard->validateView($form, $form_state); $view = $this->wizard->createView($form, $form_state); diff --git a/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php b/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php index 15e6ee2c8975..d9d9d6375ff3 100644 --- a/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php +++ b/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php @@ -66,20 +66,16 @@ protected function setType($type) { public function getFormState(ViewStorageInterface $view, $display_id, $js) { // $js may already have been converted to a Boolean. $ajax = is_string($js) ? $js === 'ajax' : $js; - return new FormState(array( - 'form_id' => $this->getFormId(), - 'form_key' => $this->getFormKey(), - 'ajax' => $ajax, - 'display_id' => $display_id, - 'view' => $view, - 'type' => $this->type, - 'id' => $this->id, - 'no_redirect' => TRUE, - 'build_info' => array( - 'args' => array(), - 'callback_object' => $this, - ), - )); + return (new FormState()) + ->set('form_id', $this->getFormId()) + ->set('form_key', $this->getFormKey()) + ->set('ajax', $ajax) + ->set('display_id', $display_id) + ->set('view', $view) + ->set('type', $this->type) + ->set('id', $this->id) + ->disableRedirect() + ->addBuildInfo('callback_object', $this); } /** diff --git a/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php b/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php index b680217f9464..9e36fcc42b13 100644 --- a/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php +++ b/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php @@ -46,7 +46,7 @@ public function testGetFormIdWithClassName() { $form_id = $this->formBuilder->getFormId($form_arg, $form_state); $this->assertSame('test_form', $form_id); - $this->assertSame($form_arg, get_class($form_state['build_info']['callback_object'])); + $this->assertSame($form_arg, get_class($form_state->getFormObject())); } /** @@ -62,7 +62,7 @@ public function testGetFormIdWithInjectedClassName() { $form_id = $this->formBuilder->getFormId($form_arg, $form_state); $this->assertSame('test_form', $form_id); - $this->assertSame($form_arg, get_class($form_state['build_info']['callback_object'])); + $this->assertSame($form_arg, get_class($form_state->getFormObject())); } /** @@ -77,7 +77,7 @@ public function testGetFormIdWithObject() { $form_id = $this->formBuilder->getFormId($form_arg, $form_state); $this->assertSame($expected_form_id, $form_id); - $this->assertSame($form_arg, $form_state['build_info']['callback_object']); + $this->assertSame($form_arg, $form_state->getFormObject()); } /** @@ -99,8 +99,8 @@ public function testGetFormIdWithBaseForm() { $form_id = $this->formBuilder->getFormId($form_arg, $form_state); $this->assertSame($expected_form_id, $form_id); - $this->assertSame($form_arg, $form_state['build_info']['callback_object']); - $this->assertSame($base_form_id, $form_state['build_info']['base_form_id']); + $this->assertSame($form_arg, $form_state->getFormObject()); + $this->assertSame($base_form_id, $form_state->getBuildInfo()['base_form_id']); } /** @@ -123,7 +123,7 @@ public function testHandleFormStateResponse($class, $form_state_key) { $form_arg->expects($this->any()) ->method('submitForm') ->will($this->returnCallback(function ($form, FormStateInterface $form_state) use ($response, $form_state_key) { - $form_state->set($form_state_key, $response); + $form_state->setFormState([$form_state_key => $response]); })); $form_state = new FormState(); @@ -136,7 +136,7 @@ public function testHandleFormStateResponse($class, $form_state_key) { catch (\Exception $e) { $this->assertSame('exit', $e->getMessage()); } - $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $form_state->get('response')); + $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $form_state->getResponse()); } /** @@ -190,7 +190,7 @@ public function testHandleRedirectWithResponse() { catch (\Exception $e) { $this->assertSame('exit', $e->getMessage()); } - $this->assertSame($response, $form_state->get('response')); + $this->assertSame($response, $form_state->getResponse()); } /** @@ -279,7 +279,7 @@ public function testBuildFormWithObject() { $form_state = new FormState(); $form = $this->formBuilder->buildForm($form_arg, $form_state); $this->assertFormElement($expected_form, $form, 'test'); - $this->assertSame($form_id, $form_state['build_info']['form_id']); + $this->assertSame($form_id, $form_state->getBuildInfo()['form_id']); $this->assertArrayHasKey('#id', $form); } @@ -305,15 +305,15 @@ public function testRebuildForm() { $original_build_id = $form['#build_id']; // Rebuild the form, and assert that the build ID has not changed. - $form_state['rebuild'] = TRUE; + $form_state->setRebuild(); $input['form_id'] = $form_id; $form_state->setUserInput($input); - $form_state['rebuild_info']['copy']['#build_id'] = TRUE; + $form_state->addRebuildInfo('copy', ['#build_id' => TRUE]); $this->formBuilder->processForm($form_id, $form, $form_state); $this->assertSame($original_build_id, $form['#build_id']); // Rebuild the form again, and assert that there is a new build ID. - $form_state['rebuild_info'] = array(); + $form_state->setRebuildInfo([]); $form = $this->formBuilder->buildForm($form_arg, $form_state); $this->assertNotSame($original_build_id, $form['#build_id']); } @@ -337,10 +337,9 @@ public function testGetCache() { ->will($this->returnValue($expected_form)); // Do an initial build of the form and track the build ID. - $form_state = new FormState(); - $form_state['build_info']['args'] = array(); - $form_state['build_info']['files'] = array(array('module' => 'node', 'type' => 'pages.inc')); - $form_state['cache'] = TRUE; + $form_state = (new FormState()) + ->addBuildInfo('files', [['module' => 'node', 'type' => 'pages.inc']]) + ->setCached(); $form = $this->formBuilder->buildForm($form_arg, $form_state); $cached_form = $form; @@ -353,12 +352,12 @@ public function testGetCache() { // The final form build will not trigger any actual form building, but will // use the form cache. - $form_state['executed'] = TRUE; + $form_state->setExecuted(); $input['form_id'] = $form_id; $input['form_build_id'] = $form['#build_id']; $form_state->setUserInput($input); $this->formBuilder->buildForm($form_arg, $form_state); - $this->assertEmpty($form_state['errors']); + $this->assertEmpty($form_state->getErrors()); } /** diff --git a/core/tests/Drupal/Tests/Core/Form/FormCacheTest.php b/core/tests/Drupal/Tests/Core/Form/FormCacheTest.php index 6d668b2fb15c..d08557ac8d7f 100644 --- a/core/tests/Drupal/Tests/Core/Form/FormCacheTest.php +++ b/core/tests/Drupal/Tests/Core/Form/FormCacheTest.php @@ -235,7 +235,7 @@ public function testLoadCachedFormState() { ->willReturn($cached_form_state); $this->formCache->getCache($form_build_id, $form_state); - $this->assertSame($cached_form_state['storage'], $form_state['storage']); + $this->assertSame($cached_form_state['storage'], $form_state->getStorage()); } /** diff --git a/core/tests/Drupal/Tests/Core/Form/FormStateTest.php b/core/tests/Drupal/Tests/Core/Form/FormStateTest.php index 0697b2da79e3..83e251816dd7 100644 --- a/core/tests/Drupal/Tests/Core/Form/FormStateTest.php +++ b/core/tests/Drupal/Tests/Core/Form/FormStateTest.php @@ -29,7 +29,7 @@ class FormStateTest extends UnitTestCase { * @dataProvider providerTestGetRedirect */ public function testGetRedirect($form_state_additions, $expected) { - $form_state = new FormState($form_state_additions); + $form_state = (new FormState())->setFormState($form_state_additions); $redirect = $form_state->getRedirect(); $this->assertEquals($expected, $redirect); } @@ -82,9 +82,9 @@ public function testSetError() { */ public function testGetError($errors, $parents, $error = NULL) { $element['#parents'] = $parents; - $form_state = new FormState(array( + $form_state = (new FormState())->setFormState([ 'errors' => $errors, - )); + ]); $this->assertSame($error, $form_state->getError($element)); } @@ -110,9 +110,9 @@ public function providerTestGetError() { */ public function testSetErrorByName($limit_validation_errors, $expected_errors, $set_message = FALSE) { $form_state = $this->getMockBuilder('Drupal\Core\Form\FormState') - ->setConstructorArgs(array(array('limit_validation_errors' => $limit_validation_errors))) ->setMethods(array('drupalSetMessage')) ->getMock(); + $form_state->setLimitValidationErrors($limit_validation_errors); $form_state->clearErrors(); $form_state->expects($set_message ? $this->once() : $this->never()) ->method('drupalSetMessage'); @@ -122,7 +122,7 @@ public function testSetErrorByName($limit_validation_errors, $expected_errors, $ $form_state->setErrorByName('options'); $this->assertSame(!empty($expected_errors), $form_state::hasAnyErrors()); - $this->assertSame($expected_errors, $form_state['errors']); + $this->assertSame($expected_errors, $form_state->getErrors()); } public function providerTestSetErrorByName() { @@ -147,9 +147,9 @@ public function providerTestSetErrorByName() { */ public function testFormErrorsDuringSubmission() { $form_state = $this->getMockBuilder('Drupal\Core\Form\FormState') - ->setConstructorArgs(array(array('validation_complete' => TRUE))) ->setMethods(array('drupalSetMessage')) ->getMock(); + $form_state->setValidationComplete(); $form_state->setErrorByName('test', 'message'); } @@ -183,12 +183,12 @@ public function testSetValueForElement() { * @dataProvider providerTestGetValue */ public function testGetValue($key, $expected, $default = NULL) { - $form_state = new FormState(array('values' => array( + $form_state = (new FormState())->setValues([ 'foo' => 'one', 'bar' => array( 'baz' => 'two', ), - ))); + ]); $this->assertSame($expected, $form_state->getValue($key, $default)); } @@ -215,7 +215,9 @@ public function providerTestGetValue() { * @dataProvider providerTestSetValue */ public function testSetValue($key, $value, $expected) { - $form_state = new FormState(array('values' => array('bar' => 'wrong'))); + $form_state = (new FormState())->setValues([ + 'bar' => 'wrong', + ]); $form_state->setValue($key, $value); $this->assertSame($expected, $form_state->getValues()); } @@ -225,9 +227,9 @@ public function testSetValue($key, $value, $expected) { */ public function testPrepareCallbackValidMethod() { $form_state = new FormState(); - $form_state['build_info']['callback_object'] = new PrepareCallbackTestForm(); + $form_state->setFormObject(new PrepareCallbackTestForm()); $processed_callback = $form_state->prepareCallback('::buildForm'); - $this->assertEquals(array($form_state['build_info']['callback_object'], 'buildForm'), $processed_callback); + $this->assertEquals([$form_state->getFormObject(), 'buildForm'], $processed_callback); } /** @@ -235,7 +237,7 @@ public function testPrepareCallbackValidMethod() { */ public function testPrepareCallbackInValidMethod() { $form_state = new FormState(); - $form_state['build_info']['callback_object'] = new PrepareCallbackTestForm(); + $form_state->setFormObject(new PrepareCallbackTestForm()); $processed_callback = $form_state->prepareCallback('not_a_method'); // The callback was not changed as no such method exists. $this->assertEquals('not_a_method', $processed_callback); @@ -246,8 +248,8 @@ public function testPrepareCallbackInValidMethod() { */ public function testPrepareCallbackArray() { $form_state = new FormState(); - $form_state['build_info']['callback_object'] = new PrepareCallbackTestForm(); - $callback = array($form_state['build_info']['callback_object'], 'buildForm'); + $form_state->setFormObject(new PrepareCallbackTestForm()); + $callback = [$form_state->getFormObject(), 'buildForm']; $processed_callback = $form_state->prepareCallback($callback); $this->assertEquals($callback, $processed_callback); } @@ -272,7 +274,7 @@ public function providerTestSetValue() { * @dataProvider providerTestHasValue */ public function testHasValue($key, $expected) { - $form_state = new FormState(array('values' => array( + $form_state = (new FormState())->setValues([ 'foo' => 'one', 'bar' => array( 'baz' => 'two', @@ -280,7 +282,7 @@ public function testHasValue($key, $expected) { 'true' => TRUE, 'false' => FALSE, 'null' => NULL, - ))); + ]); $this->assertSame($expected, $form_state->hasValue($key)); } @@ -313,7 +315,7 @@ public function providerTestHasValue() { * @dataProvider providerTestIsValueEmpty */ public function testIsValueEmpty($key, $expected) { - $form_state = new FormState(array('values' => array( + $form_state = (new FormState())->setValues([ 'foo' => 'one', 'bar' => array( 'baz' => 'two', @@ -321,7 +323,7 @@ public function testIsValueEmpty($key, $expected) { 'true' => TRUE, 'false' => FALSE, 'null' => NULL, - ))); + ]); $this->assertSame($expected, $form_state->isValueEmpty($key)); } @@ -405,22 +407,113 @@ public function testLoadIncludeAlreadyLoaded() { $module = 'some_module'; $name = 'some_name'; $form_state = $this->getMockBuilder('Drupal\Core\Form\FormState') - ->setConstructorArgs([['build_info' => ['files' => [ - 'some_module:some_name.some_type' => [ - 'type' => $type, - 'module' => $module, - 'name' => $name, - ], - ]]]]) ->setMethods(array('moduleLoadInclude')) ->getMock(); + $form_state->addBuildInfo('files', [ + 'some_module:some_name.some_type' => [ + 'type' => $type, + 'module' => $module, + 'name' => $name, + ], + ]); $form_state->expects($this->never()) ->method('moduleLoadInclude'); $this->assertFalse($form_state->loadInclude($module, $type, $name)); } + /** + * @covers ::isCached + * + * @dataProvider providerTestIsCached + */ + public function testIsCached($cache_key, $no_cache_key, $expected) { + $form_state = (new FormState())->setFormState([ + 'cache' => $cache_key, + 'no_cache' => $no_cache_key, + ]); + $this->assertSame($expected, $form_state->isCached()); + } + + /** + * Provides test data for testIsCached(). + */ + public function providerTestIsCached() { + $data = []; + $data[] = [ + TRUE, + TRUE, + FALSE, + ]; + $data[] = [ + FALSE, + TRUE, + FALSE, + ]; + $data[] = [ + FALSE, + FALSE, + FALSE, + ]; + $data[] = [ + TRUE, + FALSE, + TRUE, + ]; + $data[] = [ + TRUE, + NULL, + TRUE, + ]; + $data[] = [ + FALSE, + NULL, + FALSE, + ]; + return $data; + } + + /** + * @covers ::isMethodType + * @covers ::setMethod + * + * @dataProvider providerTestIsMethodType + */ + public function testIsMethodType($set_method_type, $input, $expected) { + $form_state = (new FormState()) + ->setMethod($set_method_type); + $this->assertSame($expected, $form_state->isMethodType($input)); + } + + /** + * Provides test data for testIsMethodType(). + */ + public function providerTestIsMethodType() { + $data = []; + $data[] = [ + 'get', + 'get', + TRUE, + ]; + $data[] = [ + 'get', + 'GET', + TRUE, + ]; + $data[] = [ + 'GET', + 'GET', + TRUE, + ]; + $data[] = [ + 'post', + 'get', + FALSE, + ]; + return $data; + } + } /** diff --git a/core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php b/core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php index e1c9462e3ed1..ff2b2cd3a085 100644 --- a/core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php +++ b/core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php @@ -45,7 +45,7 @@ public function testHandleFormSubmissionNotSubmitted() { $form_state = new FormState(); $return = $form_submitter->doSubmitForm($form, $form_state); - $this->assertFalse($form_state['executed']); + $this->assertFalse($form_state->isExecuted()); $this->assertNull($return); } @@ -55,13 +55,12 @@ public function testHandleFormSubmissionNotSubmitted() { public function testHandleFormSubmissionNoRedirect() { $form_submitter = $this->getFormSubmitter(); $form = array(); - $form_state = new FormState(array( - 'submitted' => TRUE, - 'no_redirect' => TRUE, - )); + $form_state = (new FormState()) + ->setSubmitted() + ->disableRedirect(); $return = $form_submitter->doSubmitForm($form, $form_state); - $this->assertTrue($form_state['executed']); + $this->assertTrue($form_state->isExecuted()); $this->assertNull($return); } @@ -78,10 +77,9 @@ public function testHandleFormSubmissionWithResponses($class, $form_state_key) { ->method('prepare') ->will($this->returnValue($response)); - $form_state = new FormState(array( - 'submitted' => TRUE, - $form_state_key => $response, - )); + $form_state = (new FormState()) + ->setSubmitted() + ->setFormState([$form_state_key => $response]); $form_submitter = $this->getFormSubmitter(); $form = array(); @@ -202,7 +200,7 @@ public function testRedirectWithoutResult() { */ public function testExecuteSubmitHandlers() { $form_submitter = $this->getFormSubmitter(); - $mock = $this->getMock('stdClass', array('submit_handler', 'hash_submit', 'simple_string_submit')); + $mock = $this->getMockForAbstractClass('Drupal\Core\Form\FormBase', [], '', TRUE, TRUE, TRUE, ['submit_handler', 'hash_submit', 'simple_string_submit']); $mock->expects($this->once()) ->method('submit_handler') ->with($this->isType('array'), $this->isInstanceOf('Drupal\Core\Form\FormStateInterface')); @@ -221,13 +219,13 @@ public function testExecuteSubmitHandlers() { $form_submitter->executeSubmitHandlers($form, $form_state); // $form_state submit handlers will supersede $form handlers. - $form_state['submit_handlers'][] = array($mock, 'submit_handler'); + $form_state->setSubmitHandlers([[$mock, 'submit_handler']]); $form_submitter->executeSubmitHandlers($form, $form_state); // Methods directly on the form object can be specified as a string. - $form_state = new FormState(); - $form_state['build_info']['callback_object'] = $mock; - $form_state['submit_handlers'][] = '::simple_string_submit'; + $form_state = (new FormState()) + ->setFormObject($mock) + ->setSubmitHandlers(['::simple_string_submit']); $form_submitter->executeSubmitHandlers($form, $form_state); } diff --git a/core/tests/Drupal/Tests/Core/Form/FormTestBase.php b/core/tests/Drupal/Tests/Core/Form/FormTestBase.php index f3a9443f282d..47b80b1a22f3 100644 --- a/core/tests/Drupal/Tests/Core/Form/FormTestBase.php +++ b/core/tests/Drupal/Tests/Core/Form/FormTestBase.php @@ -215,23 +215,20 @@ protected function getMockForm($form_id, $expected_form = NULL, $count = 1) { * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. * @param bool $programmed - * Whether $form_state['programmed'] should be set to TRUE or not. If it is - * not set to TRUE, you must provide additional data in $form_state for the - * submission to take place. + * Whether $form_state->setProgrammed() should be passed TRUE or not. If it + * is not set to TRUE, you must provide additional data in $form_state for + * the submission to take place. * * @return array * The built form. */ protected function simulateFormSubmission($form_id, FormInterface $form_arg, FormStateInterface $form_state, $programmed = TRUE) { - $form_state['build_info']['callback_object'] = $form_arg; - $form_state['build_info']['args'] = array(); - $input = $form_state->getUserInput(); $input['op'] = 'Submit'; - $form_state->setUserInput($input); - - $form_state['programmed'] = $programmed; - $form_state['submitted'] = TRUE; + $form_state + ->setUserInput($input) + ->setProgrammed($programmed) + ->setSubmitted(); return $this->formBuilder->buildForm($form_arg, $form_state); } diff --git a/core/tests/Drupal/Tests/Core/Form/FormValidatorTest.php b/core/tests/Drupal/Tests/Core/Form/FormValidatorTest.php index bc6e081962de..cc49c2cb32a8 100644 --- a/core/tests/Drupal/Tests/Core/Form/FormValidatorTest.php +++ b/core/tests/Drupal/Tests/Core/Form/FormValidatorTest.php @@ -33,9 +33,9 @@ public function testValidationComplete() { $form = array(); $form_state = new FormState(); - $this->assertFalse($form_state['validation_complete']); + $this->assertFalse($form_state->isValidationComplete()); $form_validator->validateForm('test_form_id', $form, $form_state); - $this->assertTrue($form_state['validation_complete']); + $this->assertTrue($form_state->isValidationComplete()); } /** @@ -52,8 +52,8 @@ public function testPreventDuplicateValidation() { ->method('doValidateForm'); $form = array(); - $form_state = new FormState(); - $form_state['validation_complete'] = TRUE; + $form_state = (new FormState()) + ->setValidationComplete(); $form_validator->validateForm('test_form_id', $form, $form_state); $this->assertArrayNotHasKey('#errors', $form); } @@ -72,9 +72,9 @@ public function testMustValidate() { ->method('doValidateForm'); $form = array(); - $form_state = new FormState(); - $form_state['validation_complete'] = TRUE; - $form_state['must_validate'] = TRUE; + $form_state = (new FormState()) + ->setValidationComplete() + ->setValidationEnforced(); $form_validator->validateForm('test_form_id', $form, $form_state); $this->assertArrayHasKey('#errors', $form); } @@ -110,7 +110,7 @@ public function testValidateInvalidFormToken() { ->with('form_token', 'The form has become outdated. Copy any unsaved work in the form below and then <a href="/test/example?foo=bar">reload this page</a>.'); $form_state->setValue('form_token', 'some_random_token'); $form_validator->validateForm('test_form_id', $form, $form_state); - $this->assertTrue($form_state['validation_complete']); + $this->assertTrue($form_state->isValidationComplete()); } /** @@ -141,7 +141,7 @@ public function testValidateValidFormToken() { ->method('setErrorByName'); $form_state->setValue('form_token', 'some_random_token'); $form_validator->validateForm('test_form_id', $form, $form_state); - $this->assertTrue($form_state['validation_complete']); + $this->assertTrue($form_state->isValidationComplete()); } /** @@ -182,10 +182,9 @@ public function testHandleErrorsWithLimitedValidation($sections, $triggering_ele $triggering_element['#limit_validation_errors'] = $sections; $form = array(); - $form_state = new FormState(array( - 'values' => $values, - 'triggering_element' => $triggering_element, - )); + $form_state = (new FormState()) + ->setValues($values) + ->setTriggeringElement($triggering_element); $form_validator->validateForm('test_form_id', $form, $form_state); $this->assertSame($expected, $form_state->getValues()); @@ -292,7 +291,8 @@ public function testExecuteValidateHandlers() { $form_validator->executeValidateHandlers($form, $form_state); // $form_state validate handlers will supersede $form handlers. - $form_state['validate_handlers'][] = array($mock, 'validate_handler'); + $validate_handlers[] = [$mock, 'validate_handler']; + $form_state->setValidateHandlers($validate_handlers); $form_validator->executeValidateHandlers($form, $form_state); } -- GitLab