Administrer un module
Ce billet décrit un exemple de page accessible par le menu d'administration pour la gestion d'un module. Pour rendre cette présentation plus concrète, il est basé sur un module personnel : le module "dh_like" et les concepts de base à 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.
1. Recherche du gestionnaire produisant l'affichage
Dans la hiérarchie du fichier "dh_like.links.menu.yml" 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 d'administration du module et la clé "default", le gestionnaire chargé de produire l'affichage. Dans notre exemple, il s'agit de la fonction "build()" du contrôleur "DhlikeListController".
Dans l'organisation Drupal, ce contrôleur est codé dans le fichier "src/Controller/DhlikeListController.php" du site.
2. Analyse du fichier "DhLikeListController.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.
Le code ci-dessous définit la classe DhlikeListController et sa fonction build().
<?php
/**
* @file
* Contains \Drupal\dhlike\Controller\DhLikeListController.
*/
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 DhlikeListController extends ControllerBase {
public function build() {
//
}
}
Le code ci-dessous définit la fonction buid() 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 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',
);
// 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' => $r,
'#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);
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>
<?php
/**
* @file
* Contains \Drupal\dhlike\Controller\DhlikeListController.
*/
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 DhlikeListController 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('like2', '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) '));
\Drupal::logger('dhLike')->notice(' le node %title n° @type n existe plus.',
array(
'@type' => $n,
'%title' => $leNode->label(),
));
}
//la ligne est ajoutée au tableau rows
$rows[]= $row;
}
}
catch(Exception $ex){
\Drupal::logger('dhlike')->error($ex->getMessage());
\Drupal::logger('dhLike')->notice(' namespace : '.__NAMESPACE__ );
}
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('like2');
$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());
\Drupal::logger('dhLike')->notice(' namespace : '.__NAMESPACE__ );
}
return $num;
}
}