Adding a settings form to a custom module

25 April, 2024

Often a custom module will have configuration settings that can be provided by an administrator. In Drupal 7, the form used for this purpose was provided via form code including a form array, typically encoded in an admin.inc file, and a hook_menu implantation in the .module file. 

It will probably come as no surprise that things are done differently in Drupal 8. So, let's go step-by-step through the creation of a custom module, example, and its settings page.

my_example.info.yml

The .info.yml file is the only file required for a module, and it doesn't need to contain much. Place it in the module root folder, modules/custom/my_example


name: my example
type: module
description: a module to use in my tutorial.
core: '8.x'
configure: my_example.settings

The configure entry uses the routing from the .routing.yml file. This entry results in a configure link being presented when the accordion control for the module is opened on the module admin page.

my_example.routing.yml

The .routing.yml file has a few purposes:

  • Establish the path for the configuration settings page
  • Tie the configuration settings page to its form
  • Declare the permissions necessary to access the page

This file will also be placed in the module root folder.


my_example.settings:
  path: '/admin/config/system/my_example/config'
  defaults:
    _form: '\Drupal\my_example\Form\Settings'
    _title: 'My Example'
  requirements:
    _permission: 'administer site configuration'

In the file, above, note that the prefix to .settings, my_example, matches the module name, and is again used in the _form reference.

my_example.links.menu.yml

Why doesn't my module have a configuration link on the admin configuration page? More often than not, the answer to this and similar questions is that this file wasn't created. The .link.menu.yaml file provides the missing link, so to speak, and like the preceding yaml files should be placed in the module's root folder.


my_example.settings:
  title: 'My Example'
  description: 'A module to use in my tutorial.'
  route_name: my_module.settings
  parent: system.admin_config_system

Note that the first line matches the name used in the .routing.yml file as does the route_name further down in the file. The parent setting determines where on the admin/config page and menu the link will appear, in the System section in this case.

Settings.php

The final file is the one that provides the settings form. Its name matches the last item in the _form setting in the .routing.yml file. It should be placed in the path /src/Form.


 
namespace Drupal\my_example\Form;
 
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
 
/**
* Configure settings for this site.
*/
class Settings extends ConfigFormBase {
/**
 * {@inheritdoc}
 */
  public function getFormId() {
    return 'my_example_settings';
  }
 
/**
 * {@inheritdoc}
 */
  protected function getEditableConfigNames() {
    return [
      'my_example.settings',
    ];
  }
 
/**
 * {@inheritdoc}
 */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $config = $this->config('my_example.settings');
 
    $form['sample_setting'] = array(
      '#type' => 'textfield',
      '#title' => $this->t('Sample setting'),
      '#description' => $this->t('A sample setting for our module.'),
      '#default_value' => $config->get('sample_setting'),
    );
 
    return parent::buildForm($form, $form_state);
  }
 
/**
 * {@inheritdoc}
 */
  public function submitForm(array &$form, FormStateInterface $form_state) {
      // Retrieve the configuration
       $this->configFactory->getEditable('my_example.settings')
      // Set the submitted configuration setting
      ->set('sample_setting', $form_state->getValue('sample_setting'))
      ->save();
 
    parent::submitForm($form, $form_state);
  }
}

A few things to note in this file:

  • The class name matches the form name given in _form setting of the .routing.yml file
  • The method names should always be as listed
  • getFormId() returns the ID of the form
  • getEditableConfigNames() returns the name from the first line of the .routing.yml file
  • buildForm() loads the saved config, if any, based on the same routing entry, and creates the config form
  • The #default_value line in the form item retrieves the last saved value, if any, for that field
  • submitForm() uses the same routing entry and saves the values of the enumerated field(s)

Login or Register to Comment!