Message d'avertissement

The subscription service is currently unavailable. Please try again later.

Articles de l'utilisateur

Par Iloofo
Iloofo

Fin de vie de Drupal 7 et 8, êtes-vous prêts ?

Les versions 7 et 8 de Drupal arriveront en fin de vie en novembre 2021.

Qu’entend-on par fin de vie ?

La "fin de vie" annonce qu’il n’y aura plus de mise à jour de sécurité pour les versions en question.
À partir de cette date (novembre 2021), les failles qui seront découvertes et corrigées sur la version 9 ne le seront plus sur les versions 7 et 8.

Votre site sera donc vulnérable aux attaques.

Par Iloofo
Iloofo

Fin de vie de Drupal 7 et 8, êtes-vous prêts ?

Les versions 7 et 8 de Drupal arriveront en fin de vie en novembre 2021.

Qu’entend-on par fin de vie ?

La "fin de vie" annonce qu’il n’y aura plus de mise à jour de sécurité pour les versions en question.
À partir de cette date (novembre 2021), les failles qui seront découvertes et corrigées sur la version 9 ne le seront plus sur les versions 7 et 8.

Votre site sera donc vulnérable aux attaques.

Par Iloofo
Iloofo

Retour sur la Drupal Con Amsterdam 2019

En octobre dernier, l'équipe a décollé pour Amsterdam afin d'y retrouver la communauté Drupal européenne.

Au programme : sessions, BoFs, discussions et contribution.

Par Iloofo
Iloofo

Retour sur la Drupal Con Amsterdam 2019

En octobre dernier, l'équipe a décollé pour Amsterdam afin d'y retrouver la communauté Drupal européenne.

Au programme : sessions, BoFs, discussions et contribution.

Par Iloofo
Iloofo

Les tests sous Drupal 8 - PHPUnit

Drupal 7 utilisait auparavant Simpletest, solution propre à Drupal pour l'écriture de ses tests.

Désormais, Drupal 8 utilise PHPUnit.

Il y a quelque temps, nous sommes intervenus pour mener une formation à l'écriture de tests sous Drupal 8. La présentation réalisée à cet effet en pièce jointe expose :

Les différents types de tests
Les outils de testing sous Drupal 8
La structure d'un test
Comment configurer PHPStorm et PHPUnit

Par Iloofo
Iloofo

Les tests sous Drupal 8 - PHPUnit

Drupal 7 utilisait auparavant Simpletest, solution propre à Drupal pour l'écriture de ses tests.

Désormais, Drupal 8 utilise PHPUnit.

Il y a quelques temps, nous sommes intervenu pour une formation à l'écriture de tests sous Drupal 8. La présentation réalisée à cet effet en pièce jointe présente :

Les différents types de tests
Les outils de testing sous Drupal 8
La structure d'un test
Comment configurer PHPStorm et PHPUnit

Par Iloofo
Iloofo

Les tests sous Drupal 8 - PHPUnit

Drupal 7 utilisait auparavant Simpletest, solution propre à Drupal pour l'écriture de ses tests.

Désormais, Drupal 8 utilise PHPUnit.

Il y a quelques temps, nous sommes intervenu pour une formation à l'écriture de tests sous Drupal 8. La présentation réalisée à cet effet en pièce jointe présente :

Les différents types de tests
Les outils de testing sous Drupal 8
La structure d'un test
Comment configurer PHPStorm et PHPUnit

Par Iloofo
Iloofo

L'Equipe.tech sera présente à la DrupalCon Amsterdam 2019

La DrupalCon est un événement organisé par la communauté Drupal qui regroupe des présentations selon différents axes :

Commerce et Marketing
DevOps et Infrastructure
Drupal et Backend

Drupal et Frontend
La Communauté Drupal et Être humain
Entreprise

Après une courte absence, relayée par la Drupal Europe en 2018, c'est le retour des DrupalCon en Europe. Pour sa reprise, la DrupalCon aura lieu à Amsterdam du 28 au 31 octobre 2019.

Par Iloofo
Iloofo

Iloofo sera présente à la DrupalCon Amsterdam 2019

La DrupalCon est un événement organisé par la communauté Drupal qui regroupe des présentations selon différents axes :

Commerce et Marketing
DevOps et Infrastructure
Drupal et Backend

Drupal et Frontend
La Communauté Drupal et Être humain
Entreprise

Après une courte absence, relayée par la Drupal Europe en 2018, c'est le retour des DrupalCon en Europe. Pour sa reprise, la DrupalCon aura lieu à Amsterdam du 28 au 31 octobre 2019.

Par Iloofo
Iloofo

L'Equipe.tech sera présente à la DrupalCon Amsterdam 2019

La DrupalCon est un événement organisé par la communauté Drupal qui regroupe des présentations selon différents axes :

Commerce et Marketing
DevOps et Infrastructure
Drupal et Backend

Drupal et Frontend
La Communauté Drupal et Être humain
Entreprise

Après une courte absence, relayée par la Drupal Europe en 2018, c'est le retour des DrupalCon en Europe. Pour sa reprise, la DrupalCon aura lieu à Amsterdam du 28 au 31 octobre 2019.

Par Iloofo
Iloofo

L'Equipe.tech sera présente à la DrupalCon Amsterdam 2019

La DrupalCon est un événement organisé par la communauté Drupal qui regroupe des présentations selon différents axes :

Commerce et Marketing
DevOps et Infrastructure
Drupal et Backend

Drupal et Frontend
La Communauté Drupal et Être humain
Entreprise

Après une courte absence, relayée par la Drupal Europe en 2018, c'est le retour des DrupalCon en Europe. Pour sa reprise, la DrupalCon aura lieu à Amsterdam du 28 au 31 octobre 2019.

Par Iloofo
Iloofo

Mon Drupal est en fin de vie

Pourquoi il est important de passer de Drupal 7 a Drupal 8 pour être pret à passer à Drupal 9.

En septembre 2018, à l'occasion du Drupal Europe, Dries Buytaert, le fondateur de Drupal à annoncé la fin de vie de Drupal 7 et de Drupal 8 pour novembre 2021.

Quand Drupal 9 sort-il ?

Drupal 9 est prévu dans sa version stable pour juin 2020.

Qu'est-ce qu'une fin de vie pour une version de logiciel ?

La fin de vie signifie que le logiciel, dans cette version majeure n'aura plus aucune correction de sécurité. Si des failles de sécurités sont découvertes et publiées, elles pourront être exploitées car la communauté ne fournira plus de mise à jour de ces versions.

Comment faire pour éviter cela ?

Le plus simple est de continuer à maintenir son site à jour et de le faire monter en versions.

Pourquoi la fin de 2 versions, dont la dernière actuelle ?

Tout d'abord, la version 7 aurait dû se terminer à la sortie de Drupal 9.

Devant le nombre important d'utilisation de cette version et la complexité à faire migrer les sites existant vers une version 8, la durée de support de sécurité pour la version 7 a été allongée pour suivre la même date de fin de vie que la version 8. Cela permet ainsi d'avoir plus de temps pour penser à une refonte et prévoir le budget et les ressources adéquates.

Drupal 7 disposera d'un programme de support commercial longue durée. Moyennant finance, il sera possible de se prémunir des futures failles de sécurités trouvées dans le core de Drupal, et ce même après sa fin de vie. Toutefois, cela ne s'applique qu'au core, les modules "contrib" de la communauté et votre code spécifique ce sera pas supporté.
Il faut également prendre en compte que plus le temps passera, et moins de sociétés seront enclines à faire de la maintenance ou des corrections sur une version qui n'est plus supportée.

Ok pour Drupal 7, mais pourquoi Drupal 8 également ?

La raison est purement technique. La grande nouveauté de Drupal 8 était son utilisation des composants de Symfony 3.x. Or Symfony 3 ne sera plus supporté à partir de novembre 2021. A cette date, il sera déconseillé d'utiliser la version 3 de Symfony, et donc d'utiliser tout Drupal utilisant cette version, au risque d'être piraté.

Par Iloofo
Iloofo

Mon Drupal est en fin de vie

