Step by step guide to creating an admin form in Drupal 8

Creating an admin form is often one of the first things you'll need to do in a custom Drupal module. An admin interface enables you to make a module's settings configurable by a site editor or administrator so they can change them on the fly.

If you've created admin forms in Drupal 7 previously, you'll see some pretty big differences in the way you define forms between Drupal 7 and Drupal 8, and there are still a lot of similarities. Forms are represented as nested arrays in both Drupal 7 and Drupal 8. But they are different in that in Drupal 7 you define your form arrays in functions and in Drupal 8 you create a form class.

In this step by step tutorial, you are going to learn how to create an admin form in Drupal 8 with a route and menu item and then use the saved form data.

It is worth pointing out that you could create most of this code with the Drupal Console. However, the best way to truly learn it is to write the code without using tools like Console to create it for you. After that, it is a create idea to use Drupal Console to create code like this for you. To learn more, you can check out my 7 day course.

Step 1: Module setup

Create the module folder

  • Create a new directory in /sites called all
  • Inside all create a directory modules
  • Create the directory called welcome inside the modules directory

Create the YAML info file

The info YAML file tells Drupal that your module exists and provides important information, such as its human readable name, machine name, description and version number.

The filename should be the machine name of your module with the .info.yml extension. In this case, it will be welcome.info.yml.

Create welcome.info.yml in the root of the welcome directory.

Add the following to welcome.info.yml:

name: Welcome  
type: module  
description: Display a message when a user logs in  
core: 8.x  
package: Custom  

The info.yml file is all you need to register the module with the Drupal system. If you head on over to Extend, you will see the Welcome module listed.

You can go ahead and enable the module (click install at the bottom of the Extend page or use Drush).

Setup the rest of the files and folders

Setup the following files and folders in the welcome module folder:

  • Create a file called welcome.routing.yml.
  • Create a file called welcome.links.menu.yml.
  • Create a file called welcome.module
  • Create a folder called src.
  • In the src folder, create a new folder called Form.
  • In the Form folder, create a file called MessagesForm.php.

Module file structure

Your module file structure should now look like this:

Drupal 8 admin form structure

Step 2: Create form

There are a few parts to creating an admin form:

  • The form itself
  • A route mapping the form to a URL, so that you can access it
  • A menu item in Drupal’s menu system, so that it can be accessed from the admin menu

Set out basic class

In MessagesForm.php, set out the basic class:

<?php  
/**  
 * @file  
 * Contains Drupal\welcome\Form\MessagesForm.  
 */  
namespace Drupal\welcome\Form;  
use Drupal\Core\Form\ConfigFormBase;  
use Drupal\Core\Form\FormStateInterface;  

class MessagesForm extends ConfigFormBase {  

}  

ConfigFormBase is a base class that is used to implement system configuration forms.

Methods to use

You are going to add the following methods to this class:

  • getEditableConfigNames() - gets the configuration name
  • getFormId() - returns the form’s unique ID
  • buildForm() - returns the form array
  • validateForm() - validates the form
  • submitForm() - processes the form submission

Add getEditableConfigNames() and getFormId()

Start off by adding getEditableConfigNames() and getFormId():

<?php  

/**  
 * @file  
 * Contains Drupal\welcome\Form\MessagesForm.  
 */  

namespace Drupal\welcome\Form;  

use Drupal\Core\Form\ConfigFormBase;  
use Drupal\Core\Form\FormStateInterface;  

class MessagesForm extends ConfigFormBase {  
  /**  
   * {@inheritdoc}  
   */  
  protected function getEditableConfigNames() {  
    return [  
      'welcome.adminsettings',  
    ];  
  }  

  /**  
   * {@inheritdoc}  
   */  
  public function getFormId() {  
    return 'welcome_form';  
  }  
}  

The buildForm() method

Next you can add the buildForm method to the MessagesForm class.

  /**  
   * {@inheritdoc}  
   */  
  public function buildForm(array $form, FormStateInterface $form_state) {  
    $config = $this->config('welcome.adminsettings');  

    $form['welcome_message'] = [  
      '#type' => 'textarea',  
      '#title' => $this->t('Welcome message'),  
      '#description' => $this->t('Welcome message display to users when they login'),  
      '#default_value' => $config->get('welcome_message'),  
    ];  

    return parent::buildForm($form, $form_state);  
  }  

Breakdown of buildForm()

Let’s break this down and see what each part is doing. 

$config = $this->config('welcome.adminsettings');  

This initialises the config variable. welcome.adminsettings is the module's configuration name, so this will load the admin settings.  

There is just one element to this form, the welcome message textarea:

      $form['welcome_message'] = [  
        '#type' => 'textarea',  
        '#title' => $this->t('Welcome message'),  
        '#description' => $this->t('Welcome message display to users when they login'),  
        '#default_value' => $config->get('welcome_message'),  
      ];  

