Skip to content

Commit 2024c40

Browse files
authored
Merge pull request #108 from systopia/clear-errors-if-triggering-element-limts-validation
Clear errors if triggering element has limited validation
2 parents dbf6d0e + f8ec83c commit 2024c40

File tree

2 files changed

+57
-4
lines changed

2 files changed

+57
-4
lines changed

src/Form/AbstractJsonFormsForm.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,13 @@ protected function buildJsonFormsForm(
155155
*/
156156
public function validateForm(array &$form, FormStateInterface $formState): void {
157157
parent::validateForm($form, $formState);
158+
if ([] !== $formState->getErrors() && [] === $this->determineLimitValidationErrors($formState)) {
159+
// Even though the triggering element has #limit_validation_errors set to
160+
// [] form state might contain errors, e.g. if a no radio button of a
161+
// required radios element was selected. This might happen on
162+
// recalculation.
163+
$formState->clearErrors();
164+
}
158165

159166
if ($formState->isSubmitted() || $formState->isValidationEnforced()) {
160167
FormCallbackExecutor::executePreSchemaValidationCallbacks($formState);
@@ -240,4 +247,54 @@ protected function doGetSubmittedData(FormStateInterface $formState): array {
240247
return FieldNameUtil::toJsonData($data);
241248
}
242249

250+
/**
251+
* Copied from
252+
* \Drupal\Core\Form\FormValidator::determineLimitValidationErrors().
253+
*
254+
* Determines if validation errors should be limited.
255+
*
256+
* @param \Drupal\Core\Form\FormStateInterface $formState
257+
* The current state of the form.
258+
*
259+
* @return array<mixed>|null
260+
*
261+
* phpcs:disable Generic.Files.LineLength.TooLong
262+
*/
263+
private function determineLimitValidationErrors(FormStateInterface &$formState): ?array {
264+
// While this element is being validated, it may be desired that some
265+
// calls to \Drupal\Core\Form\FormStateInterface::setErrorByName() be
266+
// suppressed and not result in a form error, so that a button that
267+
// implements low-risk functionality (such as "Previous" or "Add more") that
268+
// doesn't require all user input to be valid can still have its submit
269+
// handlers triggered. The triggering element's #limit_validation_errors
270+
// property contains the information for which errors are needed, and all
271+
// other errors are to be suppressed. The #limit_validation_errors property
272+
// is ignored if submit handlers will run, but the element doesn't have a
273+
// #submit property, because it's too large a security risk to have any
274+
// invalid user input when executing form-level submit handlers.
275+
$triggering_element = $formState->getTriggeringElement();
276+
if (isset($triggering_element['#limit_validation_errors']) && ($triggering_element['#limit_validation_errors'] !== FALSE) && !($formState->isSubmitted() && !isset($triggering_element['#submit']))) {
277+
return $triggering_element['#limit_validation_errors'];
278+
}
279+
// If submit handlers won't run (due to the submission having been
280+
// triggered by an element whose #executes_submit_callback property isn't
281+
// TRUE), then it's safe to suppress all validation errors, and we do so
282+
// by default, which is particularly useful during an Ajax submission
283+
// triggered by a non-button. An element can override this default by
284+
// setting the #limit_validation_errors property. For button element
285+
// types, #limit_validation_errors defaults to FALSE, so that full
286+
// validation is their default behavior.
287+
elseif ($triggering_element && !isset($triggering_element['#limit_validation_errors']) && !$formState->isSubmitted()) {
288+
return [];
289+
}
290+
// As an extra security measure, explicitly turn off error suppression if
291+
// one of the above conditions wasn't met. Since this is also done at the
292+
// end of this function, doing it here is only to handle the rare edge
293+
// case where a validate handler invokes form processing of another form.
294+
else {
295+
return NULL;
296+
}
297+
// phpcs:enable
298+
}
299+
243300
}

src/Form/Control/Callbacks/RecalculateCallback.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ final class RecalculateCallback {
3232
* sill can perform recalculation.
3333
*/
3434
public static function addAjaxCommands(AjaxResponse $response, FormStateInterface $formState): void {
35-
// Even though the triggering element has #limit_validation_errors set to []
36-
// form state might contain errors, e.g. if a no radio button of a required
37-
// radios element was selected.
38-
$formState->clearErrors();
3935
/** @var \Drupal\json_forms\Form\AbstractJsonFormsForm $formObject */
4036
$formObject = $formState->getFormObject();
4137
$newData = FieldNameUtil::toFormData($formObject->calculateData($formState));

0 commit comments

Comments
 (0)