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