D7 icon passing the baton to D8 icon

Portage du module Drupal 7 vers Drupal 8 sur l'exemple des Cookies

Le temps a déjà passé depuis la première de Drupal 8. De nouveaux projets et modules sont publiés tout le temps, et il y a un nombre toujours croissant de projets compatibles avec la version 8.x sur drupal.org. Malheureusement, ces versions sont souvent encore instables et remplies de divers bugs. À ce jour, le nombre de modules supplémentaires disponibles pour Drupal 8 est d'environ 2 250, contre 12 400 modules Drupal 7. Il est immédiatement visible que la gamme de solutions prêtes à l'emploi est beaucoup plus étroite dans le cas de la nouvelle génération, comparée à l'ancienne. Cependant, même si dans le cas de projets avancés, les écrire à partir de zéro pourrait être inutile, dans le cas des petits ajouts, nous pouvons essayer de transférer l'ensemble du module ou ses fonctionnalités intéressantes à la version 8.x. Étant une  agence Drupal, nous devons effectuer un tel développement Drupal assez souvent. Dans ce guide, nous allons transférer un module utilisé par nous pour afficher la notification de cookies sur notre site web afin qu'il soit utilisé avec Drupal 8.

image de la structure v. 7.x

Voici à quoi ressemble la structure de fichiers de la version 7.x. Le module est relativement simple, car il contient un fichier CSS personnalisé, un JavaScript, deux modèles, un fichier .inc inclus et les fichiers standards .info et .module.
Pour que le script soit visible par Drupal 8, nous aurons besoin d'un fichier .info.yml. Commençons par celui-ci. Dans Drupal 8, c'est le seul fichier requis pour que le module soit visible par le système.

1. Fichiers d'information :

Drupal 7

cookiec.info

name = CookieC
description = Ce module vise à rendre le site web conforme au nouveau règlement de l'UE sur les cookies
core = 7.x

 

Drupal 8

cookiec.info.yml

name: CookieC
type: module
core: 8.x
version: 8.x-1.0
description: Ce module vise à rendre le site web conforme au nouveau règlement de l'UE sur les cookies
configure: cookiec.settings


Les fichiers sont assez similaires - comme vous pouvez le voir, la principale différence ici est le format du fichier. Puisque Drupal 8 utilise les fichiers YML, le fichier doit avoir une extension .info.yml. De plus, nous devons également ajouter type : car les skins utilisent une syntaxe similaire, dans notre cas ce sera type : module. De plus, dans ce fichier, nous pouvons ajouter 'configure :' - un crochet de routage vers la page de configuration. Cependant, nous allons parler du routage dans la prochaine partie. Il convient de mentionner que - tout comme en Python - les indentations dans le code sont essentielles. Après avoir purgé le cache, le module doit déjà être visible dans la liste.

CookieC visible sur la liste

2. Fichier .module et hooks


Voyons maintenant ce qu'on peut trouver dans un fichier .module de D7. Notre module utilise les hooks/fonctions suivants :

  • hook_menu – utilisé pour définir la page /cookiec, qui affiche notre politique sur les cookies,
  • hook_init – utilisé pour initier notre fonctionnalité, incluant la fonction chargeant nos fichiers css et js personnalisés,
  • hook_permission – permission pour administrer notre module,
  • hook_theme – définitions de modèles.

Dans D8 hook_menu, hook_permission et hook_init ont été supprimés.
Les tâches de hook_menu sont désormais couvertes par “module_name.routing.yml”, et au lieu de hook_init nous allons utiliser EventSubscriber.
 

3. Migration de hook_menu

Drupal 7

Hook menu inclus dans le fichier .module

<?php
/**
 * Implémente hook_menu().
 */
function cookiec_menu() {
 $items['cookiec'] = array(
   //'title' => '',
   'description' => 'Page de la politique sur les cookies.',
   'page callback' => 'cookiec_policy_page',
   'access arguments' => array('access content'),
   'file' => 'cookiec.page.inc',
 );
 return $items;
}

 

