Planète

Par Artusamak
Julien Dubois

Assister au webinar « Choisir Drupal 8 » le 17 mars 2016.

Assister au webinar « Choisir Drupal 8 » le 17 mars 2016.
mer, 09/03/2016 - 14:32
Bès

Kaliop et Happyculture organisent un webinar le 17 mars à 14h15 au cours duquel Julien Fabre (@julienfabre) et moi-même aborderons le cas du passage à Drupal 8.

Nous évoquerons rapidement les nouveautés de Drupal 8 ainsi que la philosophie avec laquelle il a été développé, puis nous verrons les enjeux d'une migration vers Drupal 8 et comment s'y préparer au mieux.

La présentation n'entrera pas dans les détails techniques d'une migration, mais vous fournira les moyens clés utiles à la prise de décision.

Le webinar durera environ 45 minutes et sera disponible pendant 7 jours après diffusion alors n'hésitez pas à vous inscrire, nous répondrons aussi à vos questions à la fin de la présentation.

Si vous avez besoin de plus pour vos équipes n'hésitez pas à consulter notre formation Drupal 8 pour les développeurs !

Crédit image : Jamie McCaffrey

Catégorie
Par GoZ
Fabien CLEMENT

Vagrant pour Drupal et Symfony

Vagrant pour Drupal et Symfony

Cela fait plus d'un an maintenant que je travaille avec un environnement lamp géré par vagrant/ansible pour drupal/symfony, et je n'ai pas à m'en plaindre.

Passé les premiers moments de galères de performances, on est toujours en dessous de performances d'un vmware ou d'un intégration sans vm (il faudrait vérifier ça sur un linux sans vm), mais les performances restent bonnes pour un travail quotidien, même avec xdebug d'activé.

GoZ
ven 04/03/2016 - 16:45

Par flocondetoile
Adhérent

Drupal  8 : l'envoi de mails sous toutes les coutures

Par défaut, tous les mails envoyés par Drupal 8 le sont en texte brut. Pour envoyer des mails en HTML, que ce soit pour des newsletters, ou encore tout simplement pour les différentes notifications afin de les enrichir quelque peu, il est nécessaire de modifier le système d'envoi par défaut des courriers électroniques, ou encore d'en utiliser un autre. Faisons un tour d'horizon du système d'envoi des courriers électroniques de Drupal 8. Cela est utile à plus d'un titre. Bien sûr si nous avons besoin de réaliser un envoi programmatique, mais aussi pour mieux comprendre le mécanisme général et donc le fonctionnement des différents modules disponibles pour réaliser cette tache.

Par Artusamak
Julien Dubois

Drupal 8 : l'API de rendu (Render API)

Drupal 8 : l'API de rendu (Render API)
mer, 02/03/2016 - 10:10
Artusamak

Cet article est extrait de notre formation drupal 8 "de Drupal 7 à Drupal 8" à destination des développeurs. N'hésitez pas à nous contacter pour en savoir plus !

Afin de garder le plus de flexibilité possible dans la gestion du rendu, Drupal s’appuie sur le principe des Render arrays ou Renderable arrays introduit en D7. Dans Drupal 8 on a complètement remplacé l’appel à la fonction theme(). L’idée est d’assembler chaque portion de la page dans un tableau décrivant le type et le contenu de chaque donnée. En retardant au maximum le moment où ce tableau est converti en HTML, il devient possible pour chaque module de modifier la mise en forme des données à sa convenance.

Les tableaux se multipliant au vue du nombre d’éléments constituant une page, on peut comparer l’agglomérat de ces renderable arrays à un arbre de rendu qui serait l’équivalent du DOM d’une page web.

Il ne faut pas confondre l’API de rendu et l’API des formulaires même s’ils utilisent le même principe de tableaux décrivant leur contenu avec des propriétés.

Un renderable array combinant plusieurs éléments ressemble à cela :

<span class="token variable">$page</span> <span class="operator token">=</span> <span class="punctuation token">[</span>
  <span class="string token">'#type'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="string token">'page'</span><span class="punctuation token">,</span>
  <span class="string token">'content'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="punctuation token">[</span>
    <span class="string token">'system_main'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="punctuation token">[</span>…<span class="punctuation token">]</span><span class="punctuation token">,</span>
    <span class="string token">'another_block'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="punctuation token">[</span>…<span class="punctuation token">]</span><span class="punctuation token">,</span>
    <span class="string token">'#sorted'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="constant token">TRUE</span><span class="punctuation token">,</span>
  <span class="punctuation token">]</span><span class="punctuation token">,</span>
  <span class="string token">'sidebar_first'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="punctuation token">[</span>
    …
  <span class="punctuation token">]</span><span class="punctuation token">,</span>
<span class="punctuation token">]</span><span class="punctuation token">;</span>

Voici un exemple le plus simpliste possible d’un render array :

<span class="token variable">$render_array</span> <span class="operator token">=</span> <span class="punctuation token">[</span><span class="string token">'#markup'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> "<span class="markup token"><span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>p</span><span class="punctuation token">&gt;</span></span></span>Some text<span class="markup token"><span class="tag token"><span class="tag token"><span class="punctuation token">&lt;/</span>p</span><span class="punctuation token">&gt;</span></span></span>"<span class="punctuation token">]</span><span class="punctuation token">;</span>

Les propriétés que l’on trouve le plus souvent au sein d’un renderable array sont les suivantes :

#type

Valeur correspondant à un RenderElement (voir ci-dessous).

#cache

Attributs pour la cachabilité du tableau (voir chapitre sur le cache).

#markup

Valeur simple pour du HTML.

#prefix / #suffix

Chaîne à afficher avant / après le rendu du tableau.

#pre_render / #post_render

Tableaux de fonctions exécutée avant le rendu des données ou après. Fait pour modifier des données (#pre_render) ou ajuster l’affichage des données (#post_render).

#theme

Nom de la clé de thème à utiliser pour mettre en forme les données qui lui sont passées.

#theme_wrappers

Tableau de fonctions de thème à utiliser pour gérer le rendu autour des enfants.

 

C’est l’id des Plugins de type RenderElement qui liste les différentes valeurs pouvant être données à l’attribut #type. Ces plugins permettent d’avoir une notation raccourcie de renderable array. On verra par exemple le #type more_link qui permet d’afficher un lien “Voir plus” sans avoir à écrire trop de lignes dans le tableau. N’hésitez pas à créer les vôtres si vous avez à manipuler les structures complexes de vos données.

Dans la majorité des cas, vous ne spécifierez aucun #type et utiliserez #theme pour mettre en forme vos données.
Les clés de thème sont à déclarer via le hook_theme(). Il n’a presque pas changé depuis Drupal 7.  Quand des variables sont nécessaires pour afficher leur contenu, il suffit de les passer comme propriétés supplémentaires pour les transmettre comme dans l’exemple qui suit.

<span class="comment shell-comment token"># theme.inc</span>
<span class="comment shell-comment token"># Exemple de déclaration</span>

<span class="keyword token">function</span> <span class="function token">drupal_common_theme</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
  <span class="keyword token">return</span> <span class="keyword token">array</span><span class="punctuation token">(</span>
    <span class="string token">'item_list'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="keyword token">array</span><span class="punctuation token">(</span>
      <span class="string token">'variables'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="keyword token">array</span><span class="punctuation token">(</span>
        <span class="string token">'items'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="keyword token">array</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
        <span class="string token">'title'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="string token">''</span><span class="punctuation token">,</span>
        <span class="string token">'list_type'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="string token">'ul'</span><span class="punctuation token">,</span>
        <span class="string token">'wrapper_attributes'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="keyword token">array</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
        <span class="string token">'attributes'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="keyword token">array</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
        <span class="string token">'empty'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="keyword token">NULL</span><span class="punctuation token">,</span>
        <span class="string token">'context'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="keyword token">array</span><span class="punctuation token">(</span><span class="punctuation token">)</span>
      <span class="punctuation token">)</span><span class="punctuation token">,</span>
    <span class="punctuation token">)</span><span class="punctuation token">,</span>
  <span class="punctuation token">)</span><span class="punctuation token">;</span>
<span class="punctuation token">}</span>
<span class="comment shell-comment token"># BookController.php</span>
<span class="comment shell-comment token"># Exemple d’utilisation</span>