The default value is returned from the configuration object. It calls the get() method with the name of the property to get, which is welcome_message. You will add the code to save this when the form saves shortly.

The title and description are displayed when you view the form.

Step 2: Save form data

The submitForm() method

Next you can add the submitForm method.

  /**  
   * {@inheritdoc}  
   */  
  public function submitForm(array &$form, FormStateInterface $form_state) {  
    parent::submitForm($form, $form_state);  

    $this->config('welcome.adminsettings')  
      ->set('welcome_message', $form_state->getValue('welcome_message'))  
      ->save();  
  }  

The submitForm() method is responsible for saving the form data when the form is submitted. Take a look at the code inside the method:

    $this->config('welcome.adminsettings')  
      ->set('welcome_message', $form_state->getValue('welcome_message'))  
      ->save();  

Let’s break this down line by line:

  • $this is the admin settings form class.
  • -> is an object operator
  • config('welcome.adminsettings’): welcome.adminsettings is the name of the module's configuration.
  • ->set('welcome_message', $form_state->getValue('welcome_message’)): here it is setting ‘welcome_message’ and get the values from the form state.
  • ->save: save the form data.

Setting and Getting Configuration Objects

In the previous section, you have set the value for a configuration object in the submit function. And then in the method which defines the form, you have retrieved the configuration and configuration setting.

In submitForm(), retrieve the configuration:

$this->config('welcome.adminsettings')  

Also in submitForm(), set the configuration setting:

 ->set('welcome_message', $form_state->getValue('welcome_message'))  

In buildForm(), retrive the configuration:

$config = $this->config('welcome.adminsettings');  

Also in buildForm(), get the configuration setting:

$config->get('welcome_message'),  

Drupal 8 form configuration

Step 3: Access the form

The route

In order to access the form you just created, you need to add a route for it. This will map the URL to the form.

Open up welcome.routing.yml and add the following route:

welcome.admin_settings_form:  
  path: '/admin/config/welcome/adminsettings'  
  defaults:  
    _form: '\Drupal\welcome\Form\MessagesForm'  
    _title: 'MessagesForm'  
  requirements:  
    _permission: 'access administration pages'  
  options:  
    _admin_route: TRUE  

The route is mapping to a form controller (\Drupal\welcome\Form\MessagesForm). When you go to /admin/config/welcome/adminsettings you will get that form. 

Messages Form

If you add a message and submit the form and then refresh the page, the message will remain in the textarea as it is now saved to the database and used as the default message for the form field.

Clear the cache and then go to /admin/config/welcome/adminsettings to get the form.

Menu item

With the route mapped to the form controller, you can hit the URL to get the form.  To make this more useful, we need to add it to Drupal’s menu system. 

As mentioned previously, Drupal 8 defines menu items in a .yml file. Add the following to welcome.links.menu.yml:

welcome.admin_settings_form:  
  title: 'Welcome message configuration'  
  route_name: welcome.admin_settings_form  
  description: 'Welcome message admin'  
  parent: system.admin_config_system  
  weight: 99  

Let’s break this down:

  • Title: This will appear as the menu link. 
  • Route: This is the route that you defined earlier. This maps to the form class.
  • Description: This will appear under the title
  • Parent: This menu item will be nested under the parent menu item
  • Weight: This determines the relative positioning of the menu item in relation to its siblings

After you clear the cache, you should now see this in menu item under admin/config.

Step 4: use the form data

You could use the saved form data in a variety of places. To demonstrate its use, you are how to show the saved message to users when they login to the site.

To do that, you need to add an implementation of hook_user_login() to retrieve the config value.

In welcome.module, create welcome_user_login():

<?php

/**
 * @file
 * Contains welcome.module.
 */

function welcome_user_login() {

}

You can get the configuration for the module using the Drupalconfig() static method with the name of the module’s configuration (welcome.adminsettings).

$config = \Drupal::config('welcome.adminsettings');  

And then get the value for the welcome_message property with the get() method:

$config->get('welcome_message')  

Putting it all together in the hook implementation:

function welcome_user_login($account) {  
  $config = \Drupal::config('welcome.adminsettings');  
  drupal_set_message($config->get('welcome_message'));  
}  

Next, clear the cache for the changes to take effect.

And now, when you log out of the site and log back in again, you should see the message.

Wrapping up

You have created a simple admin form, saved the value to the database and then used that saved value and displayed it to users when they login.

Comments

Simply, no need for all that complexity and all those extra gets / these's and those's. Drupal 7 wins. No need to break ones head trying to learn all that non logical verbose system. Not to mention that it is 3x times slower than Drupal 7 for authenticated users.

I tried your steps, but get the following error, if I save the admin form:

Drupal\Core\Config\ImmutableConfigException: Can not set values on immutable configuration manifest.adminsetting:name. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object in Drupal\Core\Config\ImmutableConfig-&gt;set() (line 27 of root\core\lib\Drupal\Core\Config\ImmutableConfig.php).

What does this mean?

Add new comment