Drupal 8

Contenu du fichier cookiec.routing.yml:

cookiec.render_cookiec:
  path: '/cookiec'
  defaults:
    _controller: '\Drupal\cookiec\Controller\Cookiec::renderPage'
    _title: ''
  requirements:
    _permission: 'access content'


Le fichier *.routing.yml contient le nom du routage – cookiec.render_cookiec.
Path: adresse URL, nous permettant d'accéder à une fonctionnalité donnée ; comme dans D7, nous pouvons également utiliser des chemins dynamiques, comme par exemple : path: 'example/{user}', dans ce cas il ne sera pas nécessaire, puisque notre module n'affiche qu'une page statique.
defaults: _controller: ’\Drupal\cookiec\Controller\Cookiec::renderPage’ au contenu de /cookiec sera affiché, retourné par la classe Cookiec utilisant la méthode renderPage(). Nous en parlerons en détail lors de la création de la page statique /cookiec.
Requirements: Nous allons ajouter des permissions d'accès dans _permission: access content.
Nous devrions créer toutes les classes et méthodes assignées à nos routages à la fois pour éviter d'afficher des erreurs.
Nous allons créer un simple exemple "Hello World". Commençons par créer un fichier Cookiec.php dans /src/Controller:

namespace Drupal\cookiec\Controller;

use Drupal\Core\Controller\ControllerBase;

class Cookiec extends ControllerBase {

 function renderPage(){

  return array(
   '#title' => '',
   '#markup' => 'hello word!',
  );
 }
}


Après avoir purgé le cache et être allé sur /cookies, nous devrions obtenir une page disant "Hello World".
 

4. Migration de hook_permissions


Pour créer nos propres permissions, nous allons créer un fichier module.permission.yml, de manière similaire aux autres fichiers .yml :

administer cookiec:
 title: 'Administrer le module de message d’administration cookiec'
 description: 'Effectuer des tâches d’administration pour cookiec'


Nous ajoutons également ce qui suit à notre routage :

requirements:
 _permission: 'administer cookiec'


Utiliser la classe de formulaire est une solution utile dans ce cas.

cookiec.settings:
 path: '/admin/config/content/cookiec-settings'
 defaults:
  _form: '\Drupal\cookiec\Forms\CookiecSettingsForm'
  _title: 'configuration cookiec'
 requirements:
  _permission: 'administer cookiec'


Le nom du routage cookiec.settings sera placé dans le fichier info.yml (configure: cookiec.settings), grâce à quoi le bouton de configuration du module nous redirigera vers ce formulaire.
 

5. Migration de hook_init


Hook_init, qui dans D7 démarrait à chaque chargement de la page, a été supprimé dans D8. Afin d'obtenir une fonctionnalité similaire, nous allons utiliser les événements, en particulier EventSubscriber.
Pour créer un EventSubscriber dans Drupal 8, nous avons besoin d'un service. Nous créons un service comme d'autres fichiers .yml :
Ajoutez le code suivant à cookiec.service.yml :

services:
 cookiec_event_subscriber:
  class: Drupal\cookiec\EventSubscriber\CookiecSubscriber
  tags:
   – {name: event_subscriber}


Pour que notre service soit un Event Subscriber, nous devons créer une classe implémentant l'interface – EventSubscriberInterface. Pour qu'il fonctionne correctement, nous allons créer trois méthodes :
dans src/EventSubscriber/CookiecSubscriber.php

/**
 * @file Drupal\coociec\EventSubscriber\PopupMessageSubscriber
 */
namespace Drupal\cookiec\EventSubscriber;

use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;


/**
 * Classe PopupMessageSubscriber
 * @package Drupal\cookiec\EventSubscriber
 */
