1

I'm using Drupal 8. Within \Drupal\Core\Form\Form\FormBuilder::buildForm, if $cache_check == TRUE, i.e. - the form has a form_id and a build_form_id, then the $form_state object which results from the call made to retrieveForm() in \Drupal\Core\Form\FormBuilder::buildForm() is overwritten by the form_state that is cloned prior to the retrieval.

This would seem to effectively nullify any modification done to the $form_state object within the buildForm() method of a Form class implementing FormInterface. Is this correct?

For example, MyForm class extends FormBase -- which implements FormInterface. If I make a call to $form_state->setValidateHandlers() within the buildForm method in MyForm, the extra validate handler methods set in that call will never be invoked, as the $form_state object will be overwritten after being rebuilt within MyForm::buildForm().

Is this the expected behavior? i.e. - Is it not expected to be able to alter the $form_state within buildForm() in this way?

If that is the case, then is simply using the more "Drupal 7-ish" syntax of $form['#validate'] = ['::method1', '::method2'] the accepted/best-practice way to accomplish multiple validate handlers?

This will work, because the $form array does not get overwritten after the MyForm::buildForm() method is invoked. However, if this is the accepted/best-practice way to achieve multiple validate handlers, how would one set a validate handler that exists outside of the current form class (in this example's case, MyForm)?

1

You should add the below method in drupal 8. I hope it should work. // buildForm

public function buildForm(array $form, FormStateInterface $form_state) {

    $form['company_name'] = array(
        '#type' => 'textfield',
        '#title' => $this->t('Company Name'),
        '#required' => 'TRUE',
        '#placeholder' => $this->t('Your company name'),
    );
    $form['actions']['submit'] = array(
        '#type' => 'submit',
        '#value' => $this->t('Save'),
        '#validate' => array('::validateForm', '::method1', '::method2'),
    );

    return $form;

}

public function validateForm(array &$form, FormStateInterface $form_state) {
   // do your code stuff..
}

public function method1(array &$form, FormStateInterface $form_state) {
  // do your code stuff..
}

public function method2(array &$form, FormStateInterface $form_state) {
  // do your code stuff..
}
0

Thanks for your answer. I know that adding the validate handlers to the $form array will work, because (as I pointed out in my original post) the $form array is not being overwritten in the base class after MyForm::buildForm() is invoked.

However, the documentation clearly states that using $form_state->setValidateHandlers() in the MyForm::buildForm() method should add those extra handlers and cause them to be invoked on submission of the form. My real question I suppose is, is it true that the setValidateHandlers() method can be used within a subclass' buildForm() method to accomplish this, or is that not the case? Is attaching the handlers to the #validate element on the $form array's triggering element considered the best-practice way to do this now?

If so, then the documentation for setValidateHandlers() may need to be changed. I've filed an issue for this on drupal.org hoping for an "official" response, at https://www.drupal.org/node/2869254. At the time of this writing though, I haven't received any response there.

Thanks again Satheesh!

1
  • I'm suspecting that setValidationHandlers is created to be able to attach validation handlers on the fly - likely in a submission. In such a case, you would need to set the form to rebuild in order for them to be used.
    – Jaypan
    Apr 17 '17 at 2:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.