I recently wrote a Drupal module that uses the Form API. This post captures some learnings that may help you if you're working with that same service.
#Set the route
We need a location for the form. In your module, create modulename.routing.yml
. For the form location, you should write:
slide.add_slide:
path: '/admin/structure/slide/add'
requirements:
_permission: 'add slide entities'
The permission field should come from modulename.permissions.yml
. There should be a block that look's like this:
add slide entities:
title: 'Create new Slide entities'
#Create form class
This can be handled from the console. You want a class located in src/Form/[name]Form.php
. The class should be Drupal\modulename\Form
. It should inherit a form class like the following:
- BlockForm
- EntityForm
- EntityDeleteForm
- MenuLinkDefaultForm
- UserPermissionsForm
- AccountForm
- EntityDisplayModeAddForm
- ModulesListConfirmForm
- ConfirmFormTestForm
- ContentEntityForm
- TermForm
- ForumForm
- BulkForm
- NodeRevisionRevertForm
- ContentEntityDeleteForm
The form class needs a public function buildForm
. The buildForm
method takes two arguments array $form
and FormStateInterface $form_state
. When the console is used to generate a form class, it generates the buildForm
method, and calls the parent buildForm
method. That body needs to be cleared and attributes need to be added to the $form
array. The attributes need to be set to the input field information.
$form['slide_name'] = [
'#type' => 'textfield',
'#title' => $this->t('Slide Title')
];
$form['slide_img'] = [
'#title' => t('Slide Image'),
'#type' => 'managed_file',
'#upload_location' => 'public://slider_images/',
];
$form['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Submit')
];
At the end of the method, return the form:
return $form;
#Initialize the form state
At the beginning of the buildForm
method, add this line:
if (!$form_state->has('entity_form_initialized')) {
$this->init($form_state);
}
This is something that I didn't do and it took me a very long time to figure out why I was having trouble. I would submit my form and I would just get an error. The error is in the block below. I got it from the nginx
error log.
2017/02/16 22:25:55 [error] 1659#0: *27 FastCGI sent in stderr: "PHP message: PHP Fatal error: Call to a member function extractFormValues() on null in /drupal/core/lib/Drupal/Core/Entity/ContentEntityForm.php on line 223
PHP message: PHP Stack trace:
PHP message: PHP 1. {main}() /drupal/index.php:0
PHP message: PHP 2. Drupal\Core\DrupalKernel->handle() /drupal/index.php:19
PHP message: PHP 3. Stack\StackedHttpKernel->handle() /drupal/core/lib/Drupal/Core/DrupalKernel.php:652
PHP message: PHP 4. Drupal\Core\StackMiddleware\NegotiationMiddleware->handle() /drupal/vendor/stack/builder/src/Stack/StackedHttpKernel.php:23
PHP message: PHP 5. Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle() /drupal/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php:50
PHP message: PHP 6. Drupal\page_cache\StackMiddleware\PageCache->handle() /drupal/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php:47
PHP message: PHP 7. Drupal\page_cache\StackMiddleware\PageCache->pass() /drupal/core/modules/page_cache/src/StackMiddleware/PageCache.php:78
PHP message: PHP 8. Drupal\Core\StackMiddleware\KernelPreHandle->handle() /drupal/core/modules/page_cache/src/StackMiddleware/PageCache.php:99
PHP message: PHP 9. Drupal\Core\StackMiddleware\Session->handle() /drupal/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php:47
PHP message: PHP 10. Symfony\Component\HttpKernel\HttpKernel->handle() /drupal/core/lib/Drupal/Core/StackMiddleware/Session.php:57
PHP message: PHP 11. Symfony\Component\HttpKernel\HttpKernel->handleRaw() /drupal/vendor/symfony/http-kernel/HttpKernel.php:64
PHP message: PHP 12. call_user_func_array:{/drupal/vendor/symfony/http-kernel/HttpKernel.php:144}() /drupal/vendor/symfony/http-kernel/HttpKernel.php:144
PHP message: PHP 13. Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() /drupal/vendor/symfony/http-kernel/HttpKernel.php:144
PHP message: PHP 14. Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapp
2017/02/16 22:25:55 [error] 1659#0: *27 FastCGI sent in stderr: "ssage: PHP 28. Drupal\Core\Entity\ContentEntityForm->copyFormValuesToEntity() /drupal/core/lib/Drupal/Core/Entity/EntityForm.php:291" while reading response header from upstream, client: 33.33.33.1, server: drupal.local, request: "POST /admin/structure/slide/add HTTP/1.1", upstream: "fastcgi://unix:/var/run/php5-fpm.sock:", host: "33.33.33.12", referrer: "http://33.33.33.12/admin/structure/slide/add"
#Do Something with the submitted data
After all that is done, something has to happen with the data. The form class needs a submitForm
method as follows:
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->processData($form['slide_name']['#value'], $form['slide_img']['#files']);
}