Aller au contenu principal


Administrer un module

Ce billet décrit un exemple de page accessible par le menu d'administration pour la gestion d'un module. Les concepts de bases à connaître figurent dans le billet "autopsie d'un module". 
Le code complet du contrôleur de cette page figure dans l'onglet en bas de page.

Billet créé le :
27 Mar 2023

1. Recherche du gestionnaire produisant l'affichage

Pour rendre la présentation plus concrète, ce billet est basé sur un module personnel : le module "dh_like".

Dans celui-ci, l'item de menu pour la page d'administration figure sous "/admin/config/system/" dans le menu d'administration. Cette position dans le menu est lié à l' attribut de la clé "parent" d'une hiérarchie du fichier "dh_like.links.menu.yml". Dans cette même hiérarchie, en attribut de la clé "route-name" figure le nom de la hiérarchie (dans mon exemple,  "dh_like.home") à chercher dans le fichier  "dh_like.routing.yml" pour trouver  le gestionnaire produisant l'affichage.

Dans cette hiérarchie "dh_like.home" du fichier  "dh_like.routing.yml",  la clé "path" donne le lien associé à la page et la clé "default", le gestionnaire chargé de produire l'affichage. Dans notre exemple, il s'agit de la fonction "content()" du contrôleur "LikeController".

Dans l'organisation Drupal, ce contrôleur est codé dans le fichier "src/Controller/LikeController.php" du site.

Le gestionnaire peut également être un formulaire. Lire dans le billet "le bloc likes version configurable", l'analyse d'un tel formulaire.

2. Analyse du fichier "LikeController.php"

Ce fichier remplace la version élémentaire présentée dans §7 du billet "autopsie d'un module". Il produit la page dont l'image ci-dessous est une illustration.

Cliquez pour agrandir l'image

Le code ci-dessous définit la classe LikeController et sa fonction content().

<?php
/**
* @file
* Contains \Drupal\dhlike\Controller\LikeController.
*/
namespace Drupal\dhlike\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Database\Query\PagerSelectExtender;
use Drupal\Core\Url;

class LikeController extends ControllerBase {
    public function content() {
    //
   }
}

Le code ci-dessous définit la fonction content() qui :

  •  récupère les données fournies par l'appel à la fonction getLike() par $r= $this->getLike()  ;

  •  construit et rend le renderable array $build,  (voir le §2.3).

    public function content() { 
        $r = $this->getLike();
        $build = array();
        // le pager.
        $build[] = array(
            '#type' => 'pager',
            );
        // la liste des pages likées.
        $build[] = array(
           '#theme' => 'dhlike_liste',
           '#data' => $r,
           '#attached' => [
                'library' => [
                    'dhlike/custom',
                ],
            ],
        );        
        // The pager.
        $build[] = array(
            '#type' => 'pager',
            );
       // valeur de retour
       return $build;
    }

2.1 la fonction getLike()

Cette fonction interroge la table "like" à travers la requête SQL 
"SELECT nid, uplike, downlike FROM `like` WHERE uplike <>0 or downlike <> 0 order by downlike desc, uplike desc, nid asc;" 
puis construit le tableau "$rows" qu'elle fournira en retour.
Le tableau $enrs produit par la requête (et qui contient les enregistrements extraits de la table "like"), est analysé dans la boucle 'foreach'.
Lors de cette analyse, le champ "nid" de chaque enregistrement "$enr" est utilisé pour retrouver le titre de la page.
Lorsque ce "nid" correspond à une entité "node" (ie : une page), le titre est extrait ( $leNode->label()) pour former le lien "$link". Ce lien "aggloméré" avec le contenu des champs "uplike" et "downlike" et "nid". (   $row[]=$n; $row[]=$enr->uplike; $row[]=$enr->downlike;) forme le tableau $row, (imaginez  une portion de ligne contenant 4 cellules adjacentes dans une feuille de calcul).
En fin de boucle, le tableau est "agglomérés"à "$rows" :  $rows[]= $row (imaginez  une plage de portions de lignes adjacentes). 
Ce tableau est la valeur de retour de la fonction getLikes().