class CookiecSubscriber implements EventSubscriberInterface {

protected $config;
 /**
  * Constructeur CookiecSubscriber.
  */
 public function __construct() {
  $this->config = \Drupal::configFactory()->get('cookiec.settings');
 }

 public function showCookiecMessage(FilterResponseEvent $event) {
  // Vérifiez les permissions pour afficher le message.
  $response = $event->getResponse();

  if (!$response instanceof AttachmentsInterface) {
   return;
  }
 }

 /**
  * {@inheritdoc}
  */
 public static function getSubscribedEvents() {
  $events[KernelEvents::RESPONSE][] = array('showCookiecMessage', 20);

  return $events;
 }
}


Chargez les paramètres du module dans notre constructeur, qui seront ensuite passés au JavaScript.
Pour que notre événement fonctionne, nous devons ajouter la méthode getSubscribedEvents(), y mettre le nom de la méthode (showCookiecMessage) qui sera appelée et le poids (20). Nous pouvons utiliser le poids pour configurer l'ordre des événements.

 public static function getSubscribedEvents() {
  $events[KernelEvents::RESPONSE][] = array('showCookiecMessage', 20);

  return $events;
 }

6. Ajout des fichiers JS et CSS

Notre prochaine étape sera de transférer nos fichiers JS et CSS, dans notre cas, ils vont être laissés presque sans changements significatifs. Au lieu de cela, nous allons nous concentrer sur leur chargement lors de l'exécution de notre code.
Si nous voulons ajouter des fichiers JS ou CSS externes à notre module, nous pouvons créer un fichier nommé module.libraries.yml, dans notre cas ce sera cookiec.libraries.yml

cookiec_library:
 version: 1.x
 css:
  theme:
   css/cookiec.css: {}
 js:
  js/cookiec.js: {preprocess: false}


Nous avons ajouté ici les fichiers cookiec.css et cookiec.js. Si nous devions charger les bibliothèques existantes, nous pourrions les ajouter en utilisant des dépendances, par exemple :

 dependencies:
  – core/jquery

 
Pour charger nos bibliothèques maintenant, nous pouvons utiliser par exemple hook_preprocess_HOOK. Dans ce cas, nous devons ajouter ce qui suit à nos variables :

$variables['#attached']['library'][] = 'cookiec/cookiec_library';


Dans nos exemples, nous ajoutons nos fichiers dès le chargement de l'événement. Nous allons utiliser les méthodes suivantes pour y parvenir :

  $response = $event->getResponse();
  $attachments = $response->getAttachments();
  $attachments['library'][] = 'cookiec/cookiec_library';
  $response->setAttachments($attachments);


Notre module fait la majorité de sa magie côté client. Pour fonctionner correctement, notre script nécessite l'envoi de plusieurs paramètres. Les paramètres comme la hauteur, la largeur, le texte affiché ou la position sont envoyés au tableau drupalSettings en JS.

  $variables = array(
   'popup_enabled' => $config->get('popup_enabled'),
   'popup_agreed_enabled' => $config->get('popup_agreed_enabled'),
   'popup_hide_agreed' => $config->get('popup_hide_agreed'),
   'popup_height' => $config->get('popup_height'),
   'popup_width' => $config->get('popup_width'),
   'popup_delay' => $config->get('popup_delay')*1000,
   'popup_link' => $config->get($language."_link"),
   'popup_position' => $config->get('popup_position'),
   'popup_language' => $language,
   'popup_html_info' => $html_info,
   'popup_html_agreed' =>$html_agreed,
  );


Les valeurs des variables sont extraites des paramètres du module – configs. Nous en parlerons dans un instant.
Voici comment nous envoyons nos variables PHP au JS.

  $attachments['drupalSettings']['cookiec'] = $variables;


