diff --git a/src/HookHandler/FormAlter.php b/src/HookHandler/FormAlter.php new file mode 100644 index 0000000000000000000000000000000000000000..a04b46498c140bb1ef11929f243d02591f3c4ec7 --- /dev/null +++ b/src/HookHandler/FormAlter.php @@ -0,0 +1,60 @@ +<?php + +declare(strict_types = 1); + +namespace Drupal\ui_suite_bootstrap\HookHandler; + +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Render\Element; + +/** + * Alter forms. + */ +class FormAlter { + + /** + * Alter forms. + * + * @param array $form + * The form structure. + * @param \Drupal\Core\Form\FormStateInterface $formState + * The form state. + * @param string $form_id + * The form ID. + */ + public function alter(array &$form, FormStateInterface $formState, string $form_id): void { + // See \Drupal\Core\Form\FormBuilder::processForm(). + if ($formState->isMethodType('get') && $formState->getAlwaysProcess()) { + $form['#after_build'][] = [ + static::class, + 'afterBuildAddGetFormMethod', + ]; + } + } + + /** + * Form element #after_build callback. + */ + public static function afterBuildAddGetFormMethod(array $element, FormStateInterface $form_state): array { + static::addGetFormMethod($element); + return $element; + } + + /** + * Set form method to all form elements. + * + * To allow other processing to act based on this information. + * + * @param array $form + * The form or form element which children should have form method attached. + */ + protected static function addGetFormMethod(array &$form): void { + foreach (Element::children($form) as $child) { + if (!isset($form[$child]['#form_method'])) { + $form[$child]['#form_method'] = 'get'; + } + static::addGetFormMethod($form[$child]); + } + } + +} diff --git a/src/HookHandler/PreprocessInput.php b/src/HookHandler/PreprocessInput.php index 26600a84e549f0559fa4733be4a6148f70b5cd52..d3f6139a2e42beb9a7e0e140f63a3b0e94b28161 100644 --- a/src/HookHandler/PreprocessInput.php +++ b/src/HookHandler/PreprocessInput.php @@ -127,12 +127,16 @@ class PreprocessInput { return; } - // This is the same test as in RenderElement::setAttributes(). + // This is the same test as in + // \Drupal\Core\Render\Element\RenderElement::setAttributes(). if ($this->element->getProperty('parents') && $this->element->getProperty('validated')) { if ($this->element->getProperty('errors')) { $this->element->addClass('is-invalid'); } - else { + // Per \Drupal\Core\Form\FormBuilder::processForm(), GET forms are always + // processed and validated, so we exclude the valid feedback for GET + // forms. + elseif (!($this->element->hasProperty('form_method')) || $this->element->getProperty('form_method') != 'get') { $this->element->addClass('is-valid'); } } diff --git a/ui_suite_bootstrap.theme b/ui_suite_bootstrap.theme index da8eaa665a2047df678f54637a3779a6c730888f..e210c1009f339279684385450be0bc8a9f13955b 100644 --- a/ui_suite_bootstrap.theme +++ b/ui_suite_bootstrap.theme @@ -11,6 +11,7 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Template\Attribute; use Drupal\Core\Template\AttributeHelper; use Drupal\ui_suite_bootstrap\HookHandler\ElementInfoAlter; +use Drupal\ui_suite_bootstrap\HookHandler\FormAlter; use Drupal\ui_suite_bootstrap\HookHandler\FormCommerceCheckoutFlowMultistepDefaultAlter; use Drupal\ui_suite_bootstrap\HookHandler\FormSearchBlockFormAlter; use Drupal\ui_suite_bootstrap\HookHandler\PreprocessFormElement; @@ -43,6 +44,16 @@ function ui_suite_bootstrap_element_info_alter(array &$info): void { $instance->alter($info); } +/** + * Implements hook_form_alter(). + */ +function ui_suite_bootstrap_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void { + /** @var \Drupal\ui_suite_bootstrap\HookHandler\FormAlter $instance */ + $instance = \Drupal::service('class_resolver') + ->getInstanceFromDefinition(FormAlter::class); + $instance->alter($form, $form_state, $form_id); +} + /** * Implements hook_form_FORM_ID_alter() for 'commerce_checkout_flow_multistep_default'. */