Drupal ( 10 / 39 articles - Voir la liste )

Erreur [D8] Erreur lors de l'upgrade de Drupal à propos du module Views

Lors de la mise à jour de Drupal (par exemple de 8.3.7 vers 8.4.3), vous pouvez rencontrer ce genre d'erreur :

$ drush updb -y
The following updates are pending:

views module : 
  Fix table names for revision metadata fields.

Do you wish to run all pending updates? (y/n): y
Après la mise à jour de views                                                    [ok]
Failed: InvalidArgumentException : The configuration property                      [error]
display.default.display_options.filters.my_custom_filter_id.value.2 doesn't
exist. dans Drupal\Core\Config\Schema\ArrayElement->get() (ligne 76 de
/var/www/ftvpro/web/core/lib/Drupal/Core/Config/Schema/ArrayElement.php).
Cache rebuild complete.                                                            [ok]
Finished performing updates.

Le module Views est incapable de mettre à jour la base de données correctement, à cause d'un filtre de vue.

Pour éviter ça, cherchez dans vos modules (ou ceux communautaires que vous utilisez) le filtre de vue en question. (Ici my_custom_filter.) Le module qui déclare ce filtre doit également proposer une mise à jour de la base via un fichier yaml. Pour cet exemple, le module my_module doit contenir le fichier config/schema/my_module.views.schema.yml :

# Schema for the views plugins of the my_module module.

views.filter.my_custom_filter:
  type: views.filter.in_operator
  label: 'My custom view filter'

Si ce n'est pas le cas, crééz-le et relancer la commande drush updb.

Remarque : Si on regarde le fichier comment.views.schema.yml que propose le module Comment, on y trouve aussi ce genre de déclarations :

views.argument.argument_comment_user_uid:
  type: views_argument
  label: 'Commented user ID'

views.field.comment_depth:
  type: views_field
  label: 'Comment depth'

views.row.comment_rss:
  type: views_row
  label: 'Comment'
  mapping:
    view_mode:
      type: string
      label: 'Display type'

views.sort.comment_ces_last_comment_name:
  type: views_sort
  label: 'Last comment name'

Le problème peut donc sûrement se produire pour les arguments, les champs, les lignes et les tris des vues déclarés dans les modules.

Astuce [d8] Ajouter des variables dans un render array existant

Les render array sont utilisés partout dans Drupal, pour générer des affichages. Lorsqu'on crée un bloc côté PHP, il retourne un render array. Même chose pour un formulaire ou pour un contrôleur.

Les modules peuvent définir leurs propres apparences pour les éléments : ils peuvent décrire de nouveaux render array (hook_theme()) qui seront ensuite utilisables partout.

Pour ajouter des variables à un render array proposé par un autre module, il faut tout d'abord modifier sa définition, pour que la variable puissent être transmise au template. On utilise pour cela le hook_theme_registry_alter().

/**
 * Implements hook_theme_registry_alter().
 */
function mon_module_theme_registry_alter(&$theme_registry) {
  $theme_registry['nom_du_render_array']['variables']['nouvelle_variable'] = 'valeur_par_defaut';
}

Maintenant que la variable "est autorisée", il faut l'ajouter au render array existant. Il s'agit d'un simple hook_preprocess_HOOK().

/**
 * Implements hook_preprocess().
 */
function mon_module_preprocess_nom_du_render_array(&$variables) {
  $variables['nouvelle_variable'] = 'valeur de la variable';
}

Explication :

  • nom_du_render_array est la clé définie dans le hook_theme() du module qui le propose. C'est celle qu'on renseigne lorsqu'on utilise le render array ('#theme" => 'nom_du_render_array').
  • C'est cette clé qu'on utilise dans le nom de notre fonction hook_preprocess_HOOK().

Remarque :

Comme après chaque implémentation de hook(), pensez à vider les caches.

Astuce [D8] Ajouter un bouton d'action en back-office