<span class="keyword token">public</span> <span class="keyword token">function</span> <span class="function token">bookRender</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
<span class="token variable">$book_list</span> <span class="operator token">=</span> <span class="keyword token">array</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
<span class="keyword token">foreach</span> <span class="punctuation token">(</span><span class="token variable">$this</span><span class="operator token">-</span><span class="operator token">&gt;</span><span class="property token">bookManager</span><span class="operator token">-</span><span class="operator token">&gt;</span><span class="function token">getAllBooks</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="keyword token">as</span> <span class="token variable">$book</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
   <span class="token variable">$book_list</span><span class="punctuation token">[</span><span class="punctuation token">]</span> <span class="operator token">=</span> <span class="token variable">$this</span><span class="operator token">-</span><span class="operator token">&gt;</span><span class="function token">l</span><span class="punctuation token">(</span><span class="token variable">$book</span><span class="punctuation token">[</span><span class="string token">'title'</span><span class="punctuation token">]</span><span class="punctuation token">,</span> <span class="token variable">$book</span><span class="punctuation token">[</span><span class="string token">'url'</span><span class="punctuation token">]</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
<span class="punctuation token">}</span>
<span class="keyword token">return</span> <span class="keyword token">array</span><span class="punctuation token">(</span>
   <span class="string token">'#theme'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="string token">'item_list'</span><span class="punctuation token">,</span>
   <span class="string token">'#items'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="token variable">$book_list</span><span class="punctuation token">,</span>
   <span class="string token">'#cache'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="punctuation token">[</span>
     <span class="string token">'tags'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> \<span class="package token">Drupal</span><span class="punctuation token">:</span><span class="punctuation token">:</span><span class="function token">entityManager</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="operator token">-</span><span class="operator token">&gt;</span><span class="function token">getDefinition</span><span class="punctuation token">(</span><span class="string token">'node'</span><span class="punctuation token">)</span><span class="operator token">-</span><span class="operator token">&gt;</span><span class="function token">getListCacheTags</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
   <span class="punctuation token">]</span><span class="punctuation token">,</span>
<span class="punctuation token">)</span><span class="punctuation token">;</span>
<span class="punctuation token">}</span>

Il ne faut pas confondre un type de rendu et une clé de thème. Le premier va vous permettre de manipuler des données et de conserver un render array là où la seconde va vous retourner du HTML.

Suggestions, wrappers et dérivés

Les clés de thème peuvent aussi être utilisées pour générer le rendu d’un ou plusieurs wrappers. On utilise dans ce cas l’attribut #theme_wrappers d’un render array. Petite nouveauté dans ce cas par rapport à Drupal 7 : chaque entrée de #theme_wrappers peut désormais surcharger les valeurs passées au #theme principal si nécessaire. Exemple :

<span class="comment shell-comment token"># anywhere.php</span>

<span class="token variable">$build</span> <span class="operator token">=</span> <span class="punctuation token">[</span>
  <span class="string token">'#theme'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="string token">'my_theme_function'</span><span class="punctuation token">,</span>
  <span class="string token">'#some_var'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="string token">'Some value'</span><span class="punctuation token">,</span>
  <span class="string token">'#other_var'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="string token">'Other value'</span><span class="punctuation token">,</span>
  <span class="string token">'#theme_wrappers'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="punctuation token">[</span>
    <span class="string token">'first_wrapper_theme_function'</span><span class="punctuation token">,</span>
    <span class="string token">'second_wrapper_theme_function'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="punctuation token">[</span>
      <span class="string token">'#some_var'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="string token">'Overriden value'</span><span class="punctuation token">,</span>
    <span class="punctuation token">]</span><span class="punctuation token">,</span>
  <span class="punctuation token">]</span><span class="punctuation token">,</span>
<span class="punctuation token">]</span><span class="punctuation token">;</span>

Dans l’exemple ci-dessus, le template first_wrapper_theme_function recevra les paramètres “Some value” et “Other value” alors que le template second_wrapper_theme_function recevra “Overriden value” et “Other value”.

Pour finir, de manière bien plus simple que dans Drupal 7 il est possible de dériver des templates. En effet, chaque double underscore dans le nom d’une clé thème que l’on tente d’invoquer est considéré comme un séparateur. Ainsi, si le nom complet de la clé de thème n’est pas déclaré, on retire la dernière partie et on continue ainsi jusqu’à retomber sur une clé de thème existant. Côté noms de fichiers de template, on remplace les underscores par des tirets.
Par exemple $build = ['#theme' =&gt; 'my_theme_function__node__article']; tenterait d’abord de charger my-theme-function--node--article.html.twig, puis my-theme-function--node.html.twig et enfin my-theme-function.html.twig.

Pour chaque clé de thème, il est possible d’implémenter le hook hook_theme_suggestions_HOOK() afin de proposer des suggestions en fonction des variables passées au template.

Par exemple :

<span class="comment shell-comment token"># my_module.module</span>

<span class="comment token" spellcheck="true">/**
* Implements hook_theme_suggestions_HOOK().
*/</span>
<span class="keyword token">function</span> <span class="function token">my_module_theme_suggestions_node</span><span class="punctuation token">(</span><span class="keyword token">array</span> <span class="token variable">$variables</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
  <span class="token variable">$suggestions</span> <span class="operator token">=</span> <span class="punctuation token">[</span><span class="punctuation token">]</span><span class="punctuation token">;</span>
  <span class="keyword token">if</span> <span class="punctuation token">(</span><span class="token variable">$variables</span><span class="punctuation token">[</span><span class="string token">'#node'</span><span class="punctuation token">]</span><span class="operator token">-</span><span class="operator token">&gt;</span><span class="property token">type</span> <span class="operator token">==</span> <span class="string token">'article'</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
    <span class="token variable">$suggestions</span><span class="punctuation token">[</span><span class="punctuation token">]</span> <span class="operator token">=</span> <span class="string token">'node__article__'</span> <span class="punctuation token">.</span> <span class="token variable">$variables</span><span class="punctuation token">[</span><span class="string token">'#node'</span><span class="punctuation token">]</span><span class="operator token">-</span><span class="operator token">&gt;</span><span class="property token">field_article_type</span><span class="operator token">-</span><span class="operator token">&gt;</span><span class="property token">value</span><span class="punctuation token">;</span>
  <span class="punctuation token">}</span>
  <span class="keyword token">return</span> <span class="token variable">$suggestions</span><span class="punctuation token">;</span>
<span class="punctuation token">}</span>

