Débugger les requêtes SQL en Drupal 8

Contribué par Sylvain Lavielle le 05/08/2019

Le débuggage des requêtes SQL en Drupal 8 peut parfois s'avérer délicat. L'utilisation de la Database API et des dynamic queries peut rendre les problèmes localisés dans une requête plus difficiles à diagnostiquer que si on avait affaire à du simple code SQL. Ainsi lorsqu'on est confronté à ce type de problèmes, il est souvent utile de pouvoir visualiser directement le code SQL brute d'une requête, voire de pouvoir le tester sur des outils comme MySQL Workbench ou Sequel Pro afin de trouver la solutions sans s'encombrer de la surcouche de la Database API Drupal.

Malheureusement, obtenir le code SQL brute à partir d'un objet Query Drupal n'est pas un processus tout à fait évident.

Obtenir une version semi exploitable de la requête SQL est assez simple. les classes étendues de la classe Query disposant d'une méthode magique __toString() Il suffit de caster l'objet Query en chaîne de caractère.

Exemple pour une requête normal :

var_dump((string) $query);

Exemple pour une entity-query :

var_dump((string) $entityQuery->sqlQuery);

Cependant le code SQL ainsi obtenu n'est pas vraiment du SQL directement exploitable : Tout d'abord les noms des tables sont entourées par des accolades, et les placeholders permettant d'injecter les arguments de la requête ne sont pas résolus. Voici par exemple une dynamic query Drupal très simple :

$query = \Drupal::database()->select('node_field_data', 'nfd');
$query->addField('nfd', 'title');
$query->condition('t.promote', '1');
 
dpm((string) $query);

Et voici la version SQL que l'on obtient lorsqu'on utilise la fonction dmp du module devel :

SELECT nfd.title AS title
FROM 
{node_field_data} nfd
WHERE t.promote = :db_condition_placeholder_0

La fonction dpm permet simplement d'afficher le contenu d'une variable (ici notre objet query casté en chaîne de caractères).

Le module devel dispose d'une également d'un fonction dpq spécialisée dans le débuggage des requêtes et qui permet en grande partie d'améliorer le résultat.

$querySql = dpq($query);

Cela affichera alors la requête SQL avec les placeholders des arguments résolus

SELECT nfd.title AS title
FROM 
{node_field_data} nfd
WHERE t.promote = '1'

Cependant les noms des tables sont encore entourées d'accolades ce qui n'est pas une notation SQL standard. Évidemment, enlever deux accolades n'est pas la mer à boire, mais lorsqu'on se retrouve avec une table contenant de multiples jointures cela peut devenir plus pénible.

Afin de régler ce problème, il est possible de résoudre ces noms de tables en utilisant la fonction prefixTables de la classe de base Connection comme ceci :

dpm(\Drupal::database()->prefixTables(dpq($query, true)));

Ce qui donne un code SQL directement exécutable :

SELECT nfd.title AS title
FROM 
node_field_data nfd
WHERE t.promote = '1'

Étiquettes