Lorsque vous êtes sur la page qui liste les types de contenu par exemple, il y a le bouton Ajouter un type de contenu en haut à gauche.

Plus généralement, lorsqu'on liste des éléments (nœuds, liens de menu, ...), on propose souvent un lien pour en ajouter de nouveaux.

Si vous utilisez les vues Drupal pour ajouter des pages de liste en back-office, vous vous voudrez probablement ce genre de bouton. Cela ne se fait pas dans la configuration de la vue, mais via un fichier my_module.links.action.yml. Par exemple :

# Article
node.add.article
  route_name: node.add
  route_parameters:
    node_type: article
  title: 'Ajouter un Temps Fort'
  appears_on:
    - view.my_view_article.display_1
    - view.other_view.display_name

Explication :

On indique

  • la route (et ses paramètres) vers laquelle devra pointer le bouton d'action
  • le libellé du bouton (title)
  • sur quelle(s) page(s) il devra apparaître (= ids de routes)

Remarque :

Pour une vue, l'id de la route est composée du préfixe 'view', du nom technique de la vue, puis du nom technique de l'affichage de la vue (une vue pouvant avoir plusieurs affichages).

Ces deux ID techniques sont visibles dans l'URL lorsque vous éditez un affichage d'une vue. Ex : http://www.mysite.fr/admin/structure/views/view/`my_view_article`/edit/`display_1`.

Astuce Le module Help

Le module Help fait partie du cœur de Drupal et est activé par défaut.

Il permet d'ajouter un message au haut de la page d'édition d'un contenu : Message formulaire d'édition

Pour cela il suffit d'éditer votre type de contenu, et de remplir la zone de texte sous le champ title (le HTML est accepté) :

Configuration du module Help

Pour que le message apparaisse dans le formulaire d'édition, il faudra que le bloc Aide soit activé dans une des régions de votre thème d'administration. C'est le cas pour celui par défaut (Seven).

Astuce Modifier un élément de liste dans un formulaire

Pour ajouter une classe CSS sur un élément de formulaire basique (input, select, ...), on ajoute la clé #attributes à son render array.

Par contre pas possible de le faire pour une liste de boutons radio par exemple. La classe s'ajoutera sur le conteneur à la place.

Il existe donc la clé #after_build pour remédier à ce problème (cf. documentation). Elle attend une liste de noms de fonction en valeur.

Chacune de ces fonctions sera exécutée après coup pour modifier le render array de l'élément. À ce moment de l'exécution, les sous-éléments (ici les boutons radio) ont déjà été ajoutés et peuvent donc être modifiés.

Par exemple dans ma méthode buildForm() :

$form['my_field'] = [
  '#type' => 'radios',
  '#title' => t('My field'),
  '#options' => [
    0 => t('No'),
    1 => t('Yes'),
  ],
  '#after_build' => ['_my_module_radio_add_class']
];

Et dans mon fichier my_module.module :

function _my_module_radio_add_class(array $element, FormState $form_state) {
  $options = array_keys($element['#options']);

  // Parcours des sous-éléments options
  foreach ($options as $values) {
    $element[$values]['#attributes']['class'][] = 'myclass';
  }
  return $element;
}

Astuce Rediriger en 404 ou 403

Si vous voulez rediriger l'utilisateur vers la page 404 ("Page introuvable") ou 403 ("Vous n'avez pas le droit d’accéder à cette page") de Drupal, vous utilisiez sans doute ça en Drupal 7 :

return drupal_access_denied();
return drupal_not_found();

Voici l'équivalent pour Drupal 8 :

use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

throw new AccessDeniedHttpException();
throw new NotFoundHttpException();

Astuce Drupal dans un sous-répertoire

Si vous utilisez Drupal dans un sous-répertoire servi par Apache (ex : /var/www/html/mon_site), ou derrière un reverse proxy qui ajoute un contexte à l'URL (ex : http://mon-domaine.fr/mon-contexte), il est possible que seule la page d'accueil fonctionne.