Lorsque le "nid" ne correspond pas à une entité "node" ($lenode est NULL), l'enregistrement associé dans la table like est supprimé par la fonction deleteLike().

 /**
  * @return mixed
  */
 private function getLike(){
    try{
        $query = \Drupal::database()->select('like', 'sil');
        $group = $query
               ->orConditionGroup()  //orConditionGroup
               ->condition('uplike', 0,'<>')
               ->condition('downlike', 0,'<>')
               ;
        $query ->fields('sil', [ 'nid', 'uplike', 'downlike']);
        $query ->condition($group);
        $query->orderBy('downlike', 'DESC');
        $query->orderBy('uplike', 'DESC');
        $query->orderBy('nid', 'ASC');
        $pager = $query
       // extension de l'objet $query avec les éléments requis pour la pagination.
                        ->extend(PagerSelectExtender::class)
                         ->limit(10);
        $enrs = $pager->execute();
        //construction du tableau rows
        $rows=array();
        foreach ($enrs as $enr){
            //construction de la ligne
            $row = [];
            $n = $enr->nid;
            $leNode = \Drupal::entityTypeManager()->getStorage('node')->load($n);    
            if (!is_null($leNode)){
                $links = [];
                $links['Voir'] = [
                    'title' => $leNode->label(),
                    'url' => Url::fromUri('internal:/node/'.$n),
                  ];
                //la cellule Lien de la ligne
                $row[] = [
                    'data' => [
                      '#type' => 'operations',
                      '#links' => $links,
                    ],
                  ];
                //les 3 cellules suivantes de la ligne
                $row[]=$n;
                $row[]=$enr->uplike;
                $row[]=$enr->downlike;
            }
            else{
                $result = $this->deleteLike($n);
                \Drupal::messenger()->addMessage($this->t( $result . ' enregistrement(s) supprimé(s) '));
            }
            //la ligne est ajoutée au tableau rows
            $rows[]= $row;
        }
    }
   catch(Exception $ex){
        \Drupal::logger('dhlike')->error($ex->getMessage());
    }
   return $rows;     
 }

2.2 la fonction deleteLike()

Cette fonction reçoit en paramètre le nid à supprimer dans la table "like". Elle exécute la requête SQL : "delete nid from like where nid=" et rend le nombre de lignes supprimées dans la table.

 private function deleteLike($nid){
        // $nid : le n° du node à supprimer dans la table like
        try{
            $query = \Drupal::database()->delete('like');
            $query = $query ->condition('nid', $nid);
            $num =    $query ->execute();
            \Drupal::messenger()->addMessage($this->t('nid : ' . $nid . ' supprimé '));
        }
        catch(Exception $ex){
        \Drupal::logger('dhlike')->error($ex->getMessage());
        }
      return $num;
 }

2.3 le "renderable array"

Il reste à préparer le tableau des données à afficher.       
Ce tableau indique : 

  • le gabarit à utiliser pour la présentation des données : #theme¹;

  • la variable qui contient les données : #data ;

  • le fichier CSS de la bibliothèque  pour la mise en forme : #attached.

$build= array(         
           '#theme' => 'dhlike_liste',       
           '#data' => $rows,       
           '#attached' => [       
                   'library' => [       
                         'dhlike/custom',       
                ],       
            ],       
       );  

Ce "renderable array" est encadré par le "renderable array" affichant les liens de pagination  instanciés dans getLike() par le code :

 $pager = $query   
 // extension de l'objet $query avec les éléments requis pour la pagination.   
            ->extend('Drupal\Core\Database\Query\PagerSelectExtender')     
            ->limit(10);

 Accès à La documentation officielle qui traite l'initialisation d'un objet "pager" et des variables nécessaires pour que le système de rendu traite correctement les "renderable array"  de "#type 'pager'".

