function ConfigFormBase::validateForm

Same name in other branches
  1. 10 core/lib/Drupal/Core/Form/ConfigFormBase.php \Drupal\Core\Form\ConfigFormBase::validateForm()

Overrides FormBase::validateForm

13 methods override ConfigFormBase::validateForm()
BookSettingsForm::validateForm in core/modules/book/src/Form/BookSettingsForm.php
Form validation handler.
FormTestArgumentsObject::validateForm in core/modules/system/tests/modules/form_test/src/FormTestArgumentsObject.php
Form validation handler.
FormTestControllerObject::validateForm in core/modules/system/tests/modules/form_test/src/FormTestControllerObject.php
Form validation handler.
FormTestObject::validateForm in core/modules/system/tests/modules/form_test/src/FormTestObject.php
Form validation handler.
FormTestServiceObject::validateForm in core/modules/system/tests/modules/form_test/src/FormTestServiceObject.php
Form validation handler.

... See full list

File

core/lib/Drupal/Core/Form/ConfigFormBase.php, line 201

Class

ConfigFormBase
Base class for implementing system configuration forms.

Namespace

Drupal\Core\Form

Code

public function validateForm(array &$form, FormStateInterface $form_state) {
    $map = $form_state->get(static::CONFIG_KEY_TO_FORM_ELEMENT_MAP) ?? [];
    foreach (array_keys($map) as $config_name) {
        $config = $this->configFactory()
            ->getEditable($config_name);
        static::copyFormValuesToConfig($config, $form_state, $form);
        $typed_config = $this->typedConfigManager()
            ->createFromNameAndData($config_name, $config->getRawData());
        $violations = $typed_config->validate();
        // Rather than immediately applying all violation messages to the
        // corresponding form elements, first collect the messages. The structure
        // of the form may cause a single form element to contain multiple config
        // property paths thanks to `type: sequence`. Common example: a <textarea>
        // with one line per sequence item.
        // @see \Drupal\Core\Config\Schema\Sequence
        // @see \Drupal\Core\Config\Schema\SequenceDataDefinition
        $violations_per_form_element = [];
        
        /** @var \Symfony\Component\Validator\ConstraintViolationInterface $violation */
        foreach ($violations as $violation) {
            $property_path = $violation->getPropertyPath();
            // Default to index 0.
            $index = 0;
            // Detect if this is a sequence item property path, and if so, attempt
            // to fall back to the containing sequence's property path.
            if (!isset($map[$config_name][$property_path]) && preg_match("/.*\\.(\\d+)\$/", $property_path, $matches) === 1) {
                $index = intval($matches[1]);
                // The property path as known in the config key-to-form element map
                // will not have the sequence index in it.
                $property_path = rtrim($property_path, '0123456789.');
            }
            if (isset($map[$config_name][$property_path])) {
                $config_target = ConfigTarget::fromForm($map[$config_name][$property_path], $form);
                $form_element_name = implode('][', $config_target->elementParents);
            }
            else {
                // We cannot determine where to place the violation. The only option
                // is the entire form.
                $form_element_name = '';
            }
            $violations_per_form_element[$form_element_name][$index] = $violation;
        }
        // Now that we know how many constraint violation messages exist per form
        // element, set them. This is crucial because FormState::setErrorByName()
        // only allows a single validation error message per form element.
        // @see \Drupal\Core\Form\FormState::setErrorByName()
        foreach ($violations_per_form_element as $form_element_name => $violations) {
            // When only a single message exists, just set it.
            if (count($violations) === 1) {
                $form_state->setErrorByName($form_element_name, reset($violations)->getMessage());
                continue;
            }
            // However, if multiple exist, that implies it's a single form element
            // containing a `type: sequence`.
            $form_state->setErrorByName($form_element_name, $this->formatMultipleViolationsMessage($form_element_name, $violations));
        }
    }
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.