Vous aurez alors une erreur 404 sur toutes les autres pages (ex : http://mon-domaine.fr/mon-contexte/user/login).

Il vous faut alors modifier le .htaccess à la racine du site, en modifiant la ligne :

# RewriteBase /

Décommentez-la et remplacer le / par le contexte ou le sous-répertoire. Ex :

# Modify the RewriteBase if you are using Drupal in a subdirectory or in a
# VirtualDocumentRoot and the rewrite rules are not working properly.
# For example if your site is at http://example.com/drupal uncomment and
# modify the following line:
# RewriteBase /drupal
#
# If your site is running in a VirtualDocumentRoot at http://example.com/,
# uncomment the following line:
RewriteBase /mon-contexte

Erreur The following module is missing from the file system

Si vous installez un module dans Drupal et que vous en supprimez les fichiers avant de le désinstaller, vous pouvez rencontrer une erreur du genre :

The following module is missing from the file system: 
paragraphs in drupal_get_filename() (line 240 of core/includes/bootstrap.inc).

Pour Drupal, le module est désinstallé. Pourtant, il en garde des traces et cela cause cette erreur.

Deux solutions sont alors possibles :

  • Réinstaller le module, puis le désinstaller correctement
  • Supprimer la référence en base, via la requête suivante :
drush sql-query "DELETE FROM key_value WHERE collection='system.schema' AND name='module_name';"

Astuce [D8] Installer la dernière version de drush

Sur les dépôts des distributions linux, c'est souvent une vieille version de drush qui est disponible (ex: Debian 8.4 -> drush 5.x). Voici comment installer la dernière.

Prérequis

Composer et Git doivent être installés.

Composer

sudo apt-get install curl
sudo curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer

# Vérification
composer --version

GIT

sudo apt-get install git

# Vérification
git --version

Installation

  • Téléchargez drush :
sudo git clone --depth 1 https://github.com/drush-ops/drush.git /usr/local/src/drush
  • Mettez-le à jour :
cd /usr/local/src/drush
sudo composer install
  • Créez les liens symboliques suivant :
sudo ln -s /usr/local/src/drush/drush /usr/local/bin/drush
sudo ln -s /usr/local/src/drush/drush.complete.sh /etc/bash_completion.d/drush
  • Vérifiez l'installation :
drush --version

Astuce [d8] Surcharger l'affichage d'une page existante

Drupal 8 propose nativement des pages pour gérer l'inscription, la connexion, l'oubli de mot passe.

Malheureusement actuellement il n'y a pas de suggestion de template proposée. (Comme on peut le voir habituellement en commentaire dans le code source lorsque le mode debug est activé.)

Il faut donc procéder autrement et utiliser les hook_form_alter() et hook_theme() classiques.

Par exemple, pour surcharger le formulaire de la page oubli de mot de passe :

// mymodule.module

/**
 * Implements hook_form_alter()
 */
function mymodule_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {

  // Si le formulaire est celui d'oubli de mot de passe
  if ($form_id == 'user_pass') {
    $form['#theme'] = ['my_register_form'];
  }
}

/**
 * Implements hook_themer()
 */
function mymodule_theme(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {

  return [
    'my_password_form' => [
      'template' => 'user_forget_password_form',
      'render element' => 'form',
    ],
  ];
}

Explications :

  • Le hook_form_alter() permet de modifier le thème à utiliser pour le formulaire. Le thème choisi doit exister ou être déclaré dans votre module.
  • Le hook_theme() permet de déclarer le nouveau thème my_password_form et d'y affecter un template spécifique.

Remarque :

Par défaut, sans cette configuration, le template natif form.html.twig serait utilisé. Pour créer votre propre template il peut donc être pratique d'en faire une copie, la renommer (ici user_forget_password_form.html.twig) et de s'en servir comme base pour effectuer vos modifications.