$html_info et $html_agreed stockent du code html, obtenus en analysant les modèles TWIG et les variables :

  $variables = array(
   'title' => 'title',
   'message' => $config->get($language."_popup_info"),
  );

  $twig = \Drupal::service('twig');
  $template = $twig->loadTemplate(drupal_get_path('module', 'cookiec') . '/templates/cookiec_info.html.twig');
  $html_info = $template->render($variables);


  $variables = array(
   'title' => 'title',
   'message' => $config->get($language."_popup_info"),
   'more' => 't(more)',
   'hide' => 't(hide)',
  );
  $twig = \Drupal::service('twig');
  $template = $twig->loadTemplate(drupal_get_path('module', 'cookiec') . '/templates/cookiec_agreed.html.twig');
  $html_agreed = $template->render($variables);


Nous allons parler de TWIG dans un moment.


 
Le fichier entier avec EventSubscriber ressemble à cela :

<?php

/**
 * @file Drupal\coociec\EventSubscriber\PopupMessageSubscriber
 */
namespace Drupal\cookiec\EventSubscriber;

use Drupal\Core\Language\LanguageManager;
use Drupal\Core\Render\AttachmentsInterface;
use Drupal\Core\Render\Element;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;


/**
 * Classe PopupMessageSubscriber
 * @package Drupal\popup_message\EventSubscriber
 */
class CookiecSubscriber implements EventSubscriberInterface {

 /**
  * @var \Drupal\Core\Config\ImmutableConfig
  */
 protected $config;

 /**
  * Constructeur PopupMessageSubscriber.
  */
 public function __construct() {
  $this->config = \Drupal::configFactory()->get('cookiec.settings');
 }

 /**
  * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
  */
 public function showCookiecMessage(FilterResponseEvent $event) {
  // Vérifiez les permissions pour afficher le message.
  $response = $event->getResponse();

  if (!$response instanceof AttachmentsInterface) {
   return;
  }
  // Vérifiez que le module a activé le popup
  $config = $this->config;
  $language = \Drupal::languageManager()->getCurrentLanguage()->getId();

  $variables = array(
   'title' => 'title',
   'message' => $config->get($language."_popup_info"),
  );

  $twig = \Drupal::service('twig');
  $template = $twig->loadTemplate(drupal_get_path('module', 'cookiec') . '/templates/cookiec_info.html.twig');
  $html_info = $template->render($variables);


  $variables = array(
   'title' => 'title',
   'message' => $config->get($language."_popup_info"),
   'more' => 'more',
   'hide' => 'hide',
  );
  $twig = \Drupal::service('twig');
  $template = $twig->loadTemplate(drupal_get_path('module', 'cookiec') . '/templates/cookiec_agreed.html.twig');
  $html_agreed = $template->render($variables);

  $variables = array(
   'popup_enabled' => $config->get('popup_enabled'),
   'popup_agreed_enabled' => $config->get('popup_agreed_enabled'),
   'popup_hide_agreed' => $config->get('popup_hide_agreed'),
   'popup_height' => $config->get('popup_height'),
   'popup_width' => $config->get('popup_width'),
   'popup_delay' => $config->get('popup_delay')*1000,
   'popup_link' => $config->get($language."_link"),
   'popup_position' => $config->get('popup_position'),
   'popup_language' => $language,
   'popup_html_info' => $html_info,
   'popup_html_agreed' =>$html_agreed,
  );

  $attachments = $response->getAttachments();
  $attachments['library'][] = 'cookiec/cookiec_library';
  $attachments['drupalSettings']['cookiec'] = $variables;
  $response->setAttachments($attachments);
 }

 /**
  * {@inheritdoc}
  */
 public static function getSubscribedEvents() {
  $events[KernelEvents::RESPONSE][] = array('showCookiecMessage', 20);

  return $events;
 }
}

7. Configs

