I don't know if this is a bug or feature, but I spent the better part of a day trying to track down why my validation hook was never being called. Originally spotted in D7.14, but the code is exactly the same in the 8.x branch.
The function form_execute_handlers() first checks to see if the handler type is defined for a button press, and if so proceeds to ignore the #validate and #submit handlers defined on the top-level form element. According to the FAPI docs, it sounds like the #validate and #submit handlers should always be called.
Logically, it seems like the form-level handler should always be invoked and any specialized submit handlers should be added to the handler chain...
Is there a reason this:
// If there was a button pressed, use its handlers.
if (isset($form_state[$type . '_handlers'])) {
$handlers = $form_state[$type . '_handlers'];
}
// Otherwise, check for a form-level handler.
elseif (isset($form['#' . $type])) {
$handlers = $form['#' . $type];
}
else {
$handlers = array();
}
should not be something like this?
$handlers = array();
// If we have form-level handlers, add those
if (isset($form['#' . $type])) {
$handlers += $form['#' . $type];
}
// If there was a button pressed, add its handlers
if (isset($form_state[$type . '_handlers'])) {
$handlers += $form_state[$type . '_handlers'];
}
That code's been in there since waaaay back when, so not sure if there was a reason it was structured that way. However, if a contrib module adds a validate handler on a submit element, it causes every handler set on #validate or #submit to be skipped, which can't be a good thing...
Ran into it with the revision_scheduler module on D7 specifically, but there's nothing keeping other contrib modules from doing it as well.
| Comment | File | Size | Author |
|---|---|---|---|
| #1 | validate_submit_handler-1570018-01.patch | 1007 bytes | arpieb |
Comments
Comment #1
arpieb commentedPatch for above changes in case anyone wants to play with it...
Comment #3
marcingy commentedThis is by design
Description: Format an action button. When the button is pressed, the form will be submitted to Drupal, where it is validated and rebuilt. The submit handler is not invoked.So this is a feature request not a bug,
Comment #4
arpieb commentedThat description for the button element simply states that validation occurs after that button is clicked - not that validation is defined by that button. Isn't validation supposed to be defined by the #validate property per the D8 FAPI docs here:
What's happening now is the $form['#validate'] handlers are getting called on anything except submit, and never getting called on a submit. Which means that in order to properly cover all your validation bases, you have to set the #validate on both the form and the submit element, which seems a bit redundant and not in the spirit of the FAPI docs as not all validation callbacks are being invoked at submit time right now.
Ironically, the same goes for the #submit handlers with the way the code stands now.
Comment #5
David_Rothstein commentedThis looks like a duplicate of #372818: Form validation/submit handlers shouldn't automatically be skipped if button validation/submit handlers exist.