I have been struggling with the Drupal 8 Form API all afternoon. It seems that the API is not meant to create GET forms, while the comments state otherwise. I am trying to build sort of a filter-form that should pass it's parameters to the URL so that it can be bookmarked, etc.
My first problem is that the FormBuilder->getForm($myForm)
method creates a FormState
object that defaults to method POST. Even when I set my form's method to 'GET', the FormState
object will check the request method before the form is even being created and since the requestmethod is GET and the FormState's method is POST it will not process anything at all.
So instead I tried to create my own FormState
object (which I obviously set to GET) and call buildForm
instead (that way bypassing the getForm
logic):
$form = new MyForm();
$form_state = new FormState();
$form_state->setMethod('get');
$form = \Drupal::formBuilder()->buildForm($form, $form_state);
This seems to work better. However, as soon as I give my form a submit-button it then gets in some sort of redirect loop, which I haven't been able to pinpoint yet. I don't have such problems when using POST.
It's really weird that the API doesn't seem to be able to handle GET forms.
Also:
Would I get this to work, the comments in the Form API code state that GET forms do not use a form-ID, however the FormInterface does require a getFormId
method.
Could someone please clarify what I am doing wrong, or point out some documentation about this?
A proper example
I decided to simplify my testscenario a lot, in order to make sure that I wasn't doing anything weird. So now my testscenario is as follows:
I created a simple module with a hook_preprocess_node. There I render my form and add it to the template:
<?php
use Drupal\my_module\Form\TestForm;
function my_module_preprocess_node(&$variables) {
$form = new TestForm();
$variables['test_form'] = \Drupal::formBuilder()->getForm($form);
}
My form is as simple as I could make it:
<?php
namespace Drupal\my_module\Form;
use Drupal\Component\Utility\Html;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
class TestForm extends FormBase {
/**
* @inheritDoc
*/
public function getFormId()
{
return 'test_form';
}
/**
* @inheritDoc
*/
public function buildForm(array $form, FormStateInterface $form_state)
{
$form_state->setMethod('GET');
$form['test_input'] = [
'#type' => 'textfield',
];
$form['actions'] = array(
'#type' => 'actions',
);
$form['actions']['submit'] = [
'#name' => 'test-submit',
'#id' => Html::getUniqueId('edit-submit-test-form'),
'#type' => 'submit',
'#value' => 'Submit it',
];
return $form;
}
/**
* @inheritDoc
*/
public function validateForm(array &$form, FormStateInterface $form_state)
{
// TODO: Implement validateForm() method.
}
/**
* @inheritDoc
*/
public function submitForm(array &$form, FormStateInterface $form_state)
{
// TODO: Implement submitForm() method.
}
}
Now my node template renders a simple form containing an input field and a submit button. When I submit the form it submits using a GET-request and I see the fields appear as GET-parameters. However the Drupal formbuilder does not pick up the form as being submitted. It does not call the validate nor submit methods.
The form contains both $form_state->setMethod('GET');
and $form['#method'] = 'GET';
as suggested in the comments.
$form_state->setMethod()
inside the form definition.