Pourquoi il est important de passer de Drupal 7 a Drupal 8 pour être pret à passer à Drupal 9.

En septembre 2018, à l'occasion du Drupal Europe, Dries Buytaert, le fondateur de Drupal à annoncé la fin de vie de Drupal 7 et de Drupal 8 pour novembre 2021.

Quand Drupal 9 sort-il ?

Drupal 9 est prévu dans sa version stable pour juin 2020.

Qu'est-ce qu'une fin de vie pour une version de logiciel ?

La fin de vie signifie que le logiciel, dans cette version majeure n'aura plus aucune correction de sécurité. Si des failles de sécurités sont découvertes et publiées, elles pourront être exploitées car la communauté ne fournira plus de mise à jour de ces versions.

Comment faire pour éviter cela ?

Le plus simple est de continuer à maintenir son site à jour et de le faire monter en versions.

Pourquoi la fin de 2 versions, dont la dernière actuelle ?

Tout d'abord, la version 7 aurait dû se terminer à la sortie de Drupal 9.

Devant le nombre important d'utilisation de cette version et la complexité à faire migrer les sites existant vers une version 8, la durée de support de sécurité pour la version 7 a été allongée pour suivre la même date de fin de vie que la version 8. Cela permet ainsi d'avoir plus de temps pour penser à une refonte et prévoir le budget et les ressources adéquates.

Drupal 7 disposera d'un programme de support commercial longue durée. Moyennant finance, il sera possible de se prémunir des futures failles de sécurités trouvées dans le core de Drupal, et ce même après sa fin de vie. Toutefois, cela ne s'applique qu'au core, les modules "contrib" de la communauté et votre code spécifique ce sera pas supporté.
Il faut également prendre en compte que plus le temps passera, et moins de sociétés seront enclines à faire de la maintenance ou des corrections sur une version qui n'est plus supportée.

Ok pour Drupal 7, mais pourquoi Drupal 8 également ?

La raison est purement technique. La grande nouveauté de Drupal 8 était son utilisation des composants de Symfony 3.x. Or Symfony 3 ne sera plus supporté à partir de novembre 2021. A cette date, il sera déconseillé d'utiliser la version 3 de Symfony, et donc d'utiliser tout Drupal utilisant cette version, au risque d'être piraté.

Par Iloofo
Iloofo

Mon Drupal est en fin de vie

Pourquoi il est important de passer de Drupal 7 a Drupal 8 pour être pret à passer à Drupal 9.

En septembre 2018, à l'occasion du Drupal Europe, Dries Buytaert, le fondateur de Drupal à annoncé la fin de vie de Drupal 7 et de Drupal 8 pour novembre 2021.

Quand Drupal 9 sort-il ?

Drupal 9 est prévu dans sa version stable pour juin 2020.

Qu'est-ce qu'une fin de vie pour une version de logiciel ?

La fin de vie signifie que le logiciel, dans cette version majeure n'aura plus aucune correction de sécurité. Si des failles de sécurités sont découvertes et publiées, elles pourront être exploitées car la communauté ne fournira plus de mise à jour de ces versions.

Comment faire pour éviter cela ?

Le plus simple est de continuer à maintenir son site à jour et de le faire monter en versions.

Pourquoi la fin de 2 versions, dont la dernière actuelle ?

Tout d'abord, la version 7 aurait dû se terminer à la sortie de Drupal 9.

Devant le nombre important d'utilisation de cette version et la complexité à faire migrer les sites existant vers une version 8, la durée de support de sécurité pour la version 7 a été allongée pour suivre la même date de fin de vie que la version 8. Cela permet ainsi d'avoir plus de temps pour penser à une refonte et prévoir le budget et les ressources adéquates.

Drupal 7 disposera d'un programme de support commercial longue durée. Moyennant finance, il sera possible de se prémunir des futures failles de sécurités trouvées dans le core de Drupal, et ce même après sa fin de vie. Toutefois, cela ne s'applique qu'au core, les modules "contrib" de la communauté et votre code spécifique ce sera pas supporté.
Il faut également prendre en compte que plus le temps passera, et moins de sociétés seront enclines à faire de la maintenance ou des corrections sur une version qui n'est plus supportée.

Ok pour Drupal 7, mais pourquoi Drupal 8 également ?

La raison est purement technique. La grande nouveauté de Drupal 8 était son utilisation des composants de Symfony 3.x. Or Symfony 3 ne sera plus supporté à partir de novembre 2021. A cette date, il sera déconseillé d'utiliser la version 3 de Symfony, et donc d'utiliser tout Drupal utilisant cette version, au risque d'être piraté.

Par Iloofo
Iloofo

Mon Drupal est en fin de vie

Mon Drupal est en fin de vie Drupal 8 timelineFabien CLÉMENT
mar 20/08/2019 - 12:24

Pourquoi il est important de passer de Drupal 7 a Drupal 8 pour être pret à passer à Drupal 9.

En septembre 2018, à l'occasion du Drupal Europe, Dries Buytaert, le fondateur de Drupal à annoncé la fin de vie de Drupal 7 et de Drupal 8 pour novembre 2021.

Quand Drupal 9 sort-il ?

Drupal 9 est prévu dans sa version stable pour juin 2020.

Catégorie
Tags
Par Iloofo
Iloofo

Configuration minimum pour lancer phpunit avec Drupal

A l'heure de la virtualisation et de la containerisation, on n'a pas forcément tout un environnement lamp/wamp/mamp d'installé sur son local.

Sous Drupal 8.x, Si l'on souhaite lancer des test phpunit, nous n'avons besoin que de 3 applications :

PHP
SQLITE
Composer

Suivant votre OS, vous pouvez installer les 2 premiers :

Windows : avec leurs binaires
Linux : via les dépots
OSX : via homebrew

Pour composer, suivre les instructions sur https://getcomposer.org/download/.

Habituellement, nous aurions également besoin d'un serveur apache ou nginx pour pouvoir accéder à notre application, mais depuis la version 8.4.x, Drupal embarque ce qu'il faut pour lancer un serveur depuis php.

Lancer la commande :

php -S localhost:8888 .ht.router.php

Il ne reste plus qu'à configurer phpunit en copiant le fichier phpunit.xml.dist en phpunit.xml :

cp core/phpunit.xml.dist core/phpunit.xml

Créer le répertoire sites/default/simpletest et ajuster la configuration suivant vos besoins. Exemple :

   

   

   

   

   

   

Faire un composer install pour installer les dépendances de Drupal et obtenir phpunit.

Il ne reste plus qu'à lancer phpunit en ligne de commande ou depuis phpstorm.

Pour configurer phpstorm, aller dans le menu PHPStorm > Preferences, chercher PHP.

Ajouter votre binaire PHP puis chercher phpunit et dans Test Frameworks, configurer phpunit.

 

Par Iloofo
Iloofo

Configuration minimum pour lancer phpunit avec Drupal

Configuration minimum pour lancer phpunit avec Drupal Drupal 8 PhpUnitFabien CLÉMENT
dim 11/08/2019 - 09:44

A l'heure de la virtualisation et de la containerisation, on n'a pas forcément tout un environnement lamp/wamp/mamp d'installé sur son local.

Sous Drupal 8.x, Si l'on souhaite lancer des test phpunit, nous n'avons besoin que de 3 applications :

  • PHP
  • SQLITE
  • Composer

Suivant votre OS, vous pouvez installer les 2 premiers :

  • Windows : avec leurs binaires
  • Linux : via les dépots
  • OSX : via homebrew

Pour composer, suivre les instructions sur https://getcomposer.org/download/.

Catégorie
Tags
Par Iloofo
Iloofo

Configuration minimum pour lancer phpunit avec Drupal

A l'heure de la virtualisation et de la containerisation, on n'a pas forcément tout un environnement lamp/wamp/mamp d'installé sur son local.

Sous Drupal 8.x, Si l'on souhaite lancer des test phpunit, nous n'avons besoin que de 3 applications :

PHP
SQLITE
Composer

Suivant votre OS, vous pouvez installer les 2 premiers :

