De Drupal 7 à Drupal 8
une (r)évolution à la portée de Tous
Qui suis-je ?
- DrDam
- @DrDam8584
- 4-5 années de Drupal
- Référent Technique Drupal
- Spécialisé dans les architectures à fort trafic
- Filière biologique, formation Ingénieur Agronome
Drupal : une évolution
Modèle MVC
- ORM
- Autoloader
- Twig
Les apports de Drupal 8
Symfony 2
- Fichier en Yaml
- Routing
POO avancée
- Héritage
- Polymorphisme
- Namespace
- Annotation
- Injection de dépendance
Drupal 7 VS Drupal 8
« Ceci est une Révolution »
« J'comprends rien à c'truc, j'peux pas l'faire à l'arrache ? »
« Il n'y a qu'une seule voie, celle de la vertu »
S. Jobs
M. Robespierre
Dev PHP du dimanche
Premières réactions
Anatomie Comparée
Premier constat
- Le module
- Les permissions
- Les formulaires
- Les blocs
- Les menu_items
- Le thèming
- Le templating
- ...
- Les altérations
- le hook_theme
Ce qui change
Ce qui ne change "presque" pas
Déclarer un module
Drupal 7
Drupal 8
mon_module
- mon_module.info
- mon_module.module
mon_module
- mon_module.info.yml
- mon_module.module
- src/
name = "Mon module"
description = "Blabla"
package = "Mon package"
core = "7.x"
version = "7.x-1.0"
dependencies[] = dependance_1
dependencies[] = dependance_2
name: Mon module
type: module
description: Blabla
package: mon package
core: '8.x'
version: '8.x-1.0'
dependencies:
- dependance_1
- dependance_2
Les permissions
Déclarer une permission
mon_module_permission () {
return array(
'ma_permission' => array(
'title' => t('Ma permission'),
'description' => t('STOP'),
),
);
}
'ma permission':
title: 'Ma permission'
description: 'STOP'
Drupal 7
Drupal 8
mon_module.module
mon_module.permissions.yml
Utiliser les permissions
Drupal 7
Drupal 8
// Utiliser l'utilisateur courant
global $user;
// Utiliser l'utilisateur courant
$user = \Drupal::currentUser();
// Charger un utilisateur
$user2 = user_load(2) ;
// L'utilisateur est-il authentifié ?
if(user_is_logged_in()) {
/* ... */
}
// L'utilisateur a-t-il la permission ?
if(user_access('ma_permission')){
/* ... */
}
// Charger un utilisateur
$user2 = \Drupal\user\Entity\User::load(2);
// L'utilisateur a-t-il la permission ?
if($user->hasPermission('ma_permission')) {
/* ... */
}
// L'utilisateur est-il authentifié ?
if($user->isAuthenticated()) {
/* ... */
}
Les formulaires
Petits rappel de Drupal 7
Déclaration :
/* Utilisation du hook_form(). */
function mon_module_formtest_form() {
/* ... */
}
/* paramètre de drupal_get_form() */
function mon_module_form_deux() {
/* ... */
}
Validateur(s) :
// Dans une déclaration de formulaire
// ou un hook_form_alter
$form['#validate'][] = "form_validator";
}
function form_validator($form, &form_state) {
/* ... */
}
// ou un hook_form_validate
Contrôle(s) de soumission :
// Dans une déclaration de formulaire ou un hook_form_alter
$form['#submit'][] = "control_submit";
}
function control_submit($form, &form_state) {
/* ... */
}
/* Utilisation du hook_form_submit(). */
function mon_module_formtest_form_submit($form, &form_state) {
/* ... */
}
Déclaration d'un formulaire
namespace Drupal\mon_module\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
class FormTest extends FormBase {
}
dans le fichier formtest.php
situé : mon_module/src/Form
public function getFormId() { return 'Formulaire_de_test'; }
public function buildForm(array $form, FormStateInterface $form_state) {
// Utilisation de la formAPI
/* ... */
return $form;
}
Validation et soumission
méthodes de la classe " FormTest "
class FormTest extends FormBase {
public function getFormId() { return 'id_du_formulaire'; }
public function buildForm(array $form, FormStateInterface $form_state) {
/* ... */
}
}
public function validateForm(array &$form, FormStateInterface $form_state) {
// accès aux values
$values = $form_state->getValues();
// marquer une erreur
$form_state->setErrorByName($field_name, $this->t('Error on field'));
}
public function submitForm(array &$form, FormStateInterface $form_state){
/* ... */
}
Utilisation d'un formulaire
$form = \Drupal::formBuilder()->getForm('Drupal\mon_module\Form\FormTest');
Ex-drupal_get_form
mon_module.testform:
path: '/mon_module/testform'
defaults:
_title: 'Formulaire de test'
_form: 'Drupal\mon_module\Form\FormTest'
Page de formulaire
Altération d'un formulaire
hook_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id)
hook_form_FORM_ID_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id)
hook_form_BASE_FORM_ID_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id)
Par des fonctions
Par un objet
namespace Drupal\mon_module\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
class AlterFormTest extends FormTest {
public function getFormId() { return 'Formulaire_de_test_modif'; }
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
unset($form['field_mail']);
}
}
Les Blocs
Une longue évolution
Drupal 6
Drupal 7
function mon_module_block ( $op, $delta, $edit) {
switch($op){
function mon_module_block_view($delta = '') {
if($delta == 'mon_block') {
// fabrique mon block
$blocks['content'] = $outHTML;
}
/* ... */
return $blocks;
}
function mon_module_block_info() {
$blocks['mon_block'] = array(
'info' => t('mon block'),
);
/* ... */
return $blocks;
}
case 'view' :
// fabrique les blocs
/* ... */
break;
case 'list' :
// declare les blocs
/* ... */
break;
}
}
Déclarer un bloc
Drupal 7
Drupal 8
namespace '...';
use '...';
class blockOne extends BlockBase {
}
function mon_module_block_info() {
$blocks['mon_block'] = array(
'info' => t('mon block'),
);
/* ... */
return $blocks;
}
mon_module.module
dans le fichier BlockOne.php
situé : mon_module/src/Plugin/Block
function mon_module_block_view($delta = '') {
if($delta == 'mon_block') {
// fabrique mon block
$blocks['content'] = $outHTML;
}
/* ... */
return $blocks;
}
/**
* @Block(
* id = "block_one",
* admin_label = "Block One",
* )
*/
public function build() {
// fabrique mon block
return $themable_array;
}
Le routing
La Théorie
Nouveau paradigme
Drupal 7
Drupal 8
Un hook pour les trouver tous.
Un hook pour les gouverner tous.
Un hook pour les agréger tous
et dans les menus les lier
La prophétie du hook
Le monde décentralisé
Chacun son chemin
Chacun sa nature
Chacun son ascendance
Chacun son type
Un hook unique utilisé partout
Une multitude de fichiers
Différences théoriques
Drupal 7
Drupal 8
Type par défaut
menu_item
menu_callback
Callback de page
Fonction
Objet
Paramètre de requête
"path/%/%" et "page_argument"
auto-chargement possible
"path/{one}/{two}"
Prédéclaration des variables
Le routing
Les routes
La route unitaire
Route simple
Drupal 7
Drupal 8
mon_module
mon_module.routing.yml
mon_module_menu () {
$items['go'] = array(
'page callback' => 'runGo',
'access arguments' =>
array('ma_permission'),
'title' => 'le titre de ma page'
'type' => MENU_CALLBACK
);
/* ... */
return $items;
}
monmodule.go:
path: 'go'
defaults:
_content:
'\Drupal\mon_module\Controller\GoController::runGo'
_title: 'le titre de ma page'
requirements:
_permission: 'ma_permission'
La route unitaire
Route avec paramètres
Drupal 7
Drupal 8
mon_module
mon_module.routing.yml
mon_module_menu () {
$items['go/%/%'] = array(
'page arguments' => array(1,2),
'page callback' => 'run_go',
'access arguments' =>
array('ma_permission'),
'title' => 'le titre de ma page'
'type' => MENU_CALLBACK
);
/* ... */
return $items;
}
monmodule.go:
path: 'go/{one}/{two}'
defaults:
_content:
'\Drupal\mon_module\Controller\GoController::runGo'
_title: 'le titre de ma page'
requirements:
_permission: 'ma_permission'
La route unitaire
Déclarer une page
Dans le fichier GoController.php
situé : mon_module/src/Controller
namespace Drupal\mon_module\Controller;
use Drupal\Core\Controller\ControllerBase;
class GoController extends ControllerBase {
public function runGo($one,$two) {
// je fabrique ma page
return $theming_array;
}
}
Le routing
Les arborescences
Arborescence
Classique
mon_module.links.menu.yml
menu.go_results:
title: 'Resultat'
parent: mon_module.go
description: 'Resultats'
route_name: mon_module.go_results
menu.go_results_more:
title: 'Plus de Resultat'
parent: mon_module.go_results
description: 'Plus de Resultats'
route_name: mon_module.go_results_more
Arborescence
Local task
mon_module.links.task.yml
mon_module.root:
title: 'page de configuration'
route_name: mon_module.conf
base_route : mon_module.conf
mon_module.advanced:
title: 'Configuration avancée'
route_name: mon_module.more
base_route : mon_module.conf
Et après ?
Le thèming
Nouvelle conception
- Remplacement de PHPTemplate par Twig
- 1 entrée hook_theme déclare 1 template Twig
- Aucune fonction ne retourne directement du HTML
- "drupal_render" est au cœur de l'affichage
Preprocessing
- hook_preprocess / hook_preprocess_HOOK
- 4 niveaux d'interception
- module / template / engin / theme
- Altérations des theme_suggestions
Et après ?
Entity_API
Côté code PHP :
- POO Avancée !
- Annotations
- Classes parentes & Interfaces
- Héritage multiple ?
Changement de fonctionnement
- Ctools + EntityAPI + Rules + DS
- Objets techniques
- Déclaration Yaml
Et après ?
La gestion des configurations
Dans la théorie :
- Récupération de Feature & Strongarm
- Export en format Yaml
Dans la pratique :
- Gestion d'état (A jour / surchargé)
- Gestion de version (activ / stagging)
- Workflow de montée de version
Conclusions
« Ceci est une Révolution »
« J'comprends rien à c'truc, j'peux pas l'faire à l'arrache ? »
« Il n'y aura qu'une seule voie, celle de la vertu »
S. Jobs
M. Drupespierre
Dev PHP du dimanche
Merci
De Drupal 7 à Drupal 8
By Damien Robert (DrDam)
De Drupal 7 à Drupal 8
Une introduction aux évolutions apportées par Drupal 8
- 2,776