Un autre grand changement dans Drupal 8 est l'utilisation des fichiers de configuration. Ce sont aussi des fichiers YML, dont le but est de faciliter la synchronisation des paramètres, variables et autres données enregistrées dans la base de données entre les environnements.
Vous pouvez en lire plus à ce sujet ici : https://www.drupal.org/docs/8/configuration-management/managing-your-sites-configuration
La version compatible D8 de notre module utilise des configs pour stocker les paramètres de notre fenêtre et charger les paramètres par défaut lors de l'installation. Après avoir placé le fichier de config dans le dossier config/install, il sera automatiquement chargé lors de l'installation du module, donc nous n'utiliserons plus hook_install.
Notre fichier config/install/cookiec.settings.yml”

popup_enabled: 1
popup_agreed_enabled: 1
popup_hide_agreed: 1
popup_width: 100%
popup_delay: '1'
popup_height: '100'
en_popup_title: 'Politique en matière de cookies'
en_popup_info: 'Ce site utilise des cookies. En restant sur ce site, vous acceptez notre <a href="/cookiec">politique en matière de cookies</a>'
en_popup_agreed: 'Je suis d'accord'
en_popup_p_private: '<p>Ce site ne collecte pas automatique....</p>"
pl_popup_title: 'Polityka cookie'
pl_popup_info: 'Powiadomienie o plikach cookie. Ta strona korzysta z plików cookie. Pozostając na tej stronie, wyrażasz zgodę na korzystanie z plików cookie. <a href="/cookiec">Dowiedz się więcej'
pl_popup_agreed: 'Zgadzam się'
pl_popup_p_private: "  <p>Serwis nie zbiera w sposób automatyczny żadnych informacji, z wyjątkiem informacji zawartych w plikach cookies.</p>\r\n  <p>Pliki cookies (tzw. „ciasteczka”) </p>"
en_popup_link: /cookiec
pl_popup_link: /cookiec


Si vous avez besoin de charger les données dans le code du site, utilisez le service configFactory() avec la méthode get et fournissez le nom de la config.

   $this->config = \Drupal::configFactory()->get('cookiec.settings');


Ce code a été utilisé dans le constructeur de la classe CookiecSubscriber, nous donnant un accès rapide et facile à tous les paramètres du module.
Nous allons les assigner au tableau $variables

...
 'popup_hide_agreed' => $config->get('popup_hide_agreed'),
 'popup_height' => $config->get('popup_height'),
 'popup_width' => $config->get('popup_width'),
...
 

8. Modèles TWIG

L'un des changements les plus significatifs après être passé de D7 à D8 est le fait que D8 a abandonné les modèles PHP au profit de TWIG (http://twig.sensiolabs.org/). C'est un sujet assez vaste en soi, donc nous allons probablement écrire un article séparé à ce propos. Pour l'instant, la principale chose à retenir pour nous est que nous ne pouvons plus utiliser les fonctions PHP, et la logique est limitée à de simples boucles et conditions.
Notre module Drupal 7 a deux modèles :
cookiec-agreed.tpl.php
cookiec-info.tpl.php

​
<?php
/**
 * @file
 * Il s'agit d'un fichier modèle pour une fenêtre popup informant un utilisateur qu'il a déjà
 * accepté les cookies.
 *
 * Lors de la surcharge de ce modèle, il est important de noter que jQuery utilisera
 * les classes suivantes pour attribuer des actions aux boutons :
 *
 * hide-popup-button – détruire le popup
 * find-more-button – lien vers une page d'information
 *
 * Variables disponibles :
 * – $message : Contient le texte qui sera affiché dans la popup
 */
?>

<div>
 <div class ="popup-content agreed">
  <div id="popup-text">
   <?php print $message ?>
  </div>
  <div id="popup-buttons">
   <button type="button" class="hide-popup-button"><?php print t("Masquer ce message"); ?> </button>
   <button type="button" class="find-more-button" ><?php print t("Plus d'informations sur les cookies"); ?></button>
  </div>
 </div>
</div>

​


Nous allons commencer par changer les noms en remplaçant l'extension par xxx.html.twig.
Les balises PHP ne sont pas analysées dans les fichiers .twig, nous devrons donc adapter toutes les fonctions et les commentaires au format TWIG.