Windows : avec leurs binaires
Linux : via les dépots
OSX : via homebrew

Pour composer, suivre les instructions sur https://getcomposer.org/download/.

Habituellement, nous aurions également besoin d'un serveur apache ou nginx pour pouvoir accéder à notre application, mais depuis la version 8.4.x, Drupal embarque ce qu'il faut pour lancer un serveur depuis php.

Lancer la commande :

php -S localhost:8888 .ht.router.php

Il ne reste plus qu'à configurer phpunit en copiant le fichier phpunit.xml.dist en phpunit.xml :

cp core/phpunit.xml.dist core/phpunit.xml

Créer le répertoire sites/default/simpletest et ajuster la configuration suivant vos besoins. Exemple :

   

   

   

   

   

   

Faire un composer install pour installer les dépendances de Drupal et obtenir phpunit.

Il ne reste plus qu'à lancer phpunit en ligne de commande ou depuis phpstorm.

Pour configurer phpstorm, aller dans le menu PHPStorm > Preferences, chercher PHP.

Ajouter votre binaire PHP puis chercher phpunit et dans Test Frameworks, configurer phpunit.

 

Par Iloofo
Iloofo

Configuration minimum pour lancer phpunit avec Drupal

A l'heure de la virtualisation et de la containerisation, on n'a pas forcément tout un environnement lamp/wamp/mamp d'installé sur son local.

Sous Drupal 8.x, Si l'on souhaite lancer des test phpunit, nous n'avons besoin que de 3 applications :

PHP
SQLITE
Composer

Suivant votre OS, vous pouvez installer les 2 premiers :

Windows : avec leurs binaires
Linux : via les dépots
OSX : via homebrew

Pour composer, suivre les instructions sur https://getcomposer.org/download/.

Habituellement, nous aurions également besoin d'un serveur apache ou nginx pour pouvoir accéder à notre application, mais depuis la version 8.4.x, Drupal embarque ce qu'il faut pour lancer un serveur depuis php.

Lancer la commande :

php -S localhost:8888 .ht.router.php

Il ne reste plus qu'à configurer phpunit en copiant le fichier phpunit.xml.dist en phpunit.xml :

cp core/phpunit.xml.dist core/phpunit.xml

Créer le répertoire sites/default/simpletest et ajuster la configuration suivant vos besoins. Exemple :

   

   

   

   

   

   

Faire un composer install pour installer les dépendances de Drupal et obtenir phpunit.

Il ne reste plus qu'à lancer phpunit en ligne de commande ou depuis phpstorm.

Pour configurer phpstorm, aller dans le menu PHPStorm > Preferences, chercher PHP.

Ajouter votre binaire PHP puis chercher phpunit et dans Test Frameworks, configurer phpunit.

 

Par Iloofo
Iloofo

Docker et OSX

Chez l'Équipe.tech, nous avons toujours travaillé sous OSX avec des Macbook Pro. Pendant de nombreuses années nous en étions très content. Plus simple pour le web que sous Microsoft Windows qui n'est pas adapté pour du développement PHP, plus propre et clé en main que Linux, et finition impeccable.

La majorité de notre expérience sur cet environnement s'est fait avant l'avènement de Docker, et surtout avant que les machines d'Apple ne soient compatibles avec Docker, quand ils n'utilisaient pas encore de processeurs Intel.

Lorsque nos machines (et leur processeurs) nous l'ont permis, nous nous sommes alors mis à Docker et ses promesses. Exit les Vagrant, Virtualbox, LXC et compagnie. Et là c'est la douche froide.

Il fallait auparavant utiliser boot2docker (souvenir douloureux), ça avait le mérite de fonctionner, mais on s'arrêtait là. Manque de stabilité, perfs désastreuses.

Puis est arrivé Docker Desktop (for mac). Côté perfs, ce n'est toujours pas ça mais on a gagné en stabilité.

Pourquoi mon application PHP (Symfony, Drupal etc) avec Docker sous OSX est si lente ?

Le gros problème sous OSX avec docker, c'est la façon dont est gérée l'écriture disque et la synchronisation entre les données du container et le système hôte (osx).

Partant de ce constat, Eugen Meyer a créé Docker Sync.

Docker sync

Cet outil promet d'améliorer drastiquement les performances de votre application sous Docker. Une fois que tout est en place, c'est vrai que cela fonctionne comme convenu. C'est bien plus rapide. Mais il y a un mais !