2.4 le gabarit "dhlike-liste.html.twig"

Ce code affiche la table HTML en affichant dans chaque ligne de la table un item du tableau "data".

<div class="dh_like_page">
    <table>
        <thead>
            <tr>
                <th>Voir</th>
                <th>Page ID</th>
                <th>Nb Likes</th>
                <th>Nb DisLikes</th>
            </tr>
        </thead>
        <tbody>
            {% for item in data %}
                <tr>
                    <td>{{ item[0] }}</td>
                    <td>{{ item[1] }}</td>
                    <td>{{ item[2] }}</td>
                    <td>{{ item[3] }}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
</div>

 

Cliquez sur le bouton pour copier le code
dans le presse papier  
    
<?php
/**
* @file
* Contains \Drupal\dhlike\Controller\LikeController.
*/
namespace Drupal\dhlike\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Database\Query\PagerSelectExtender;
use Drupal\Core\Url;
//
class LikeController extends ControllerBase {
   public function build() {
       $r = $this->getLike();
       //
       $build = array();
       // le pager.
       $build[] = array(
           '#type' => 'pager',
           );
       // la liste des pages likées.
       $build[] = array(
        '#theme' => 'dhlike_liste',
        '#data' => $r,
        '#attached' => [
               'library' => [
                   'dhlike/custom',
               ],
           ],
       );       
       // The pager.
       $build[] = array(
           '#type' => 'pager',
           );
       //
    return $build;
   }
//
/**
* @return mixed
*/
private function getLike(){
   try{
       $query = \Drupal::database()->select('like', 'sil');
       $group = $query
            ->orConditionGroup() //orConditionGroup
            ->condition('uplike', 0,'<>')
            ->condition('downlike', 0,'<>')
            ;
       $query ->fields('sil', [ 'nid', 'uplike', 'downlike']);
       $query ->condition($group);
       $query->orderBy('downlike', 'DESC');
       $query->orderBy('uplike', 'DESC');
       $query->orderBy('nid', 'ASC');
       // extension de l'objet $query avec les éléments requis pour la pagination.
       $pager = $query->extend(PagerSelectExtender::class)->limit(5);
$enrs = $pager->execute();
       //construction du tableau rows
       $rows=array();
       foreach ($enrs as $enr){
           //construction de la ligne
           $row = [];
           $n = $enr->nid;
           $leNode = \Drupal::entityTypeManager()->getStorage('node')->load($n);   
           if (!is_null($leNode)){
               $links = [];
               $links['Voir'] = [
                   'title' => $leNode->label(),
                   'url' => Url::fromUri('internal:/node/'.$n),
                ];
               //la cellule Lien de la ligne
               $row[] = [
                   'data' => [
                    '#type' => 'operations',
                    '#links' => $links,
                   ],
                ];
               //les 3 cellules suivantes de la ligne
               $row[]=$n;
               $row[]=$enr->uplike;
               $row[]=$enr->downlike;
           }
           else{
               $result = $this->deleteLike($n);
               \Drupal::messenger()->addMessage($this->t( $result . ' enregistrement(s) supprimé(s) '));
           }
           //la ligne est ajoutée au tableau rows
           $rows[]= $row;
       }
   }
catch(Exception $ex){
       \Drupal::logger('dhlike')->error($ex->getMessage());
   }
return $rows;   
}
/**
* @param $nid
* @return int
*/
private function deleteLike($nid){
       // $nid : le n° du node à supprimer dans la table like2
       try{
           $query = \Drupal::database()->delete('like');
           $query = $query ->condition('nid', $nid);
           $num =    $query ->execute();
           \Drupal::messenger()->addMessage($this->t('nid : ' . $nid . ' supprimé '));
       }
       catch(Exception $ex){
       \Drupal::logger('dhlike')->error($ex->getMessage());
       }
    return $num;
}
}