Commentaires :

Si nous voulons conserver les anciens ou ajouter de nouveaux commentaires, nous devons remplacer les balises PHP par {# .... #}.

<#
/**
 * @file
 * Il s'agit d'un fichier modèle pour une fenêtre popup informant un utilisateur qu'il a déjà
 * accepté les cookies.
 *
 * Lors de la surcharge de ce modèle, il est important de noter que jQuery utilisera
 * les classes suivantes pour attribuer des actions aux boutons :
 *
 *
 * Variables disponibles :
 * message Contient le texte qui sera affiché dans la popup
 * hide – détruire le popup
 * more – lien vers une page d'information
 */
#>


Impression des valeurs des variables

Nous pouvons imprimer la variable en plaçant notre variable entre accolades comme ceci : {{ variable }}. Notre module a trois variables :
message, hide, more – elles contiennent des chaînes traduites. Ajouter {{ message | raw }} entraînera le rendu de l'html dans sa forme pure, sans par exemple remplacer . < > en &lt; &gt; .

​
<div>
 <div class ="popup-content agreed">
  <div id="popup-text">
   {{ message | raw}}
  </div>
  <div id="popup-buttons">
   <button type="button" class="hide-popup-button"> {{ hide }} </button>
   <button type="button" class="find-more-button" > {{ more }} </button>
  </div>
 </div>
</div>

​

Logique dans TWIG

Notre exemple est assez simple; cependant, TWIG nous permet d'utiliser une logique simple. Les opérations de logique sont enveloppées entre les balises {% %}.
Nous pouvons utiliser des balises, des filtres de variables et des fonctions.
Voici quelques exemples :

Exemples de balises :

Boucle For each :

  {% for user in users %}
    <li>{{ user.username|e }}</li>
  {% endfor %}


Condition IF :

{% if online == false %}
  <p>Notre site est en mode maintenance. Veuillez revenir plus tard.</p>
{% endif %}


Opérations sur les variables :

{% set foo = 'bar' %}

Exemples de filtres :

Nous utilisons les filtres en ajoutant | entre les accolades {{}} avec notre variable.

Trim – supprime les espaces ou les chaînes données.

{{ ' J'aime Twig. '|trim }}
{# outputs 'J'aime Twig.' #}

{{ ' J'aime Twig.'|trim('.') }}
{# outputs ' J'aime Twig' #}


Date – formatage de la date

{{ "now"|date("m/d/Y") }}
{{ post.published_at|date("m/d/Y", "Europe/Paris") }}

Fonctions :

fonction random()

{{ random(['apple', 'orange', 'citrus']) }} {# sortie d'exemple: orange #}
{{ random('ABC') }}             {# sortie d'exemple: C #}
{{ random() }}               {# sortie d'exemple: 15386094 (fonctionne comme la fonction PHP native mt_rand) #}
{{ random(5) }}               {# sortie d'exemple: 3 #}


Drupal a également une méthode AddClass très utile, permettant d'ajouter des classes CSS à un élément html.

{%
 set classes = [
  'red',
  'green',
 ]
%}
<div{{ attributes.addClass(classes) }}></div>


Ce ne sont que quelques exemples et cas d'utilisation, pour en savoir plus, vous pouvez lire la documentation TWIG disponible sur http://twig.sensiolabs.org/documentation.
De plus, pour travailler avec DRUPAL 8 et TWIG, il est recommandé de lire également :
https://www.drupal.org/node/1903374 – Débogage des modèles compilés Twig
https://www.drupal.org/docs/8/theming/twig/work-with-twig-templates – Travailler avec les modèles Twig
https://www.drupal.org/docs/8/theming/twig/twig-template-naming-conventions – Conventions de nommage des modèles Twig

Envoi de données à TWIG

Comme vous pouvez le voir, TWIG offre de grandes capacités. Cependant, pour que nos variables soient visibles dans notre TWIG, nous devons les amener là.
Dans notre exemple, nous devons enregistrer le contenu du TWIG analysé dans la variable et l'envoyer au tableau JS. Nous pouvons le faire comme ça :
Tout d'abord, nous collectons les variables à utiliser dans notre TWIG :
 

$variables = array(
   'title' => 'title',
   'message' => $config->get($language."_popup_info"),
   'more' => 'more',
   'hide' => 'hide',
  );


Analyse du modèle :

  $twig = \Drupal::service('twig');
  $template = $twig->loadTemplate(drupal_get_path('module', 'cookiec') . '/templates/cookiec_agreed.html.twig');
  $html_agreed = $template->render($variables);


Cependant, vous utiliserez rarement cette méthode en travaillant avec Drupal 8. Le plus souvent, vous utiliserez d'autres méthodes, comme le remplacement des modèles standard en utilisant les conventions de nommage des modèles Twig.
Blocs :
1. block--module--delta.html.twig
2. block--module.html.twig
3. block.html.twig
Nœuds :
1. node--nodeid--viewmode.html.twig
2. node--nodeid.html.twig
3. node--type--viewmode.html.twig
4. node--type.html.twig
5. node--viewmode.html.twig
6. node.html.twig
etc.
Ensuite, mettez les modèles personnalisés dans notre dossier theme/templates.
Il y a aussi une méthode plus avancée pour faire la même chose - ajouter des fichiers directement aux modules en utilisant hook_theme,

/**
 * Implémente hook_theme().
 */
function cookiec_theme() {
 return array(
  'cookiec_agreed' => array(
   'template' => 'cookiec_agreed',
   'variables' => array(
    'title' => NULL,
    'body' => NULL,
    'read_more' => NULL,
   ),
  ),
  'cookiec_info' => array(
   'template' => 'cookiec_info',
   'variables' => array(
    'title' => NULL,
    'body' => NULL,
    'read_more' => NULL,
   ),
  ),
 );
}


Pour utiliser un tel TWIG, notre bloc ou site doit renvoyer un tableau avec la clé #theme et les variables définies dans hook_theme().
Ci-dessous, vous pouvez voir l'exemple d'un bloc utilisant un TWIG personnalisé

namespace Drupal\hello_world\Plugin\Block;

use Drupal\Core\Block\BlockBase;

/**
 * Fournit un bloc 'Hello'
 *
 * @Block(
 *  id = "hello_block",
 *  admin_label = @Translation("Hello block"),
 * )
 */
class HelloBlock extends BlockBase {
 /**
  * {@inheritdoc}
  */
 public function build() {

 $variables = array(
   'title' => 'title',
   'body' => 'body',
   'read_more' => 'more',
  );

  return array(
   '#theme' => 'cookiec_info',
   '#variables' => $variables,
  );
 }
}

Résumé

Toutes les fonctionnalités ont été portées et sont maintenant entièrement compatibles avec Drupal 8.x. Le module fonctionne parfaitement et est utilisé par nous dans plusieurs projets.
Vous pouvez télécharger le projet depuis GitHub :
https://github.com/droptica/cookiec/
Laissez un commentaire ci-dessous si vous avez des questions ou des problèmes.
Pour résumer notre court article : Les changements entre D7 et D8 sont significatifs, et ce n'est qu'une petite partie de la vaste portée des innovations et nouvelles capacités offertes par notre nouveau CMS. Si vous souhaitez élargir encore vos connaissances sur D8 et d'autres outils utiles pour concevoir des applications web, donnez-nous un like sur  Facebook, où nous partageons nos tutoriels, guides, et diverses choses intéressantes de l'industrie. Vous pouvez également participer à Drupal Day et au Camp Drupal! Du nouveau contenu arrive aussi bientôt sur notre blog!
 

Grand logo D8

3. Best practices for software development teams