Pour gagner en rapidité, il faut laisser docker sync... synchroniser. Et là c'est le drame. Le processeur en prend pour son grade. C'est violent, ça chauffe, pour peu que beaucoup de fichiers soient modifiés (c'est quand même le but), il faut attendre un certain temps que ça se mette à jour. Et comme il est gourmand, c'est a son tour de dégrader les performances d'osx cette fois.

Docker sync doit forcément être lancé avant vos containers et pour peu que d'autres personnes de l'équipe ne soit pas sous osx, il nous faut une configuration différente pour gérer docker sync sur notre projet. On est loin de la promesse de plateforme d'environnement uniformisée...

Enfin, dans le cas où on passe d'un projet à l'autre, il faut veiller a bien configurer le docker sync pour ne pas se marcher dessus entre les différents projets et surtout si vous avez besoin de reconstruire entièrement le projet, il faut alors vider docker sync et recommencer l'indexation (prenez un café, allez faire un tour, ou montrez-vous patient).

La solution : Les volumes

Docker sync a donc rapidement été abandonné. Une solution à base de VM virtualbox sous linux pour gérer notre docker à été testée. Les perfs étaient bien meilleures mais devoir lancer une machine virtuelle pour lancer un docker, c'est loin d'être optimal et ça risque vite de déraper en inception... Sans parler qu'avec Virtualbox, on a tendance à se prendre un beau BSOD sans prévenir...

Le top du top : jouer avec les volumes.

Au risque de se répéter, le problème c'est la synchronisation des fichiers entre le container et osx. Il est vrai que c'est bien plus simple de faire un gros volume et de synchroniser tous les fichiers, sauf que c'est là où docker et osx ne sont pas contents.

On utilise donc deux choses :

On segmente notre projet en différents volumes. On écarte ce qui est du code custom que l'on a besoin de modifier : notre code; de ce qui ne nous appartient pas et ne doit de toute façon pas être modifié : les vendors par exemple.
On utilise les options de montage de docker : cached, delegated, ro, rw.

Concernant le premier point, si vous faites du Symfony (ou du Drupal ou tout autre solution opensource), une partie du code de votre projet est issue de la communauté. Celui-ci bouge rarement, et s'il bouge, vous pouvez vous permettre d'avoir un temps de latence un peu plus important pour que votre container se mette a jour (on ne parle que d'une poignée de secondes). Toute ce code peut donc être monté dans un volume avec l'option cached voir mieux : delegated.

Pour votre code custom qui ne doit plus représenter grand chose par rapport au volume total du projet, vous pouvez alors le monter avec l'option cached.

Rien qu'avec cette configuration, vous allez remarquer une belle amélioration. Il est important de se rappeler que si des fichiers sont beaucoup modifiés mais ne sont pas du fait de votre développement, ils ne doivent pas être synchronisés directement sur votre hôte osx.

Les fichiers de cache / les fichiers "volatiles"

Que l'on soit sous Drupal ou Symfony, des fichiers de cache sont générés, ou des fichiers "données" son uploadés. Ces fichiers ne sont pas liés au développement de votre application et, sauf exception pour les fichiers uploadés suivant les cas, peuvent être perdus à tout moment sans impacter votre application. Inutile donc de s'embêter à les synchroniser, autant les laisser dans un volume de container interne à Docker.

Pas de synchronisation, utiliser le mécanisme interne de volumes de Docker

Même sous OSX, les volumes de Docker qui ne sont pas montés sur l'hôte n'ont pas ce problème de performances. Donc le mieux est de ne monter QUE ce qui vous est réellement nécessaire pour vos développements. Dans la partie précédente, nous avons parlé des fichiers générés. Ces fichiers n'ont aucune besoin d'être montés et sont générés en masse, donc autant les placer dans un volume non monté.

Le top du top serait de ne conserver que vos fichiers custom dans des volumes montés. Si vous n'avez pas besoin du code communautaire, inutile de vous embêter à le monter. Vous verrez la différence de performances.

L'exemple

Voici un fichier docker-compose.yml d'exemple commenté pour illustrer cet article dans le cas d'une configuration Drupal (issu de notre stack docker drupal) :

version: "3"

services:
php:
container_name: ${COMPOSE_PROJECT_NAME}_php
volumes:
# La partie web contient l'ensemble du code drupal de notre application. Il n'est pas utile
# de le synchroniser à la seconde car il n'y aura des modifications qu'à la mise à jour mais
# ces fichiers représentent un gros volume.
- ../../web:/var/www/html/web:rw,delegated
# Les paquets vendors n'ont pas besoin d'être synchronisé à la seconde car peu modifiés
# mais ils représentent un gros volume.
- ../../vendor:/var/www/html/vendor:rw,delegated
# On y stocke la configuration sous forme de fichiers. Beaucoup de fichiers générés que l'on
# souhaite versionner mais pas de nécessité de synchronisation immédiate.
- ../../config:/var/www/html/config:rw,delegated
# On monte ces fichiers par commodité pour pouvoir les modifier simplement et que leur modification
# soit prise en compte sans devoir copier un fichier ou relancer un container.
- ../conf/settings.php:/var/www/html/web/sites/default/settings.php:rw,delegated
- ../conf/settings.local.php:/var/www/html/web/sites/default/settings.local.php:rw,delegated
- ../conf/development.services.yml:/var/www/html/web/sites/development.services.yml:rw,delegated
- ../../composer.json:/var/www/html/composer.json:rw,delegated
- ../../composer.lock:/var/www/html/composer.lock:rw,delegated
- ./php/docker-php-upload.ini:/usr/local/etc/php/conf.d/docker-php-upload.ini
# Seuls ces trois répertoires représentent notre code custom et demandent plus de réactivité.
- ../../web/profiles/custom:/var/www/html/web/profiles/custom:rw,cached
- ../../web/modules/custom:/var/www/html/web/modules/custom:rw,cached
- ../../web/themes/custom:/var/www/html/web/themes/custom:rw,cached
# On ne synchronise pas les fichiers de cache et fichiers uploadés.
- drupal-files:/var/www/html/web/sites/default/files
depends_on:
- mysql

apache:
container_name: ${COMPOSE_PROJECT_NAME}_apache
volumes:
# Apache n'est pas censé écrire dans ce répertoire, on peut donc le passer en lecture seule.
- ../../:/var/www/html:ro,delegated
# On partage les fichiers avec le volume de fichier.
- drupal-files:/var/www/html/web/sites/default/files
depends_on:
- php

mysql:
container_name: ${COMPOSE_PROJECT_NAME}_mysql
build:
context: ./mysql
# # On ne monte surtout pas les volumes MYSQL pour des raisons de performances évidentes.
# volumes:
# - ./data/mysql:/var/lib/mysql:rw
# - ./entrypoint:/docker-entrypoint-initdb.d

volumes:
# Ce volume n'étant pas monté avec osx, il ne dégrade pas ses performances.
drupal-files:

 

Par Iloofo
Iloofo

Docker et OSX

Chez l'Équipe.tech, nous avons toujours travaillé sous OSX avec des Macbook Pro. Pendant de nombreuses années nous en étions très content. Plus simple pour le web que sous Microsoft Windows qui n'est pas adapté pour du développement PHP, plus propre et clé en main que Linux, et finition impeccable.

La majorité de notre expérience sur cet environnement s'est fait avant l'avènement de Docker, et surtout avant que les machines d'Apple ne soient compatibles avec Docker, quand ils n'utilisaient pas encore de processeurs Intel.

Lorsque nos machines (et leur processeurs) nous l'ont permis, nous nous sommes alors mis à Docker et ses promesses. Exit les Vagrant, Virtualbox, LXC et compagnie. Et là c'est la douche froide.

Il fallait auparavant utiliser boot2docker (souvenir douloureux), ça avait le mérite de fonctionner, mais on s'arrêtait là. Manque de stabilité, perfs désastreuses.

Puis est arrivé Docker Desktop (for mac). Côté perfs, ce n'est toujours pas ça mais on a gagné en stabilité.

Pourquoi mon application PHP (Symfony, Drupal etc) avec Docker sous OSX est si lente ?

Le gros problème sous OSX avec docker, c'est la façon dont est gérée l'écriture disque et la synchronisation entre les données du container et le système hôte (osx).

Partant de ce constat, Eugen Meyer a créé Docker Sync.

Docker sync

Cet outil promet d'améliorer drastiquement les performances de votre application sous Docker. Une fois que tout est en place, c'est vrai que cela fonctionne comme convenu. C'est bien plus rapide. Mais il y a un mais !

Pour gagner en rapidité, il faut laisser docker sync... synchroniser. Et là c'est le drame. Le processeur en prend pour son grade. C'est violent, ça chauffe, pour peu que beaucoup de fichiers soient modifiés (c'est quand même le but), il faut attendre un certain temps que ça se mette à jour. Et comme il est gourmand, c'est a son tour de dégrader les performances d'osx cette fois.

Docker sync doit forcément être lancé avant vos containers et pour peu que d'autres personnes de l'équipe ne soit pas sous osx, il nous faut une configuration différente pour gérer docker sync sur notre projet. On est loin de la promesse de plateforme d'environnement uniformisée...

Enfin, dans le cas où on passe d'un projet à l'autre, il faut veiller a bien configurer le docker sync pour ne pas se marcher dessus entre les différents projets et surtout si vous avez besoin de reconstruire entièrement le projet, il faut alors vider docker sync et recommencer l'indexation (prenez un café, allez faire un tour, ou montrez-vous patient).

La solution : Les volumes

Docker sync a donc rapidement été abandonné. Une solution à base de VM virtualbox sous linux pour gérer notre docker à été testée. Les perfs étaient bien meilleures mais devoir lancer une machine virtuelle pour lancer un docker, c'est loin d'être optimal et ça risque vite de déraper en inception... Sans parler qu'avec Virtualbox, on a tendance à se prendre un beau BSOD sans prévenir...

Le top du top : jouer avec les volumes.

Au risque de se répéter, le problème c'est la synchronisation des fichiers entre le container et osx. Il est vrai que c'est bien plus simple de faire un gros volume et de synchroniser tous les fichiers, sauf que c'est là où docker et osx ne sont pas contents.

On utilise donc deux choses :

On segmente notre projet en différents volumes. On écarte ce qui est du code custom que l'on a besoin de modifier : notre code; de ce qui ne nous appartient pas et ne doit de toute façon pas être modifié : les vendors par exemple.
On utilise les options de montage de docker : cached, delegated, ro, rw.

Concernant le premier point, si vous faites du Symfony (ou du Drupal ou tout autre solution opensource), une partie du code de votre projet est issue de la communauté. Celui-ci bouge rarement, et s'il bouge, vous pouvez vous permettre d'avoir un temps de latence un peu plus important pour que votre container se mette a jour (on ne parle que d'une poignée de secondes). Toute ce code peut donc être monté dans un volume avec l'option cached voir mieux : delegated.

Pour votre code custom qui ne doit plus représenter grand chose par rapport au volume total du projet, vous pouvez alors le monter avec l'option cached.

Rien qu'avec cette configuration, vous allez remarquer une belle amélioration. Il est important de se rappeler que si des fichiers sont beaucoup modifiés mais ne sont pas du fait de votre développement, ils ne doivent pas être synchronisés directement sur votre hôte osx.

Les fichiers de cache / les fichiers "volatiles"

Que l'on soit sous Drupal ou Symfony, des fichiers de cache sont générés, ou des fichiers "données" son uploadés. Ces fichiers ne sont pas liés au développement de votre application et, sauf exception pour les fichiers uploadés suivant les cas, peuvent être perdus à tout moment sans impacter votre application. Inutile donc de s'embêter à les synchroniser, autant les laisser dans un volume de container interne à Docker.

Pas de synchronisation, utiliser le mécanisme interne de volumes de Docker

Même sous OSX, les volumes de Docker qui ne sont pas montés sur l'hôte n'ont pas ce problème de performances. Donc le mieux est de ne monter QUE ce qui vous est réellement nécessaire pour vos développements. Dans la partie précédente, nous avons parlé des fichiers générés. Ces fichiers n'ont aucune besoin d'être montés et sont générés en masse, donc autant les placer dans un volume non monté.

Le top du top serait de ne conserver que vos fichiers custom dans des volumes montés. Si vous n'avez pas besoin du code communautaire, inutile de vous embêter à le monter. Vous verrez la différence de performances.

L'exemple

Voici un fichier docker-compose.yml d'exemple commenté pour illustrer cet article dans le cas d'une configuration Drupal (issu de notre stack docker drupal) :

version: "3"

services:
php:
container_name: ${COMPOSE_PROJECT_NAME}_php
volumes:
# La partie web contient l'ensemble du code drupal de notre application. Il n'est pas utile
# de le synchroniser à la seconde car il n'y aura des modifications qu'à la mise à jour mais
# ces fichiers représentent un gros volume.
- ../../web:/var/www/html/web:rw,delegated
# Les paquets vendors n'ont pas besoin d'être synchronisé à la seconde car peu modifiés
# mais ils représentent un gros volume.
- ../../vendor:/var/www/html/vendor:rw,delegated
# On y stocke la configuration sous forme de fichiers. Beaucoup de fichiers générés que l'on
# souhaite versionner mais pas de nécessité de synchronisation immédiate.
- ../../config:/var/www/html/config:rw,delegated
# On monte ces fichiers par commodité pour pouvoir les modifier simplement et que leur modification
# soit prise en compte sans devoir copier un fichier ou relancer un container.
- ../conf/settings.php:/var/www/html/web/sites/default/settings.php:rw,delegated
- ../conf/settings.local.php:/var/www/html/web/sites/default/settings.local.php:rw,delegated
- ../conf/development.services.yml:/var/www/html/web/sites/development.services.yml:rw,delegated
- ../../composer.json:/var/www/html/composer.json:rw,delegated
- ../../composer.lock:/var/www/html/composer.lock:rw,delegated
- ./php/docker-php-upload.ini:/usr/local/etc/php/conf.d/docker-php-upload.ini
# Seuls ces trois répertoires représentent notre code custom et demandent plus de réactivité.
- ../../web/profiles/custom:/var/www/html/web/profiles/custom:rw,cached
- ../../web/modules/custom:/var/www/html/web/modules/custom:rw,cached
- ../../web/themes/custom:/var/www/html/web/themes/custom:rw,cached
# On ne synchronise pas les fichiers de cache et fichiers uploadés.
- drupal-files:/var/www/html/web/sites/default/files
depends_on:
- mysql

apache:
container_name: ${COMPOSE_PROJECT_NAME}_apache
volumes:
# Apache n'est pas censé écrire dans ce répertoire, on peut donc le passer en lecture seule.
- ../../:/var/www/html:ro,delegated
# On partage les fichiers avec le volume de fichier.
- drupal-files:/var/www/html/web/sites/default/files
depends_on:
- php

mysql:
container_name: ${COMPOSE_PROJECT_NAME}_mysql
build:
context: ./mysql
# # On ne monte surtout pas les volumes MYSQL pour des raisons de performances évidentes.
# volumes:
# - ./data/mysql:/var/lib/mysql:rw
# - ./entrypoint:/docker-entrypoint-initdb.d

volumes:
# Ce volume n'étant pas monté avec osx, il ne dégrade pas ses performances.
drupal-files:

 

Par Iloofo
Iloofo

Docker et OSX

Docker et OSX Docker + OSXFabien CLÉMENT
mar 16/07/2019 - 11:26

Chez l'Équipe.tech, nous avons toujours travaillé sous OSX avec des Macbook Pro. Pendant de nombreuses années nous en étions très content. Plus simple pour le web que sous Microsoft Windows qui n'est pas adapté pour du développement PHP, plus propre et clé en main que Linux, et finition impeccable.

La majorité de notre expérience sur cet environnement s'est fait avant l'avènement de Docker, et surtout avant que les machines d'Apple ne soient compatibles avec Docker, quand ils n'utilisaient pas encore de processeurs Intel.

Catégorie
Tags
Par Iloofo
Iloofo

Docker et OSX

Chez l'Équipe.tech, nous avons toujours travaillé sous OSX avec des Macbook Pro. Pendant de nombreuses années nous en étions très content. Plus simple pour le web que sous Microsoft Windows qui n'est pas adapté pour du développement PHP, plus propre et clé en main que Linux, et finition impeccable.

La majorité de notre expérience sur cet environnement s'est fait avant l'avènement de Docker, et surtout avant que les machines d'Apple ne soient compatibles avec Docker, quand ils n'utilisaient pas encore de processeurs Intel.

Lorsque nos machines (et leur processeurs) nous l'ont permis, nous nous sommes alors mis à Docker et ses promesses. Exit les Vagrant, Virtualbox, LXC et compagnie. Et là c'est la douche froide.

Il fallait auparavant utiliser boot2docker (souvenir douloureux), ça avait le mérite de fonctionner, mais on s'arrêtait là. Manque de stabilité, perfs désastreuses.

Puis est arrivé Docker Desktop (for mac). Côté perfs, ce n'est toujours pas ça mais on a gagné en stabilité.

Pourquoi mon application PHP (Symfony, Drupal etc) avec Docker sous OSX est si lente ?

Le gros problème sous OSX avec docker, c'est la façon dont est gérée l'écriture disque et la synchronisation entre les données du container et le système hôte (osx).

Partant de ce constat, Eugen Meyer a créé Docker Sync.

Docker sync

Cet outil promet d'améliorer drastiquement les performances de votre application sous Docker. Une fois que tout est en place, c'est vrai que cela fonctionne comme convenu. C'est bien plus rapide. Mais il y a un mais !

Pour gagner en rapidité, il faut laisser docker sync... synchroniser. Et là c'est le drame. Le processeur en prend pour son grade. C'est violent, ça chauffe, pour peu que beaucoup de fichiers soient modifiés (c'est quand même le but), il faut attendre un certain temps que ça se mette à jour. Et comme il est gourmand, c'est a son tour de dégrader les performances d'osx cette fois.

Docker sync doit forcément être lancé avant vos containers et pour peu que d'autres personnes de l'équipe ne soit pas sous osx, il nous faut une configuration différente pour gérer docker sync sur notre projet. On est loin de la promesse de plateforme d'environnement uniformisée...

Enfin, dans le cas où on passe d'un projet à l'autre, il faut veiller a bien configurer le docker sync pour ne pas se marcher dessus entre les différents projets et surtout si vous avez besoin de reconstruire entièrement le projet, il faut alors vider docker sync et recommencer l'indexation (prenez un café, allez faire un tour, ou montrez-vous patient).

La solution : Les volumes

Docker sync a donc rapidement été abandonné. Une solution à base de VM virtualbox sous linux pour gérer notre docker à été testée. Les perfs étaient bien meilleures mais devoir lancer une machine virtuelle pour lancer un docker, c'est loin d'être optimal et ça risque vite de déraper en inception... Sans parler qu'avec Virtualbox, on a tendance à se prendre un beau BSOD sans prévenir...

Le top du top : jouer avec les volumes.

Au risque de se répéter, le problème c'est la synchronisation des fichiers entre le container et osx. Il est vrai que c'est bien plus simple de faire un gros volume et de synchroniser tous les fichiers, sauf que c'est là où docker et osx ne sont pas contents.

On utilise donc deux choses :

On segmente notre projet en différents volumes. On écarte ce qui est du code custom que l'on a besoin de modifier : notre code; de ce qui ne nous appartient pas et ne doit de toute façon pas être modifié : les vendors par exemple.
On utilise les options de montage de docker : cached, delegated, ro, rw.

Concernant le premier point, si vous faites du Symfony (ou du Drupal ou tout autre solution opensource), une partie du code de votre projet est issue de la communauté. Celui-ci bouge rarement, et s'il bouge, vous pouvez vous permettre d'avoir un temps de latence un peu plus important pour que votre container se mette a jour (on ne parle que d'une poignée de secondes). Toute ce code peut donc être monté dans un volume avec l'option cached voir mieux : delegated.

Pour votre code custom qui ne doit plus représenter grand chose par rapport au volume total du projet, vous pouvez alors le monter avec l'option cached.

Rien qu'avec cette configuration, vous allez remarquer une belle amélioration. Il est important de se rappeler que si des fichiers sont beaucoup modifiés mais ne sont pas du fait de votre développement, ils ne doivent pas être synchronisés directement sur votre hôte osx.

Les fichiers de cache / les fichiers "volatiles"

Que l'on soit sous Drupal ou Symfony, des fichiers de cache sont générés, ou des fichiers "données" son uploadés. Ces fichiers ne sont pas liés au développement de votre application et, sauf exception pour les fichiers uploadés suivant les cas, peuvent être perdus à tout moment sans impacter votre application. Inutile donc de s'embêter à les synchroniser, autant les laisser dans un volume de container interne à Docker.

Pas de synchronisation, utiliser le mécanisme interne de volumes de Docker

Même sous OSX, les volumes de Docker qui ne sont pas montés sur l'hôte n'ont pas ce problème de performances. Donc le mieux est de ne monter QUE ce qui vous est réellement nécessaire pour vos développements. Dans la partie précédente, nous avons parlé des fichiers générés. Ces fichiers n'ont aucune besoin d'être montés et sont générés en masse, donc autant les placer dans un volume non monté.

Le top du top serait de ne conserver que vos fichiers custom dans des volumes montés. Si vous n'avez pas besoin du code communautaire, inutile de vous embêter à le monter. Vous verrez la différence de performances.

L'exemple

Voici un fichier docker-compose.yml d'exemple commenté pour illustrer cet article dans le cas d'une configuration Drupal (issu de notre stack docker drupal) :

version: "3"

services:
php:
container_name: ${COMPOSE_PROJECT_NAME}_php
volumes:
# La partie web contient l'ensemble du code drupal de notre application. Il n'est pas utile
# de le synchroniser à la seconde car il n'y aura des modifications qu'à la mise à jour mais
# ces fichiers représentent un gros volume.
- ../../web:/var/www/html/web:rw,delegated
# Les paquets vendors n'ont pas besoin d'être synchronisé à la seconde car peu modifiés
# mais ils représentent un gros volume.
- ../../vendor:/var/www/html/vendor:rw,delegated
# On y stocke la configuration sous forme de fichiers. Beaucoup de fichiers générés que l'on
# souhaite versionner mais pas de nécessité de synchronisation immédiate.
- ../../config:/var/www/html/config:rw,delegated
# On monte ces fichiers par commodité pour pouvoir les modifier simplement et que leur modification
# soit prise en compte sans devoir copier un fichier ou relancer un container.
- ../conf/settings.php:/var/www/html/web/sites/default/settings.php:rw,delegated
- ../conf/settings.local.php:/var/www/html/web/sites/default/settings.local.php:rw,delegated
- ../conf/development.services.yml:/var/www/html/web/sites/development.services.yml:rw,delegated
- ../../composer.json:/var/www/html/composer.json:rw,delegated
- ../../composer.lock:/var/www/html/composer.lock:rw,delegated
- ./php/docker-php-upload.ini:/usr/local/etc/php/conf.d/docker-php-upload.ini
# Seuls ces trois répertoires représentent notre code custom et demandent plus de réactivité.
- ../../web/profiles/custom:/var/www/html/web/profiles/custom:rw,cached
- ../../web/modules/custom:/var/www/html/web/modules/custom:rw,cached
- ../../web/themes/custom:/var/www/html/web/themes/custom:rw,cached
# On ne synchronise pas les fichiers de cache et fichiers uploadés.
- drupal-files:/var/www/html/web/sites/default/files
depends_on:
- mysql

apache:
container_name: ${COMPOSE_PROJECT_NAME}_apache
volumes:
# Apache n'est pas censé écrire dans ce répertoire, on peut donc le passer en lecture seule.
- ../../:/var/www/html:ro,delegated
# On partage les fichiers avec le volume de fichier.
- drupal-files:/var/www/html/web/sites/default/files
depends_on:
- php

mysql:
container_name: ${COMPOSE_PROJECT_NAME}_mysql
build:
context: ./mysql
# # On ne monte surtout pas les volumes MYSQL pour des raisons de performances évidentes.
# volumes:
# - ./data/mysql:/var/lib/mysql:rw
# - ./entrypoint:/docker-entrypoint-initdb.d

volumes:
# Ce volume n'étant pas monté avec osx, il ne dégrade pas ses performances.
drupal-files:

 

Par Iloofo
Iloofo

Ajouter un formulaire à une entité existante

Problématique

Dans notre Drupal, nous avons une entité composée de plusieurs champs mais ne souhaitons pas qu'ils soient tous renseignés via le même formulaire ? 2 solutions s'offrent à nous :

La première est de créer notre controller, créer notre formulaire et gérer le chargement et l'enregistrement des données.
La seconde est d'altérer la définition de l'entité pour rajouter notre formulaire.

Nous conviendrons rapidement que la première méthode n'est pas la plus appropriée eu égard aux bonnes pratiques Drupal. De même, l'effort à fournir par le second cas sera moindre par rapport au premier. Pourquoi tout reconstruire alors que l'on peut utiliser les mécanismes existants ?

Voyons comment réaliser cela via un cas pratique : nous avons une entité 'user' pour laquelle nous souhaitons avoir un formulaire d'édition générale (e-mail / mot de passe) et un formulaire pour qu'il renseigne ses informations personnelles (nom / prénom / adresse).

Création du nouvel affichage de formulaire

Dans un premier temps, allons créer un nouvel affichage de formulaire.

Aller sur la page d'administration de l'affichage de notre type d'utilisateur /admin/config/people/accounts/form-display.
Ajouter un affichage de formulaire 'personal'.
N'y placer que les champs (que nous aurons préalablement créés) nom, prénom, adresse.
Dans l'affichage du formulaire par défaut, retirer ces 3 champs de l'affichage.

Nous avons maintenant un nouvel affichage de formulaire, sauf que celui-ci n'est utilisé nulle part.

Nous allons donc créer une nouvelle définition de route pour y accéder.

Accéder au nouvel affichage de formulaire

Dans le fichier de routing de notre module custom (MONMODULE) : MONMODULE.routing.yml, ajouter une nouvelle route :

MONMODULE.user.personal_form:
path: '/user/{user}/personal_form'
defaults:
_entity_form: user.personal
_title: Personal infromations
requirements:
_entity_access: user.update
user: \d+
options:
_admin_route: FALSE

 

Voyons en détail à quoi servent ces lignes :

# Nom de la route.
MONMODULE.user.personal_form:
# Chemin vers la route. On reprend le chemin d'un user, {user} permet de définir que l'on souhaite utiliser un jeton correspondant à notre entité user.
path: '/user/{user}/personal'
defaults:
# Cette route pointe vers un formulaire d'entité de l'entité user avec l'affichage de formulaire que nous venons de créer : personal.
_entity_form: user.personal
_title: Personal infromations
requirements:
# Par mesure de sécurité, l'utilisateur doit avoir les droits d'accès de l'entité user.update (identique à l'édition normale d'une entité user).
_entity_access: user.update
# Définition des règles de validation de notre token user.
user: \d+
options:
# Cette route n'est pas une route admin (FALSE par défaut).
_admin_route: FALSE

 

On vide les caches, et nous pouvons maintenant accéder à notre formulaire qui ne contiendra que les champs voulus.

Modifier le formulaire

Si l'on souhaite modifier le formulaire existant pour par exemple y ajouter le rendu de notre utilisateur avant les champs d'édition et ajouter un message informatif, nous allons modifier la définition de l'entité user pour y ajouter une nouvelle classe de gestion de notre formulaire.

Dans le fichier MONMODULE.module, créer la méthode MONMODULE_entity_type_alter() ou y ajouter la ligne suivante :

/**
* Implements hook_entity_type_alter().
*/
function MONMODULE_entity_type_alter(array &$entity_types) {
$entity_types['user']->setFormClass('personal', 'Drupal\MONMODULE\Form\UserPersonalForm');
}

 

et créons dans src/Form/UserPersonalForm notre nouvelle classe qui hérite de AccountForm.

namespace Drupal\MONMODULE\Form;

use Drupal\Core\Form\FormStateInterface;
use Drupal\user\AccountForm;

/**
* Class UserPersonalForm.
*
* @package Drupal\MONMODULE\Form
*/
class UserPersonalForm extends AccountForm {

/**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state) {
// Chargement de l'entité en cours pour pouvoir générer son affichage.
$user = $this->getEntity();

$user_view = $this->entityTypeManager->getViewBuilder('user')->view($user, 'default');
$user_view['#attributes'] = [
'class' => ['user-default-infos'],
];
$form['user_view'] = $user_view;

$form = parent::form($form, $form_state);

// Nous pouvons ici modifier le formulaire comme bon nous semble.

return $form;
}

/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
parent::validateForm($form, $form_state);
// Nous pouvons faire ici nos propres validations.
}

/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
parent::submitForm($form, $form_state);
// Nous pouvons faire ici des actions à la suite de la soumission.
}

/**
* {@inheritdoc}
*/
protected function actions(array $form, FormStateInterface $form_state) {
$element = parent::actions($form, $form_state);

// Nous pouvons ici modifier les éléments d'action (boutons).

return $element;
}

}

 

Ajouter un template de lien

Il y a une définition d'entité très pratique et simple à utiliser pour gérer des liens d'entités, il s'agit des templates de lien. On les retrouve par exemple dans l'annotation de notre entité user :

* links = {
* "canonical" = "/user/{user}",
* "edit-form" = "/user/{user}/edit",
* "cancel-form" = "/user/{user}/cancel",
* "collection" = "/admin/people",
* },

 

L'avantage de ces templates de liens est de pouvoir générer un lien à partir de l'entité plutôt que de devoir instancier le générateur de route, et de devoir lui passer tous les paramètres.

// Via le générateur de route.
$url = \Drupal::service('url_generator')->generateFromRoute('entity.user.edit_form', ['user' => $user]);
// Via le template de lien.
/** @var \Drupal\user\Entity\User $user */
$url = $user->url('edit-form');

 

Vu que nous avons ajouté notre formulaire personal, nous pouvons également définir un template de lien pour celui-ci.

Dans notre fichier MONMODULE.module, ajouter la ligne suivante au hook MONMODULE_entity_type_alter().

/**
* Implements hook_entity_type_build().
*/
function MONMODULE_entity_type_alter(array &$entity_types) {
$entity_types['user']->setFormClass('personal', 'Drupal\MONMODULE\Form\UserPersonalForm');
$entity_types['user']->setLinkTemplate('personal-form', '/user/{user}/personal');
}

 

Ce qui nous permettra également de générer nos liens de la sorte :

/** @var \Drupal\user\Entity\User $user */
$url = $user->url('personal-form');

Par Iloofo
Iloofo

Ajouter un formulaire à une entité existante

Problématique

Dans notre Drupal, nous avons une entité composée de plusieurs champs mais ne souhaitons pas qu'ils soient tous renseignés via le même formulaire ? 2 solutions s'offrent à nous :

La première est de créer notre controller, créer notre formulaire et gérer le chargement et l'enregistrement des données.
La seconde est d'altérer la définition de l'entité pour rajouter notre formulaire.

Nous conviendrons rapidement que la première méthode n'est pas la plus appropriée eu égard aux bonnes pratiques Drupal. De même, l'effort à fournir par le second cas sera moindre par rapport au premier. Pourquoi tout reconstruire alors que l'on peut utiliser les mécanismes existants ?

Voyons comment réaliser cela via un cas pratique : nous avons une entité 'user' pour laquelle nous souhaitons avoir un formulaire d'édition générale (e-mail / mot de passe) et un formulaire pour qu'il renseigne ses informations personnelles (nom / prénom / adresse).

Création du nouvel affichage de formulaire

Dans un premier temps, allons créer un nouvel affichage de formulaire.

Aller sur la page d'administration de l'affichage de notre type d'utilisateur /admin/config/people/accounts/form-display.
Ajouter un affichage de formulaire 'personal'.
N'y placer que les champs (que nous aurons préalablement créés) nom, prénom, adresse.
Dans l'affichage du formulaire par défaut, retirer ces 3 champs de l'affichage.

Nous avons maintenant un nouvel affichage de formulaire, sauf que celui-ci n'est utilisé nulle part.

Nous allons donc créer une nouvelle définition de route pour y accéder.

Accéder au nouvel affichage de formulaire

Dans le fichier de routing de notre module custom (MONMODULE) : MONMODULE.routing.yml, ajouter une nouvelle route :

MONMODULE.user.personal_form:
path: '/user/{user}/personal_form'
defaults:
_entity_form: user.personal
_title: Personal infromations
requirements:
_entity_access: user.update
user: \d+
options:
_admin_route: FALSE

 

Voyons en détail à quoi servent ces lignes :

# Nom de la route.
MONMODULE.user.personal_form:
# Chemin vers la route. On reprend le chemin d'un user, {user} permet de définir que l'on souhaite utiliser un jeton correspondant à notre entité user.
path: '/user/{user}/personal'
defaults:
# Cette route pointe vers un formulaire d'entité de l'entité user avec l'affichage de formulaire que nous venons de créer : personal.
_entity_form: user.personal
_title: Personal infromations
requirements:
# Par mesure de sécurité, l'utilisateur doit avoir les droits d'accès de l'entité user.update (identique à l'édition normale d'une entité user).
_entity_access: user.update
# Définition des règles de validation de notre token user.
user: \d+
options:
# Cette route n'est pas une route admin (FALSE par défaut).
_admin_route: FALSE

 

On vide les caches, et nous pouvons maintenant accéder à notre formulaire qui ne contiendra que les champs voulus.

Modifier le formulaire

Si l'on souhaite modifier le formulaire existant pour par exemple y ajouter le rendu de notre utilisateur avant les champs d'édition et ajouter un message informatif, nous allons modifier la définition de l'entité user pour y ajouter une nouvelle classe de gestion de notre formulaire.

Dans le fichier MONMODULE.module, créer la méthode MONMODULE_entity_type_alter() ou y ajouter la ligne suivante :

/**
* Implements hook_entity_type_alter().
*/
function MONMODULE_entity_type_alter(array &$entity_types) {
$entity_types['user']->setFormClass('personal', 'Drupal\MONMODULE\Form\UserPersonalForm');
}

 

et créons dans src/Form/UserPersonalForm notre nouvelle classe qui hérite de AccountForm.

namespace Drupal\MONMODULE\Form;

use Drupal\Core\Form\FormStateInterface;
use Drupal\user\AccountForm;

/**
* Class UserPersonalForm.
*
* @package Drupal\MONMODULE\Form
*/
class UserPersonalForm extends AccountForm {

/**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state) {
// Chargement de l'entité en cours pour pouvoir générer son affichage.
$user = $this->getEntity();

$user_view = $this->entityTypeManager->getViewBuilder('user')->view($user, 'default');
$user_view['#attributes'] = [
'class' => ['user-default-infos'],
];
$form['user_view'] = $user_view;

$form = parent::form($form, $form_state);

// Nous pouvons ici modifier le formulaire comme bon nous semble.

return $form;
}

/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
parent::validateForm($form, $form_state);
// Nous pouvons faire ici nos propres validations.
}

/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
parent::submitForm($form, $form_state);
// Nous pouvons faire ici des actions à la suite de la soumission.
}

/**
* {@inheritdoc}
*/
protected function actions(array $form, FormStateInterface $form_state) {
$element = parent::actions($form, $form_state);

// Nous pouvons ici modifier les éléments d'action (boutons).

return $element;
}

}

 

Ajouter un template de lien

Il y a une définition d'entité très pratique et simple à utiliser pour gérer des liens d'entités, il s'agit des templates de lien. On les retrouve par exemple dans l'annotation de notre entité user :

* links = {
* "canonical" = "/user/{user}",
* "edit-form" = "/user/{user}/edit",
* "cancel-form" = "/user/{user}/cancel",
* "collection" = "/admin/people",
* },

 

L'avantage de ces templates de liens est de pouvoir générer un lien à partir de l'entité plutôt que de devoir instancier le générateur de route, et de devoir lui passer tous les paramètres.

// Via le générateur de route.
$url = \Drupal::service('url_generator')->generateFromRoute('entity.user.edit_form', ['user' => $user]);
// Via le template de lien.
/** @var \Drupal\user\Entity\User $user */
$url = $user->url('edit-form');

 

Vu que nous avons ajouté notre formulaire personal, nous pouvons également définir un template de lien pour celui-ci.

Dans notre fichier MONMODULE.module, ajouter la ligne suivante au hook MONMODULE_entity_type_alter().

/**
* Implements hook_entity_type_build().
*/
function MONMODULE_entity_type_alter(array &$entity_types) {
$entity_types['user']->setFormClass('personal', 'Drupal\MONMODULE\Form\UserPersonalForm');
$entity_types['user']->setLinkTemplate('personal-form', '/user/{user}/personal');
}

 

Ce qui nous permettra également de générer nos liens de la sorte :

/** @var \Drupal\user\Entity\User $user */
$url = $user->url('personal-form');

Par Iloofo
Iloofo

Ajouter un formulaire à une entité existante

Problématique

Dans notre Drupal, nous avons une entité composée de plusieurs champs mais ne souhaitons pas qu'ils soient tous renseignés via le même formulaire ? 2 solutions s'offrent à nous :

La première est de créer notre controller, créer notre formulaire et gérer le chargement et l'enregistrement des données.
La seconde est d'altérer la définition de l'entité pour rajouter notre formulaire.

Nous conviendrons rapidement que la première méthode n'est pas la plus appropriée eu égard aux bonnes pratiques Drupal. De même, l'effort à fournir par le second cas sera moindre par rapport au premier. Pourquoi tout reconstruire alors que l'on peut utiliser les mécanismes existants ?

Voyons comment réaliser cela via un cas pratique : nous avons une entité 'user' pour laquelle nous souhaitons avoir un formulaire d'édition générale (e-mail / mot de passe) et un formulaire pour qu'il renseigne ses informations personnelles (nom / prénom / adresse).

Création du nouvel affichage de formulaire

Dans un premier temps, allons créer un nouvel affichage de formulaire.

Aller sur la page d'administration de l'affichage de notre type d'utilisateur /admin/config/people/accounts/form-display.
Ajouter un affichage de formulaire 'personal'.
N'y placer que les champs (que nous aurons préalablement créés) nom, prénom, adresse.
Dans l'affichage du formulaire par défaut, retirer ces 3 champs de l'affichage.

Nous avons maintenant un nouvel affichage de formulaire, sauf que celui-ci n'est utilisé nulle part.

Nous allons donc créer une nouvelle définition de route pour y accéder.

Accéder au nouvel affichage de formulaire

Dans le fichier de routing de notre module custom (MONMODULE) : MONMODULE.routing.yml, ajouter une nouvelle route :

MONMODULE.user.personal_form:
path: '/user/{user}/personal_form'
defaults:
_entity_form: user.personal
_title: Personal infromations
requirements:
_entity_access: user.update
user: \d+
options:
_admin_route: FALSE

 

Voyons en détail à quoi servent ces lignes :

# Nom de la route.
MONMODULE.user.personal_form:
# Chemin vers la route. On reprend le chemin d'un user, {user} permet de définir que l'on souhaite utiliser un jeton correspondant à notre entité user.
path: '/user/{user}/personal'
defaults:
# Cette route pointe vers un formulaire d'entité de l'entité user avec l'affichage de formulaire que nous venons de créer : personal.
_entity_form: user.personal
_title: Personal infromations
requirements:
# Par mesure de sécurité, l'utilisateur doit avoir les droits d'accès de l'entité user.update (identique à l'édition normale d'une entité user).
_entity_access: user.update
# Définition des règles de validation de notre token user.
user: \d+
options:
# Cette route n'est pas une route admin (FALSE par défaut).
_admin_route: FALSE

 

On vide les caches, et nous pouvons maintenant accéder à notre formulaire qui ne contiendra que les champs voulus.

Modifier le formulaire

Si l'on souhaite modifier le formulaire existant pour par exemple y ajouter le rendu de notre utilisateur avant les champs d'édition et ajouter un message informatif, nous allons modifier la définition de l'entité user pour y ajouter une nouvelle classe de gestion de notre formulaire.

Dans le fichier MONMODULE.module, créer la méthode MONMODULE_entity_type_alter() ou y ajouter la ligne suivante :

/**
* Implements hook_entity_type_alter().
*/
function MONMODULE_entity_type_alter(array &$entity_types) {
$entity_types['user']->setFormClass('personal', 'Drupal\MONMODULE\Form\UserPersonalForm');
}

 

et créons dans src/Form/UserPersonalForm notre nouvelle classe qui hérite de AccountForm.

namespace Drupal\MONMODULE\Form;

use Drupal\Core\Form\FormStateInterface;
use Drupal\user\AccountForm;

/**
* Class UserPersonalForm.
*
* @package Drupal\MONMODULE\Form
*/
class UserPersonalForm extends AccountForm {

/**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state) {
// Chargement de l'entité en cours pour pouvoir générer son affichage.
$user = $this->getEntity();

$user_view = $this->entityTypeManager->getViewBuilder('user')->view($user, 'default');
$user_view['#attributes'] = [
'class' => ['user-default-infos'],
];
$form['user_view'] = $user_view;

$form = parent::form($form, $form_state);

// Nous pouvons ici modifier le formulaire comme bon nous semble.

return $form;
}

/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
parent::validateForm($form, $form_state);
// Nous pouvons faire ici nos propres validations.
}

/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
parent::submitForm($form, $form_state);
// Nous pouvons faire ici des actions à la suite de la soumission.
}

/**
* {@inheritdoc}
*/
protected function actions(array $form, FormStateInterface $form_state) {
$element = parent::actions($form, $form_state);

// Nous pouvons ici modifier les éléments d'action (boutons).

return $element;
}

}

 

Ajouter un template de lien

Il y a une définition d'entité très pratique et simple à utiliser pour gérer des liens d'entités, il s'agit des templates de lien. On les retrouve par exemple dans l'annotation de notre entité user :

* links = {
* "canonical" = "/user/{user}",
* "edit-form" = "/user/{user}/edit",
* "cancel-form" = "/user/{user}/cancel",
* "collection" = "/admin/people",
* },

 

L'avantage de ces templates de liens est de pouvoir générer un lien à partir de l'entité plutôt que de devoir instancier le générateur de route, et de devoir lui passer tous les paramètres.

// Via le générateur de route.
$url = \Drupal::service('url_generator')->generateFromRoute('entity.user.edit_form', ['user' => $user]);
// Via le template de lien.
/** @var \Drupal\user\Entity\User $user */
$url = $user->url('edit-form');

 

Vu que nous avons ajouté notre formulaire personal, nous pouvons également définir un template de lien pour celui-ci.

Dans notre fichier MONMODULE.module, ajouter la ligne suivante au hook MONMODULE_entity_type_alter().

/**
* Implements hook_entity_type_build().
*/
function MONMODULE_entity_type_alter(array &$entity_types) {
$entity_types['user']->setFormClass('personal', 'Drupal\MONMODULE\Form\UserPersonalForm');
$entity_types['user']->setLinkTemplate('personal-form', '/user/{user}/personal');
}

 

Ce qui nous permettra également de générer nos liens de la sorte :

/** @var \Drupal\user\Entity\User $user */
$url = $user->url('personal-form');

Pages