Le rendu final (conversion des Render arrays vers du HTML) est effectué par des Plugins de type Renderer. Le cœur définit 4 types de Renderer : HTML, AJAX, Dialog et Modal. Dans la plupart des requêtes, la réponse retournera du HTML. Sa génération se passe en 3 grandes étapes.

  • La première consiste à passer dans HtmlRenderer::prepare() qui s’assure que les données sont formatées correctement (présence d’un #type =&gt; ‘page’, ajout des attachments si besoin).
  • La seconde se déroule dans HtmlRenderer::renderResponse() qui encapsule le cœur de la page dans un #type =&gt; ‘html’ pour avoir les tags <html>, <head>, <body>, <scripts>, etc.
  • Et enfin on passe tout cela dans la classe Renderer qui se charge de sortir tout cela en HTML avant de le renvoyer comme réponse (Response).

Le cheminement complet de rendu d’une page est décrit dans cette page de documentation https://www.drupal.org/developing/api/8/render/pipeline, je vous invite à la consulter si vous êtes curieux.

Alors, quand utiliser les render arrays ? C’est simple, tout le temps ! Si vous êtes en train de générer une réponse qui met en forme des données, vous devez utiliser un render array.

Par Artusamak
Julien Dubois

Drupal 8 : Créer un formateur de champ

Drupal 8 : Créer un formateur de champ
lun, 29/02/2016 - 11:28
Artusamak

Cet article est extrait de notre formation drupal 8 "de Drupal 7 à Drupal 8" à destination des développeurs. N'hésitez pas à nous contacter pour en savoir plus !

Voyons maintenant comment se passe dans Drupal 8 l'une des actions que l'on fait le plus lors de la réalisation de projets : la création de formateurs de champs.
L’essentiel des
Hooks qui étaient nécessaires en Drupal 7 sont devenus des méthodes à implémenter dans une classe.

Les Hooks utilisés pour implémenter un formateur de champ étaient les suivants :

Nom du hook Drupal 7

Equivalent Drupal 8

hook_field_formatter_info()

Annotation de type @FieldFormatter
Namespace : Plugin\Field\FieldFormatter

A noter que les paramètres par défaut qui vivaient dans le hook D7 ont maintenant leur propre méthode FormatterInterface::defaultSettings().

hook_field_formatter_view()

FormatterInterface::viewElements()

hook_field_formatter_settings_form()

FormatterInterface::settingsForm()

hook_field_formatter_settings_summary()

FormatterInterface::settingsSummary()

hook_field_formatter_prepare_view()

FormatterInterface::prepareView()

La création d’un nouveau formateur de champ passe par la création d’un plugin, qui va étendre la classe abstraite Drupal\Core\Field\FormatterBase.

Cette classe implémente l’interface Drupal\Core\Field\FormatterInterface qui décrit les méthodes à surcharger et leur but.

Les nouveaux Plugins à créer doivent être placés dans le répertoire /src/Plugin/ de votre module. Un Plugin de formateur de champ doit être ensuite mis dans Field/FieldFormatter.

Il faut donc créer le fichier qui contiendra votre classe dans /src/Plugin/Field/FieldFormatter. Le nom du fichier doit correspondre au nom de la classe suivi de l’extension .php.

Il est important de respecter les noms et placements car cela est utilisé par le chargement automatique (PSR-4) de Drupal pour charger les classes au moment nécessaire.

Nous allons pour cet exercice appliquer la recette pour créer un formateur, nous verrons dans les chapitres suivants les particularités associées aux Plugins.

Implémentation du formateur

La première chose à faire dans le fichier est de définir le Namespace courant (toujours pour le chargement automatique et PSR-4).

<span class="keyword token">namespace</span> <span class="package token">Drupal<span class="punctuation token">\</span></span><span class="markup token"><span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>module</span><span class="punctuation token">&gt;</span></span></span>\<span class="package token">Plugin<span class="punctuation token">\</span>Field<span class="punctuation token">\</span>FieldFormatter</span><span class="punctuation token">;</span>

Ensuite, nous allons dire à Drupal que nous déclarons une classe d’un plugin. Cette partie remplace le hook_field_formatter_info() et se fait à l’aide d’une annotation de type @FieldFormatter.

<span class="comment token" spellcheck="true">/**
* Plugin implementation of the 'remote_cover' formatter.
*
* @FieldFormatter(
*   id = "remote_cover",
*   label = @Translation("Remote Cover"),
*   field_types = {
*     "string"
*   },
* )
*/</span>
  • id attend un nom machine unique.
  • label est la version humaine du nom visible dans la configuration de l’affichage des entités.
  • field_types liste les types de champs sur lesquels ce formateur est applicable.

Puis on déclare notre classe qui étend Drupal\Core\Field\FormatterBase.

<span class="keyword token">class</span> <span class="class-name token">RemoteCover</span> <span class="keyword token">extends</span> <span class="class-name token">FormatterBase</span> <span class="punctuation token">{</span>

Il ne reste plus qu’à implémenter les méthodes dont vous avez besoin comme viewElements() ou prepareView().

On notera la présence d’une méthode view() possédant une implémentation par défaut dans la classe abstraite Drupal\Core\Field\FormatterBase. Cette méthode s’occupe de faire le rendu du champ complet (rajout du label et d’autres informations). Il est donc possible pour un formateur de champs de la surcharger pour modifier le comportement par défaut des champs Drupal dans un cas particulier. La modification d’un formateur existant pour adapter son comportement se voit simplifiée grâce à la programmation objet. Il suffit maintenant d’étendre un formateur existant au lieu de Drupal\Core\Field\FormatterBase et de modifier uniquement le code nécessaire en appelant la méthode parente si nécessaire.

Par GoZ
Fabien CLEMENT

Drupal 8 hébergé chez 1and1 mutualisé

Drupal 8 hébergé chez 1and1 mutualisé

Les hébergements mutualisés sont loin d'être des foudres de guerre, et encore moins pratiques pour héberger de manière pérenne un site.

Toutefois, les prix très bas de ce type de solutions s'avèrent intéressant pour l'hébergement de petits sites ou blogs personnels.

Tandis que Drupal 7 en est à sa version 7.43 et que 1and1 propose via son App Center d'installer Drupal en version 7.39 (Oo?), leur offre mutualisé et l'intégration de PHP7 permet néanmoins l'installation manuelle d'un Drupal 8 (à jour).

GoZ
lun 29/02/2016 - 08:56

Par flocondetoile
Adhérent

Maîtriser les entêtes de Drupal 8 et son SEO

Après avoir mis en ligne votre site Drupal 8, vous pourriez constater dans les journaux d'accès à votre site de nombreuses tentatives d'accès aux formulaires d'édition, d'ajout ou encore de suppression de vos contenus, qui échouent bien entendu sur un accès refusé. De belles erreurs 403. Que diable ? Etes-vous la cible d'une attaque ciblée ? Ou bien tout simplement, les moteurs de recherche cherchent-ils à accéder à ces pages généralement interdites aux visiteurs anonymes ? Découvrons le pourquoi du comment, et quelques solutions pour y remédier.

Par Artusamak
Julien Dubois

Drupal 8 : les blocs, enfin des entités, exemple de création

Drupal 8 : les blocs, enfin des entités, exemple de création
mer, 24/02/2016 - 18:00
Artusamak

Cet article est extrait de notre formation drupal 8 "de Drupal 7 à Drupal 8" à destination des développeurs. N'hésitez pas à nous contacter pour en savoir plus !

Le système de bloc dans Drupal 8 met un point d’honneur à illustrer les efforts de la communauté pour homogénéiser les outils et principes utilisés dans Drupal. Ainsi, les blocs sont maintenant des plugins et s’inscrivent dans la logique tout est entité.

En effet, le module Block Content du cœur définit un type d’entité permettant de gérer des blocs au contenu administrable. Cela signifie qu’il est désormais possible de créer plusieurs bundles de blocs, chacun avec ses propres champs. Il devient dès lors très simple de permettre à un utilisateur d’avoir, par exemple, un bloc d’éditorial administrable sur sa page d’accueil sans utiliser de module contribué, ou de fournir des blocs d’appel à action sans passer par des noeuds.

La démarche tout est bloc initiée par Drupal 7 est maintenant achevée, car tous les éléments classiques de Drupal, comme le titre de la page, les onglets, le fil d’ariane, ou les informations du site (titre, slogan, etc) sont devenus des blocs. Ainsi le template de page ne devrait plus contenir que des régions !

Point à noter, les blocs de menus proposent maintenant de choisir le niveau initial d’affichage et la profondeur à la façon de Menu Block dans Drupal 7. De plus, On retrouve les filtres de visibilité classiques (type de contenu, rôle, page) ainsi qu’un nouveau par langue qui n’était disponible que grâce au module Internationalization en Drupal 7.

Enfin, une dernière nouveauté et pas des moindres, il est dorénavant possible de positionner un bloc plusieurs fois, avec une configuration spécifique pour chaque bloc. Cela permettra par exemple de pouvoir avoir 2 blocs du menu principal avec des niveaux d’affichage différents.

Exemple de création d'un bloc programmatique

La création d’un bloc par le code se fait grâce à l’utilisation des plugins de Drupal 8. Nous rentrerons plus tard dans les détails du fonctionnement des plugins. Voyons, pour le moment, la recette rapide pour en implémenter un.

Il faut créer une classe dans un fichier portant le même nom dans le répertoire src/Plugin/Block/ de son module. Dans notre cas, LibraryBlock.php.

On doit ensuite définir l’espace de nom de notre classe ainsi que les classes dont on se sert. Nous allons étendre la classe Drupal\Core\Block\BlockBase, il faut donc la rajouter.

<span class="comment shell-comment token"># src/Plugin/Block/LibraryBlock.php</span>

<span class="keyword token">namespace</span> <span class="package token">Drupal<span class="punctuation token">\</span>happy_alexandrie<span class="punctuation token">\</span>Plugin<span class="punctuation token">\</span>Block</span><span class="punctuation token">;</span>

<span class="keyword token">use</span> <span class="package token">Drupal<span class="punctuation token">\</span>Core<span class="punctuation token">\</span>Block<span class="punctuation token">\</span>BlockBase</span><span class="punctuation token">;</span>

Pour que notre bloc soit découvert par Drupal, il faut définir une annotation juste avant la classe. Une annotation est un commentaire spécial qui a un effet sur l’interprétation du code. Le fonctionnement de l’annotation sera détaillé plus tard, pour l’instant il faut voir cela comme un remplaçant du hook_block_info().

Il faut définir id qui est le nom machine du bloc et admin_label

<span class="comment shell-comment token"># src/Plugin/Block/LibraryBlock.php</span>

<span class="comment token" spellcheck="true">/**
* Provides a 'Call to visit' block.
*
* @Block(
*   id = "visit_library",
*   admin_label = @Translation("Visit the library"),
* )
*/</span>
<span class="keyword token">class</span> <span class="class-name token">LibraryBlock</span> <span class="keyword token">extends</span> <span class="class-name token">BlockBase</span> <span class="punctuation token">{</span>

Enfin, il faut définir la méthode build() de la classe qui replace hook_block_view() et qui doit renvoyer un render array.

<span class="comment shell-comment token"># src/Plugin/Block/LibraryBlock.php</span>

<span class="keyword token">public</span> <span class="keyword token">function</span> <span class="function token">build</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
  <span class="keyword token">return</span> <span class="keyword token">array</span><span class="punctuation token">(</span>
    <span class="string token">'#markup'</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="string token">"Contenu du bloc"</span><span class="punctuation token">,</span>
  <span class="punctuation token">)</span><span class="punctuation token">;</span>
<span class="punctuation token">}</span>

Le bloc devrait maintenant être visible dans l’interface de gestion des blocs, et on peut le positionner là où bon nous semble.

Par admin

Convocation à l'assemblée générale du mercredi 23 mars 2016

Fichier attaché Taille
Fichierdff-ag-2016_convocation-et-formulaire-pouvoir.odt 44.86 Ko

Cher adhérent,

Le bureau et moi-même avons le plaisir de te convier à l'assemblée générale ordinaire de notre association mercredi 23 mars 2016, conformément à l'article 8 des statuts, qui se tiendra à 18h30 à la Maison des Associations du 3ème, 5 rue Perrée, 75003 Paris.

J'attire ton attention sur le fait que l'assemblée générale a besoin d'un taux de participation ou représentation (pouvoirs) suffisant pour atteindre le quorum nécessaire au vote. Ta participation marque aussi ton soutien à l'association et à ses actions.

L'assemblée générale ordinaire aura à l'ordre du jour :
Rapport moral présenté par le président
Rapport financier présenté par le trésorier
Élection du nouveau conseil d'administration
Questions ouvertes

Les membres désirant présenter leur candidature au bureau, et ceux qui souhaitent inclure des points complémentaires à l'ordre du jour devront se manifester au plus tôt au bureau via email à bureau@listes.drupalfr.org

Si tu ne peux être physiquement présent lors du vote, tu peux te faire représenter par un autre membre de l'association muni d'un pouvoir régulier (ou tu peux l'envoyer à l'adresse de l'association au minimum 4 jours avant l'assemblée générale ou par scan signé à bureau@listes.drupalfr.org). Le pouvoir est disponible ci-dessous.

Tu peux également participer à l'assemblée générale par un moyen de communication électronique permettant de t'identifier formellement. Dans ce cas, si tu souhaites participer aux votes tu devras renoncer à l'anonymat des votes afin de les transmettre.

Je te rappelle également que seuls les membres à jour de leur cotisation peuvent participer à l'assemblée générale et participer au vote, n'hésite pas à adhérer dès à présent grâce au bulletin d'adhésion en ligne (bloc à gauche une fois que tu es connecté sur le site drupalfr.org), ou via le formulaire pdf (http://drupalfr.org/sites/default/files/formulaire-adherent-drupalfr.pdf) à compléter et renvoyer avec ta cotisation ou sur place le jour même. Pour adhérer au titre de ton entreprise ou renouveler son adhésion, utilise le formulaire pdf.

Merci pour ta participation et à bientôt.

Léon Cros
Président Drupal France et francophonie

En page d'accueil : 
Par flocondetoile
Adhérent

Drupal 8 à votre service !

A l'instar des Plugins, Drupal 8 a introduit un nouveau concept, repris de Symfony2, dans son API : les Services. Ces derniers permettent de mettre à disposition des fonctionnalités assurant une et seule tache, comme par exemple envoyer un courrier électronique ou encore construire le fil d'ariane. La différence majeure des Services comparés aux Plugins est que les services ne disposent pas généralement (ou tout du moins directement) d'une interface graphique de configuration. Pour reprendre la définition concise : un service est un objet PHP, conçu dans le but d'atteindre un objectif spécifique, qui effectue une sorte de tâche globale. Découvrons ce nouveau système des services.

Par Artusamak
Julien Dubois

Drupal 8 : charger et lister des entités avec EntityQuery

Drupal 8 : charger et lister des entités avec EntityQuery
mer, 17/02/2016 - 14:38
Artusamak

Cet article est extrait de notre formation drupal 8 "de Drupal 7 à Drupal 8" à destination des développeurs. N'hésitez pas à nous contacter pour en savoir plus !

Durant l’ère de Drupal 6, l’utilisation massive de CCK a poussé les développeurs à vouloir transposer beaucoup de concepts Drupal en nœuds. On a voulu que les blocs, les utilisateurs, la taxonomie puissent être enrichis par des champs à l’aide d’une seule API.

Cela a donné naissance au système d’entités de Drupal 7 et au “tout entité”. Bien que certains éléments n’aient pas subi ce changement (pauvre bloc) sous Drupal 7, cette démarche a été poussée à l’extrême dans Drupal 8 et encore plus de composants sont gérés par une API unifiée et deviennent des entités.

Lister des entités

Drupal 8 introduit, en s’inspirant de EntityFieldQuery, un Service de requêtage d’entités entity.query via la classe \Drupal\Core\Entity\Query\QueryFactory.
Une fois une instance récupérée, il est possible de chaîner les conditions pour former une requête :

<span class="token variable">$fids</span> <span class="operator token">=</span> \<span class="package token">Drupal</span><span class="punctuation token">:</span><span class="punctuation token">:</span><span class="function token">entityQuery</span><span class="punctuation token">(</span><span class="string token">'file'</span><span class="punctuation token">)</span>
  <span class="operator token">-</span><span class="operator token">&gt;</span><span class="function token">condition</span><span class="punctuation token">(</span><span class="string token">'status'</span><span class="punctuation token">,</span> <span class="constant token">FILE_STATUS_PERMANENT</span><span class="punctuation token">,</span> <span class="string token">'&lt;&gt;'</span><span class="punctuation token">)</span>
  <span class="operator token">-</span><span class="operator token">&gt;</span><span class="function token">condition</span><span class="punctuation token">(</span><span class="string token">'changed'</span><span class="punctuation token">,</span> <span class="constant token">REQUEST_TIME</span> <span class="operator token">-</span> <span class="token variable">$age</span><span class="punctuation token">,</span> <span class="string token">'&lt;'</span><span class="punctuation token">)</span>
  <span class="operator token">-</span><span class="operator token">&gt;</span><span class="function token">range</span><span class="punctuation token">(</span><span class="number token">0</span><span class="punctuation token">,</span> <span class="number token">100</span><span class="punctuation token">)</span>
  <span class="operator token">-</span><span class="operator token">&gt;</span><span class="function token">execute</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">;</span>

Charger des entités

Une classe de gestion des entités a été créée dans Drupal 8, il s’agit de la classe \Drupal\Core\Entity\EntityTypeManager. Elle donne accès à plusieurs outils pour charger, lister, ou afficher des entités. La méthode getStorage() donne ainsi accès à une classe de gestion de stockage des entités qui implémente EntityStorageInterface. Les méthodes load() ou loadMultiple() quant à elles remplacent entity_load() de Drupal 7.

<span class="token variable">$entitytype_manager</span> <span class="operator token">=</span> \<span class="package token">Drupal</span><span class="punctuation token">:</span><span class="punctuation token">:</span><span class="function token">service</span><span class="punctuation token">(</span><span class="string token">'entity_type.manager'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
<span class="token variable">$storage</span> <span class="operator token">=</span> <span class="token variable">$entitytype_manager</span><span class="operator token">-</span><span class="operator token">&gt;</span><span class="function token">getStorage</span><span class="punctuation token">(</span><span class="string token">'file'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
<span class="token variable">$files</span> <span class="operator token">=</span> <span class="token variable">$storage</span><span class="operator token">-</span><span class="operator token">&gt;</span><span class="function token">loadMultiple</span><span class="punctuation token">(</span><span class="token variable">$fids</span><span class="punctuation token">)</span><span class="punctuation token">;</span>

Afficher des entités

L’affichage d’un contenu qui pouvait se faire grâce à entity_view() en Drupal 7 passe aussi par la classe \Drupal\Core\Entity\EntityTypeManager et les classes se basant sur l’interface EntityViewBuilderInterface. Il faut utiliser la méthode getViewBuilder() pour récupérer une instance de la classe et les méthodes view() et viewMultiple() pour en faire le rendu.

<span class="token variable">$view_builder</span> <span class="operator token">=</span> <span class="token variable">$entitytype_manager</span><span class="operator token">-</span><span class="operator token">&gt;</span><span class="function token">getViewBuilder</span><span class="punctuation token">(</span><span class="string token">'file'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
<span class="token variable">$output</span> <span class="operator token">=</span> <span class="token variable">$view_builder</span><span class="operator token">-</span><span class="operator token">&gt;</span><span class="function token">viewMultiple</span><span class="punctuation token">(</span><span class="token variable">$nodes</span><span class="punctuation token">,</span> <span class="token variable">$view_mode</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
Par Kgaut
Adhérent
Kevin Gautreau

Première alpha de mon module de pronostics sous drupal 8 : MesPronos

Je travaille depuis quelques années sur un module de pronostics (à un rythme loin d'être soutenu comme tout bon side-project). Il a connu un début de version en Drupal 7, puis en Ruby on Rails, puis sur Symfony, puis enfin sur Drupal 8, il m'a permis de tester Drupal 8 à l'aube des premières versions alpha.

Entièrement open-source, le module est hébergé sur Github : https://github.com/mespronos/mespronos.

Depuis ce week-end, j'ai mis en production le module sur le site https://mespronos.net/ afin de pouvoir le tester en conditions réelles et récupérer suffisamment de données afin de continuer à travailler sur les templates et fonctionnalités à venir (classements...). Pour l'instant les pronostics sont possible sur la ligue 1 Française et le tournois des VI nations.

N'hésitez-pas à tester et me donner vos retours, tout en gardant à l'esprit que c'est une version alpha, et que le thème n'est pour l'instant pas du tout travailler (c'est celui de base de Drupal 8).

Pour suivre l'avancement, vous pouvez-vous rendre sur la page facebook dédiée : https://www.facebook.com/mespronos/.

 

Par Artusamak
Julien Dubois

Sécurité : le processus de mise à jour de Drupal est-il dangereux ?

Sécurité : le processus de mise à jour de Drupal est-il dangereux ?
mer, 10/02/2016 - 12:00
DuaelFr

Courant novembre, un groupe de recherche a contacté l'équipe de sécurité de Drupal pour évoquer un problème lié au processus de vérification et de téléchargement des mises à jour du cœur et des modules. Le sujet a été débattu en interne et la menace a été jugée suffisamment sérieuse pour nécessiter des mises à jour mais avec un impact potentiel trop faible pour opacifier le processus. Début janvier, le lanceur d'alerte a donc publié un article traitant du sujet, et l'équipe de sécurité a posté une réponse quelques jours plus tard pour répondre à l'article publiquement.

Problème déclaré n°1 : lorsque le processus de recherche des mises à jour de Drupal échoue, Drupal indique que tous les modules sont à jour au lieu d'afficher un message d'alerte.

Lorsque vous disposez des permissions suffisantes, il est possible de consulter la liste des mises à jour disponibles pour le cœur et vos modules depuis votre interface d'administration. Par défaut, cette liste est mise à jour quotidiennement via l'exécution d'une tâche planifiée (cron) mais vous pouvez également lancer la vérification manuellement en cliquant sur un lien.

Ce que soulève le lanceur d'alerte c'est que lorsque cette procédure automatisée échoue, par exemple à cause d'une perte de connexion ou d'une surcharge momentanée des serveurs de drupal.org, aucun message d'erreur n'est affiché et, pire, votre site indique alors que tous les modules sont à jour.

Capture d'écran de la page de recherche des mises à jour après une erreur mentionnant le message copié dans la légende.
« Tous vos projets sont à jour »

Il est vrai qu'un message sur cette page serait bénéfique pour éviter tout malentendu concernant l'état des mises à jour du site. On repense notamment à l'unique faille hautement critique détectée depuis Drupal 7, surnommée « Drupageddon », qu'il aurait fallu corriger en moins de quelques heures pour pouvoir certifier que le site n'était pas vérolé. Cependant, l'équipe de sécurité de Drupal se veut rassurante car, même s'il n'y a en effet pas de message sur cette page, il y en a bien un sur toutes les autres pages de l'interface d'administration.

Capture d'écran d'une autre page du site montrant le message d'erreur recopié dans la légende.
« Un problème est survenu durant la vérification des mises à jour disponibles de Drupal. Consultez la page des mises à jour disponibles pour plus d'information et pour installer vos mises à jour manquantes. »

 

Bien qu'assez mineur, ce problème est actuellement en train d'être corrigé (EN) et la future version 8.0.3 devrait le résoudre sans grande difficulté. L'équipe de sécurité de Drupal rappelle tout de même qu'elle communique à propos de ces mises à jour par le biais de quatre autres canaux (leur groupe sur drupal.org, la newsletter dédiée, leur flux RSS et leur fil Twitter).

Problème déclaré n°2 : un attaquant pourrait forcer un administrateur à vérifier les mises à jour disponibles très fréquemment à cause d'une vulnérabilité « CSRF ».

Une vulnérabilité de « Cross-Site Request Forgery » (CSRF) consiste à inciter le navigateur de la cible à se rendre sur une page très précise de son propre site sans qu'il ne le sache. La plupart du temps, ce genre d'attaque s'opère par le biais d'une fausse image dont le chemin est en fait l'URL de la page à attaquer. Ainsi, lorsque le navigateur de la cible va tenter d'afficher l'image, il va en fait faire une requête sur la page en question qui va s'exécuter normalement. Lorsque le navigateur recevra le contenu de la page et se rendra compte qu'il ne s'agit pas d'une image, il n'affichera rien ou alors une indication d'une image brisée. Cette image peut être placée sur l'un des sites de l'attaquant sur lequel il espérera que vous passiez ou alors même sur votre propre site, dans un commentaire par exemple.

Capture d'écran d'un commentaire frauduleux. Voir légende.
Un utilisateur malicieux dépose un commentaire sur le site contenant le message « Haha regardez cette magnifique image trop drôle ! » suivi d'une balise image vérolée.

Ce que soulève ici le lanceur d'alertes est que ce type d'attaque pourrait avoir plusieurs conséquences. Tout d'abord, si cette page était trop souvent visitée volontairement ou pas par les administrateurs du site, cela pourrait surcharger le serveur et rendre le site inaccessible. Ensuite, si cette pratique était reproduite sur plusieurs sites différents, cela pourrait envoyer de nombreuses requêtes aux serveurs de drupal.org et ce coup-ci surcharger directement la source et impacter des milliers d'autres sites. Enfin, en maîtrisant le moment où cette requête pourrait être exécutée, un attaquant étant capable de compromettre un serveur DNS ou d'écouter le trafic du site pendant un bref instant pourrait synchroniser ses actions pour obtenir des informations importantes sans laisser de traces.

Outre le premier problème qui pourrait impacter les sites disposant de peu de ressources pour s'exécuter, les deux autres points semblent bien moins probables. En effet, l'équipe de sécurité de Drupal rappelle que des millions de clients se connectent chaque jour à l'infrastructure de drupal.org et que celle-ci est mise en cache derrière un réseau de contenu distribué (CDN). Il faudrait donc opérer une grande attaque coordonnée sur de très nombreux sites afin de générer suffisamment de trafic pour compromettre l'architecture de drupal.org.

Malgré tout, le problème est tout de même pris au sérieux et un correctif est en préparation. Étant donné que cela a un impact sur toutes les versions de Drupal et que le problème n'est pas critique, il se peut qu'il faille attendre quelques mois avant de le voir définitivement intégré.

Problème soulevé n°3 : les mises à jour de sécurité sont transférées de façon non-cryptée et sans en vérifier l'authenticité, ce qui pourrait compromettre la sécurité du site, de la base de données et éventuellement du serveur.

Ce dernier problème est finalement le plus sérieux bien que sa mise en œuvre et sa correction soient plus complexes. L'URL à laquelle se connecte le site pour vérifier les mises à jour n'utilisant pas de connexion HTTPS, il est possible pour un pirate d'écouter et même de remplacer certaines données avec celles de son choix. Pour cela, il doit s'intercaler entre le serveur hébergeant le site et les serveurs de drupal.org. Ce type d'attaque, appelé « man-in-the-middle », est très difficile à réaliser dans des conditions de production normales (serveur hébergé sur un réseau professionnel et dont l'infrastructure n'a pas été compromise).

Ainsi, en admettant que le pirate soit capable d'intercepter le trafic entre votre serveur et ceux de drupal.org, il pourrait vous renvoyer une version totalement fausse du fichier indiquant quels modules sont à jour et lesquels ne le sont pas. Cela lui permettrait de leurrer l'administrateur du site en lui proposant de fausses mises à jour.

Capture d'écran de la page de recherche des mises à jour piratée.
« Mise à jour de sécurité requise ! »
Téléchargement proposé de Drupal 8.6.66 à l'adresse détournée http://my.hijacked.url/drupal-8.6.66.tar.gz.

Pire encore, au moment du téléchargement du module le pirate pourrait également fournir une version modifiée par ses soins et contenant du code qui pourrait aller jusqu'à compromettre tout le serveur. Une fois le serveur compromis, il pourrait être utilisé comme plateforme d'envoi de spams ou comme vecteur d'attaque pour d'autres serveurs situés sur la même architecture.

Malgré la gravité de ce type d'attaque, il est très difficile à réaliser et le devient encore plus lorsque l'on respecte quelques règles de base de vigilance. Par exemple, au lieu de cliquer directement sur le lien fourni dans l'interface d'administration de Drupal, il est préférable de se rendre sur le site drupal.org pour y vérifier la véracité de l'information et y télécharger le module. En effet, alors qu'il est assez simple de leurrer un simple script PHP en fournissant un faux certificat SSL, la technologie HSTS (HTTP Strict Transport Security), implémentée par les navigateurs modernes, rend l'usurpation d'identité quasi impossible. Si un pirate essayait de se faire passer pour les serveurs de drupal.org, le navigateur le détecterait immédiatement et empêcherait l'accès au site compromis et aux téléchargements douteux en affichant une alerte.

Capture d'écran de la page d'erreur affichée par Chrome lors de la détection d'une tentative d'usurpation du site drupal.org.
« Votre connexion n'est pas privée. Il se peut que des pirates soient en train d'essayer de dérober vos informations sur le site updates.drupal.org [...] »

En attendant l'implémentation potentielle d'une solution lourde mais définitive pour tous ces problèmes, l'équipe de sécurité de Drupal va travailler en collaboration avec l'équipe d'infrastructure pour activer et définir par défaut les URLs en HTTPS. Ils feront également en sorte que Drupal aille chercher l'état de ses modules en utilisant ce protocole sécurisé.  

Conclusion

C'est une bonne chose que les problématiques liées à la mise à jour de nos sites aient été dévoilées publiquement car cela a permis à tout l'écosystème de se remettre en question pour déterminer quel était le risque acceptable de ce genre de situation. Des produits comme Wordpress, permettant l'installation directe de plugins et de mises à jour avec une intervention minimale de l'administrateur ont été et sont encore particulièrement concernés. Au final cet article aura fait plus de bruit que de dégâts mais il nous aura permis d'approfondir un domaine souvent laissé de côté malgré la position centrale de ce processus de mise à jour dans notre travail quotidien.
 

Photo de couverture © Theen Moy

 

Catégorie
Par Artusamak
Julien Dubois

Drupal 8 : Les formulaires

Drupal 8 : Les formulaires
lun, 08/02/2016 - 17:29
Artusamak

Cet article est extrait de notre formation drupal 8 "de Drupal 7 à Drupal 8" à destination des développeurs. N'hésitez pas à nous contacter pour en savoir plus !

Les formulaires ne coupent pas au passage à la POO. Maintenant pour en créer un il vous faut étendre l’une des trois classes de base fournies par le coeur.
Il y a celle que vous utiliserez probablement le plus qui est
FormBase qui permet tout simplement de créer un formulaire “classique”.
Vient ensuite
ConfirmFormBase qui sert à créer des formulaires de confirmation.
S’ajoute enfin à cela
ConfigFormBase qui permet de faire un formulaire qui va aller exporter ses données dans de la configuration.

Pourquoi s’appuyer sur des classes de base ? Si l’on prend l’exemple de la classe ConfigFormBase, c’est que vous voulez sauver une donnée de façon pérenne dans de la configuration. Pour faire cela proprement, il faut faire appel au service qui gère la configuration (nous verrons plus tard ce que sont les services).
Pour éviter d’avoir à tout (re)faire à la main, des classes de base sont à votre disposition pour cela, chacune apportant sont lot de services et d’accès aux données (utilisateur courant, route, etc) vous évitant ainsi d’écrire beaucoup de code à faible valeur ajoutée.

Voici un exemple de classe d'un formulaire de configuration :

&lt;?php
namespace Drupal\happy_alexandrie\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Configuration form for the grand Alexandrie library.
*/
class AlexandrieConfigForm extends ConfigFormBase {
  /**
   * Defines the form ID.
   *
   * This method replaces the hook_form.
   */
  public function getFormId() {
    return 'alexandrie_config_form';
  }
  /**
   * Indicates the namespace of the exported data for this form.
   *
   * Specific to the config forms, indicates under which name the configuration
   * data should be exported. It will be the filename of the exported data.
   */
  public function getEditableConfigNames() {
    return array(
      'happy_alexandrie.library_config'
    );
  }
  /**
   * Defines the form structure.
   *
   * This is where you will define the content of the form, note that the
   * method takes two arguments as in Drupal 7, the form and form state but
   * the form states is now an object, it must match the FormStateInterface.
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    // Call the parent implementation to inherit from the save button and
    // form style.
    $form = parent::buildForm($form, $form_state);
    // Add our custom form fields.
    $form['opening_hours'] = array(
      '#type' =&gt; 'textarea',
      '#title' =&gt; 'Opening hours',
      '#description' =&gt; 'Days / hours of the library',
      '#default_value' =&gt; $this-&gt;config('happy_alexandrie.library_config')-&gt;get('opening_hours'),
      '#rows' =&gt; 5,
    );
    return $form;
  }
  /**
   * Submit callback.
   *
   * Implements the form logic.
   */
  public function submitForm(array &amp;$form, FormStateInterface $form_state) {
    $this-&gt;config('happy_alexandrie.library_config')
      -&gt;set('opening_hours', $form_state-&gt;getValue('opening_hours'))
      -&gt;save();
    // Call the parent implementation to inherit from what has been done in it.
    // In our case, display the confirmation message.
    parent::submitForm($form, $form_state);
  }
}

Les formulaires n’ont pas radicalement changé dans leur fonctionnement. L’identifiant du formulaire est fourni via la méthode getFormId(), le contenu du formulaire est défini dans la méthode buildForm() et le traitement du formulaire une fois soumis est implémenté dans la méthode submitForm(). Il est toujours possible de valider les données via la méthode validateForm().

L’autre changement important lié aux formulaires est la manipulation de la variable $form_state. Anciennement un tableau, c’est devenu un objet de type FormStateInterface.
Quels conséquences cela engendre-t-il ? Il devient plus simple de parcourir ses données car la récupération des valeurs se fait via la méthode
getValue() comme suit :

<span class="comment shell-comment token"># NodePreviewForm.php</span>
<span class="comment token" spellcheck="true">// Récupération du view mode dans lequel prévisualiser le noeud.</span>
<span class="token variable">$view_mode</span> <span class="operator token">=</span> <span class="token variable">$form_state</span><span class="operator token">-</span><span class="operator token">&gt;</span><span class="function token">getValue</span><span class="punctuation token">(</span><span class="string token">'view_mode'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>

Cette interface contient aussi une méthode setRedirect() pour rediriger l’utisateur, une méthode getErrors() pour récupérer les erreurs, une méthode setErrorByName() pour indiquer une erreur sur un champ, une méthode setValue() pour surcharger la valeur d’un champ, etc. Jetez un oeil à la définition de l’interface pour voir tout ce qu’il est possible de faire.

La sauvegarde des données qui étaient stockées dans la table variable se fait maintenant via l’API de configuration simple pour être exportées dans les fichiers de configuration YAML.
Cela signifie c’est que c’est à vous d’écrire le code qui exporte vos données (entre autres, parce que c’est aussi à vous de choisir le nom machine de ces données).

Par Artusamak
Julien Dubois

Drupal 8 : CMI / Configuration, les fondements

Drupal 8 : CMI / Configuration, les fondements
mer, 03/02/2016 - 14:34
Artusamak

Cet article est extrait de notre formation drupal 8 "de Drupal 7 à Drupal 8" à destination des développeurs. N'hésitez pas à nous contacter pour en savoir plus !

Il y a plusieurs mois de cela nous vous avions présenté les concepts de l'initiative CMI (Configuration Management Initiative) et vous avions montré quelques exemples pratiques. Cette initiative, annoncée dès le démarrage du cycle de développement de Drupal 8. a donné naissance à l’API de configuration. Elle permet l’export de  la configuration du site dans des fichiers YAML.

Le YAML 

Le YAML est un format de représentation des données standard utilisé par beaucoup d’autres logiciels ou technologies, notamment Symfony. Il a l’avantage d’être plus facilement “parsé” que les anciens fichiers INI en .info tout en restant compréhensible par les humains.

Les fichiers associés à ce format sont les .yml et sont utilisés dans Drupal 8 pour exporter / importer l’ensemble de la configuration du site.

Il existe plusieurs outils pour gérer de la configuration, chacun répondant à un besoin particulier.

  • Le Service de gestion de configuration
  • La State API
  • Les entités de configuration

Les données simples

Les données de configuration simples (exemple : une option oui / non pour un paramètre de votre module, la taille d’un buffer, logger ou non des erreurs, etc) exploitent le Service de gestion de configuration. Ces données très simples à stocker n’ont qu’une version possible et sont pérennes.

Exemple de données simples exportés dans un fichier .yml :

# system.theme.yml
admin: ''
default: stark

Il est possible de fournir de la configuration par défaut, prise en compte lors de l’installation d’un module, en la plaçant dans le dossier config/install/<module_name>.<groupe>.yml du module, le groupe permettant de rassembler des variables traitant du même sujet. Il arrivera que votre module puisse livrer de la configuration pour des dépendances non activées (exemple : une vue pour de la taxonomie alors que le module de taxonomie n’est pas actif). Pour éviter d’avoir à activer tous les modules, vous pourrez livrer de la configuration dite optionnelle, il faudra dans ce cas la placer dans le dossier config/optional/<module>.<groupe>.yml.

Documentation officielle : https://www.drupal.org/node/1809490

Configuration schema

La configuration ayant vocation à être exportée, il a fallut créer une façon de décrire les données à exporter. CMI a mis en place un système de description de la configuration et l’enrichit de certaines méta-données à travers un fichier .yml. L’idée de ce fichier est de décrire le type de données stockées par la configuration, d’y associer un label, d’informer que les données soient traduisibles ou non, etc. Plus d’informations à propos des schémas de configuration et des méta-données peuvent être trouvées sur cette page : https://www.drupal.org/node/1905070.

Le fichier à créer se placera dans config/schema/<module_name>.schema.yml et il permettra de décrire toutes les configurations utilisées par ce module.

Extrait du fichier schéma pour le fichier system.schema.yml :

# system.schema.yml
# [...]
system.theme: # couple .
  type: config_object
  label: 'Theme settings'
  mapping:
    admin:
      type: string
      label: 'Administration theme'
        default:
      type: string
      label: 'Default theme
# [...]

Le couple <module_name>.<groupe> du fichier de configuration sera utilisé comme clef dans le fichier schéma, vient ensuite la description des types de données de chacune des données, ainsi qu’un label descriptif. Les types de données existants sont décrits dans la page de documentation liée plus haut et exploitent la Typed Data API.

Documentation officielle : https://www.drupal.org/node/1905070

Utilisation de la configuration

On pourra récupérer les données liées à ce groupe en utilisant comme identifiant de configuration la clé “module.groupe” (voir ci-dessous).
La configuration doit toujours être sauvée. Mettre des données dans un objet de configuration ne suffit pas. Les objets de configuration peuvent être récupérés soit en lecture seule soit prêts à être modifiés selon les besoins.

# Controller.php
// Récupérer la valeur pour lecture.
$config = \Drupal::config('system.performance');
$enabled = $config-&gt;get('cache.page.enabled');
// Définir la valeur pour écriture.
$config = \Drupal::configFactory()-&gt;getEditable('system.performance');
$config-&gt;set('cache.page.enabled', TRUE);
$config-&gt;save();

Une ligne de configuration peut être supprimée en utilisant la fonction clear(). Pour supprimer une configuration complète il faudra utiliser la fonction delete().

Exemple :

# Controller.php
$config_factory = \Drupal::configFactory();
// Supprime la configuration de la durée de vie maximale du cache de page.
$config = $config_factory-&gt;getEditable('system.performance');
$config-&gt;clear('cache.page.max_age')-&gt;save();
// Supprime la configuration globale de system.performance.
$config_factory-&gt;getEditable('system.performance')-&gt;delete();

Ces données lorsqu’elles sont sauvées sont stockées dans la table config. Cette table remplace la défunte table fourre-tout variable. C’est le point de passage centralisé où les données de configuration transitent avant d’être exportées. Si vos données ne sont pas exportées elles resteront dans cette table.

State API

Certaines de vos données ne seront pas identiques d’un environnement à un autre, voire indépendante. Exemples : dernier passage de cron, clés d’API externe, niveau de reporting des erreurs. Ces données pourraient être éligibles pour être gérées via l’API de configuration des données simples mais un système dédié leur est consacré.

Ce système est la State API qui s’utilise comme suit :

# Controller.php
// Récupérer une valeur.
$maintenance_state = \Drupal::state()-&gt;get('system.maintenance_mode');
// Récupérer une valeur multiple.
$pairs = \Drupal::state()-&gt;getMultiple($keys);
// Définir une valeur.
\Drupal::state()-&gt;set('key','value');
// Définir une valeur multiple.
\Drupal::state()-&gt;setMultiple($keyvalues);
// Supprimer une valeur.
\Drupal::state()-&gt;delete('key');

Une bonne pratique consiste à préfixer les clés avec le nom du module qui défini la valeur, exemple : system.maintenance_mode. Il n’est pas toujours simple de choisir s’il on va utiliser la State API ou l’API de configuration de données simples alors voici un truc pour savoir quoi faire : si vos données doivent être exportées, utilisez l’API de configuration, si ça n’est pas le cas, la State API fera sûrement l’affaire !

À noter qu'il existe un PDF d'aide pour retrouver toutes les commandes liées à la manipulation de la configuration.

Entité de configuration

Poursuivant le principe de “tout est nœud” puis “tout est entité” des anciennes versions de Drupal, une partie de la configuration se retrouve aussi dans des entités. Cela s’appelle les entités de configuration et elles sont majoritairement utilisées quand il s’agit de définir un ensemble de variables de configuration pouvant être définies plusieurs fois. Le principe de type et de bundle existe dans ce cas là aussi mais les bundles d’entités ne sont pas utilisés. Toutes les entités de configuration d’un même type (une vue, un profil de style d’image, un rôle, un vocabulaire, etc) ont le bundle par défaut. (C’est déjà suffisamment compliqué comme ça !).
Bien qu’ayant un fonctionnement différent des données simples, les entités de configuration sont aussi exportables au même format que la configuration simple.

Exemple de configuration d’une entité exportée dans un fichier .yml :

# user.role.administrator.yml

uuid: aad4152c-be3a-4be7-8555-85d45b67e239
langcode: en
status: true
dependencies: {  }
id: administrator
label: Administrator
weight: 2
is_admin: true
permissions: {  }
Par admin

Les propositions de logo pour l'association

Il y a quelques semaines, nous présentions l'appel à contribution, lançant un concours de logo pour l'association. L'idée est de mettre une coup de neuf sur l'identité visuelle de l'association.

Voici les propositions anonymes, sans annotations.
Les commentaires sont ouverts, et le bureau fera une sélection prochainement.

Il reste encore une semaine pour proposer vos contributions, à vos crayons.

1. Logo 1 1. Fond Bleu logo 1
2. Logo 2 2. Fond bleu logo 2
3. Logo 3 3. Fond blanc logo 3
4. Logo 4 fond bleu 4. Logo 4
5. Logo 5 6. Logo 6
7. Logo 7 8. Logo 8
9. Logo 9 10. Logo 10
11. Logo 11 12. Logo 12
13. Logo 13 13. bis Logo 13 bis
14. Logo 14
En page d'accueil : 
Par Marc Delnatte
Akabia

Gestion de Drupal 8 avec Drupal Console

Comme sur Symfony, Drupal 8 dispose maintenant de son outil Drupal Console. En complément de Drush, Drupal Console permet d’automatiser certaines tâches comme la génération de modules, de blocs, d’entités …

Pages