Khanh Hoang - Kenn
Kenn is a user experience designer and front end developer who enjoys creating beautiful and usable web and mobile experiences.
Like all Drupal 8 module development, creating forms isn't quite as straight forward as it has been in the past using the hook system. Symfony has changed the way that forms get created and called, adding a layer of complexity with the move to object-oriented code. As far as the actual form API, several HTML5 form elements have been introduced, but in general it should be a pretty easy transition for most people.
We'll start by creating a very simple form that doesn't have any bells and whistles.
Start by creating your controller file, modules/foobar/lib/Drupal/foobar/Form/FoobarForm.php, with the following contents:
<?php /** * @file * Contains \Drupal\foobar\Form\FoobarForm. */ namespace Drupal\foobar\Form; use Drupal\Core\Form\FormInterface; /** * Provides a simple example form. */ class FoobarForm implements FormInterface { /** * Implements \Drupal\Core\Form\FormInterface::getFormID(). */ public function getFormID() { return 'foobar_form'; } /** * Implements \Drupal\Core\Form\FormInterface::buildForm(). */ public function buildForm(array $form, array &$form_state) { // Use the Form API to define form elements. return $form; } /** * Implements \Drupal\Core\Form\FormInterface::validateForm(). */ public function validateForm(array &$form, array &$form_state) { // Validate the form values. } /** * Implements \Drupal\Core\Form\FormInterface::submitForm(). */ public function submitForm(array &$form, array &$form_state) { // Do something useful. } }
There are a few things to make note of here:
You'll need to create a route for your new form controller. Inside foobar.routing.yml add the following code:
foobar.form: pattern: 'admin/foobar/form' defaults: _form: '\Drupal\foobar\Form\FoobarForm' requirements: _permission: 'access administration pages'
Notice that we're using the _form parameter instead of _content to define which controller to use.
Controllers and routers are great, but what if I don't want to render a form on a page?
drupal_get_form() used to be the function you needed any time you wanted to display a form anywhere. Now that we're using controllers and routers, drupal_get_form() is no longer necessary for displaying forms as pages. However, it is still needed to render forms inside things like blocks…
use Drupal\foobar\Form\FoobarForm; drupal_get_form(new FoobarForm());
There are a number of form types in core Drupal that may already include some or all of the fields and functionality that you're needing to create. Part of the beauty of object-oriented code is that you can simply extend these form types rather than reinventing the wheel each time. This adds a layer of consistency that you may not have any other way.
Let's assume you want to create a basic admin configuration form with the Save configuration button at the bottom. Typically, you would use system_settings_form() in your form definition to add additional administrative functionality to a form. However, the same thing can be achieved simply by extending the SystemConfigFormBase class in Drupal 8.
This particular form type, SystemConfigFormBase, comes from the System module in core.
<?php /** * @file * Contains \Drupal\foobar\Form\FoobarConfigForm. */ namespace Drupal\foobar\Form; use Drupal\system\SystemConfigFormBase; class FoobarConfigForm extends SystemConfigFormBase { /** * Implements \Drupal\Core\Form\FormInterface::getFormID(). */ public function getFormID() { return 'foobar_systemconfigformbase'; } /** * Implements \Drupal\Core\Form\FormInterface::buildForm(). */ public function buildForm(array $form, array &$form_state) { $form = parent::buildForm($form, $form_state); // Use the Form API to define form elements. return $form; } /** * Implements \Drupal\Core\Form\FormInterface::validateForm(). */ public function validateForm(array &$form, array &$form_state) { parent::validateForm($form, $form_state); // Validate the form values. } /** * Implements \Drupal\Core\Form\FormInterface::submitForm(). */ public function submitForm(array &$form, array &$form_state) { parent::submitForm($form, $form_state); // Do something useful. } }
Here's a short list of some of the extendable form types in core: