Astuce [D8] Ajouter des pages de configuration

Pour rendre votre site plus facilement paramétrable, il est utile de fournir une interface d'administration pour modifier telle ou telle option.

Ces options seront ensuite accessibles partout dans votre code :

$config = \Drupal::config('mon_module.settings');
$my_option_value = $config->get('my_option');

Comme son prédécesseur, Drupal 8 permet de générer rapidement ces interfaces, ainsi que les éléments du menu d'administration correspondant :

Page d'administration en back-office

Pour générer deux pages de formulaires avec des onglets pour passer de l'un à l'autre, vous aurez besoin des fichiers suivants :

Arborescence nécesaire

Remarque :

L'exemple qui suit requiert d'activer ces deux modules : admin_toolbar et admin_toolbar_tools.

Création d'un formulaire d'administration

Voici un exemple de formulaire d'administration affichant trois champs, de types numérique, texte riche et email.

Structure générale

<?php

namespace Drupal\my_module\Form;

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

/**
 * Gère le formulaire de configuration générale pour le module.
 */
class GlobalSettingsForm extends ConfigFormBase {

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

  /**
  * {@inheritdoc}
  */
  protected function getEditableConfigNames() {
    return [
      'my_module.settings',
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {

  }

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

  }

}

Explications :

  • Le formulaire hérite de la classe abstraite ConfigFormBase, fournie par Drupal.
  • En plus des méthodes getFormId(), buildForm() et submitForm() habituelles, elle impose que la méthode getEditableConfigNames() soit implémentée.
  • Cette méthode permet de définir un "namespace" pour votre configuration. Chaque propriété devra avoir un id unique au sein du même "namespace".

Méthodes buildForm() et submitForm()

/**
  * {@inheritdoc}
  */
public function buildForm(array $form, FormStateInterface $form_state) {

  // Récupération de la configuration avec le "namespace" my_module.settings
  $config = $this->config('my_module.settings');

  $form['nb_news_homepage'] = array(
    '#type' => 'number',
    '#title' => $this->t('Nombre d\'actualités afichées en page d\'accueil'),
    '#default_value' => $config->get('nb_news_homepage'),
  );

  $form['welcome_text'] = array(
    '#type' => 'text_format',
    '#title' => $this->t('Texte de bienvenue'),
    '#description' => $this->t('Texte affiché en page d\'accueil.'),
    '#default_value' => $config->get('welcome_text'),
  );

  $form['contact_receiver_email'] = array(
    '#type' => 'email',
    '#title' => $this->t('Adresse email du destinataire pour le formulaire de contact'),
    '#default_value' => $config->get('contact_receiver_email'),
  );

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

/**
 * {@inheritdoc}
 */
public function submitForm(array &$form, FormStateInterface $form_state) {
  $this->config('my_module.settings')
    ->set('nb_news_homepage', $form_state->getValue('nb_news_homepage', 5))
    ->set('welcome_text', $form_state->getValue('welcome_text', '<p>Texte de bienvenue à changer.</p>')['value'])
    ->set('contact_receiver_email', $form_state->getValue('contact_receiver_email', 'admin@monsite.com'))
    ->save();

  parent::submitForm($form, $form_state);
}

Explications :

La méthode buildForm() est semblable à celle d'un formulaire classique. À noter cependant :

  • Pour récupérer les valeurs présentes en base et préremplir les champs, on utilise la méthode config(), avec le "namespace" définit précédemment
  • Chaque valeur est accessible individuellement, via un simple getter
  • La méthode parente est appelée

La méthode submitForm() va enregistrer les données soumises en base :

  • Les configurations actuelles sont récupérées
  • Les nouvelles valeurs sont mises à jour, puis sauvegardées
  • La méthode parente est appelée

Remarque :

Pour un champ texte riche, la méthode getValue() proposée par FormStateInterface retourne un tableau et non pas une valeur enregistrable en base.

Il faut penser à ajouter ['value'] derrière, pour avoir une chaîne de caractère utilisable.

Configuration du menu

my_module.routing.yml

C'est le fichier classique de Drupal, permettant de lier des URL à vos contrôleurs et formulaires.

# Page générale listant les pages de configuration du module
my_module.overview:
  path: '/admin/config/my_module'
  defaults:
    _controller: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage'
    _title: 'Mon module - Configuration'
    link_id: 'my_module.overview'
  requirements:
    _permission: 'administer site configuration'

# Page de configuration générale du module
my_module.settings:
  path: '/admin/config/my_module/general'
  defaults:
    _form: '\Drupal\my_module\Form\GlobalSettingsForm'
    _title: 'Mon module - Configuration générale'
  requirements:
    _permission: 'administer site configuration'

# Page de configuration des webservices du module
my_module.webservices.settings:
  path: '/admin/config/my_module/webservices'
  defaults:
    _form: '\Drupal\my_module\Form\WebservicesSettingsForm'
    _title: 'Mon module - Configuration des webservices'
  requirements:
    _permission: 'administer site configuration'

Explications :

  • Les deux dernières routes sont classiques. Elles pointent vers vos nouvelles pages de formulaire de configuration.
  • La première pointe vers un contrôleur fourni par Drupal, qui permet de lister des sous-pages (ex: http://www.monsite.com/admin/config/people)

my_module.links.menu.yml

Ce fichier définit de nouveaux éléments dans le menu d’administration.

# Page générale listant les pages de configuration du module
my_module.overview:
  title: 'Mon module'
  parent: system.admin_config
  description: 'Voir les pages de configuration du module "Mon module".'
  route_name: my_module.overview
  weight: -100

# Page de configuration générale du module
my_module.settings:
  title: 'Général'
  parent: my_module.overview
  description: 'Gérer la configuration générale du module.'
  route_name: my_module.settings
  weight: -10

# Page de configuration des webservices du module
my_module.webservice.settings:
  title: 'Webservices'
  parent: my_module.overview
  description: 'Gérer la configuration des webservices.'
  route_name: my_module.webservices.settings
  weight: -5

Explication :

Pour chaque lien souhaité, on définit :

  • le libellé (title)
  • la description au survol (attribut title pour le lien généré)
  • l'élément de menu parent
  • la route vers laquelle pointer
  • le poids de l'élément (le plus petit apparaîtra en premier)

Dans cet exemple, la page "overview" est parente des deux autres.

my_module.links.task.yml

Ce fichier définit des onglets accessibles dans les pages d'administration. Depuis la première page, on a donc un lien rapide vers la seconde, et vice-versa.

my_module.settings:
  route_name: my_module.settings
  title: 'Général'
  base_route: my_module.settings

my_module.webservices.settings:
  route_name: my_module.webservices.settings
  title: 'Webservices'
  base_route: my_module.settings

Explication :

Pour chaque onglet souhaité, on définit :

  • le libellé (title)
  • la route vers laquelle pointer
  • l'onglet principal