Drupal 8 - Les EntityQuery par l'exemple

Posté le Mardi 26 septembre 2017 - 08:24
Dernière mise à jour le Vendredi 9 mars 2018 - 11:11
Entity Query

Remplacement des Entity Field Query en drupal 7, les Entity Query permettent d'effectuer des requêtes sur nos types d'entités, (custom ou non) selon leurs propriétés ou leurs champs (fields).

Elles sont une bonne solution pour faire des queries même avancées, sans avoir à faire des jointures à en perdre la tête.

Un exemple simple

Récupération et chargement de l'ensemble des utilisateurs activés.

  1. //On commence par donner le type d'entité que l'on souhaite « requêter »
  2. $query = \Drupal::entityQuery('user');
  3. //On ajoute une condition, ici « status = 1 » pour ne récupérer que les utilisateurs actifs
  4. $query->condition('status', 1);
  5. //On lance la requête et récupère les ids des utilisateurs.
  6. $users_ids = $query->execute();
  7. //on charge les utilisateurs en question
  8. $users = User::loadMultiple($users_ids);

Que peut-on peut requêter ?

Sous drupal 8, tout est entité (ou presque), on peut ainsi faire des requêtes sur :

  • Les noeuds
  • Les blocs
  • Les utilisateurs
  • Les menus
  • Les éléments de menus
  • Nos types d'entités custom
  • ...

Bref, beaucoup de chose !

La déclaration du type d'entité se fait lors de la génération de la requête :

Pour requêter les utilisateurs

  1. // Requête sur les utilisateurs
  2. $query = \Drupal::entityQuery('user');
  3.  
  4. // Requête sur les noeuds
  5. $query = \Drupal::entityQuery('node');
  6.  
  7. // Requête sur les terme de taxonomie
  8. $query = \Drupal::entityQuery('taxonomy_term');

Les conditions

  1. $query->condition(champ_ou_propriété, valeur, opérateur);

Le champ sur lequel on fait une condition peut -être soit une propriété (nid, changed, created, title, name...) ou bien un champ « field » (field_tags, field_image...)

Exemple en requetant les noeuds de type « produit » :

  1. $query = \Drupal::entityQuery('node');
  2. $query->condition('type', 'produit');

Par défaut l'opérateur est : = (égal)

  1. // uid == 1
  2. $query->condition('uid', 1);

mais on peut évidement le spécifier :

  1. // uid "différent de" 1
  2. $query->condition('uid', $user->id(), '<>');

On peut utiliser le IN, afin de, par exemple récupérer et charger tous les users en fonction d'un field "interest" qui fait référence à des termes de taxonomies :

  1. $interests = [127, 128, 27];
  2. $query = \Drupal::entityQuery('user');
  3. $query->condition('field_interests', $interests, 'IN');
  4. $profils_similaires = $query->execute();
  5.  
  6. $users = User::loadMultiple($profils_similaires);

Avec un "LIKE", afin de tester le même département :

  1. // si $code_postal = "123456"
  2. // field_adresse_zipcode LIKE "12%"
  3. $query->condition('field_adresse_zipcode', substr($code_postal, 0, 2).'%', 'LIKE');

Plus propre en utilisant db_like qui fait un échappement

  1. $query = \Drupal::entityQuery('taxonomy_term');
  2. $query->condition('vid', 'tags');
  3. $query->condition('name', '%' . db_like($keyword) . '%', 'like');
  4. $terms = Term::loadMultiple($query->execute());

Tester si un champ est vide ou non vide (is null / is not null)

(Comme signalé par Christophe Caron dans les commentaires)

  1. // Tester que le champ field_name soit renseigné :
  2. // Équivalent à where field_name IS NOT NULL
  3. $query->exists('field_name');
  4.  
  5. // Tester que le champ field_name ne soit pas renseigné :
  6. // Équivalent à where field_name IS NULL
  7. $query->notExists('field_name');

Conditions multiples

Aussi on peut ajouter plusieurs conditions, ici je fais un test sur la date de naissance, qu'elle soit bien comprise entre $min_date & $max_date :

  1. $query = \Drupal::entityQuery('user');
  2. $query->condition('field_interests', $interests, 'IN');
  3. $query->condition('field_birthday', $min_date->format('Y-m-d'), '<');
  4. $query->condition('field_birthday', $max_date->format('Y-m-d'), '>');
  5. $profils_similaires = $query->execute();
  6.  
  7. $users = User::loadMultiple($profils_similaires);

Avec des conditions Or

On peut utiliser des conditions logiques « OR », ici je veux récuperer les utilisateurs qui ont les mêmes centres d'intérêts (field_interests) OU qui sont manuellement mis en avant (field_pinned)

  1. $query = \Drupal::entityQuery('user');
  2.  
  3. $condition_or = $query->orConditionGroup();
  4. $condition_or->condition('field_pinned',1);
  5. $condition_or->condition('field_interests', $interests, 'IN');
  6.  
  7. $query->condition($condition_or);
  8.  
  9. $profils_similaires = $query->execute();
  10.  
  11. $users = User::loadMultiple($profils_similaires);

Avec des conditions OR et AND

On peut faire des conditions un peu plus balaises, avec ici donc : soit les utilisateurs mis en avant (field_pinned) OU (qui ont les même centres d'intérêts (field_interest) ET qui sont nés après $max_date ET avant $min_date :

  1. $query = \Drupal::entityQuery('user');
  2.  
  3. $condition_or = $query->orConditionGroup();
  4. $condition_or->condition('field_pinned',1);
  5.  
  6. $condition_and = $query->andConditionGroup();
  7.  
  8. $condition_and->condition('field_interests', $interests, 'IN');
  9. $condition_and->condition('field_birthday', $min_date->format('Y-m-d'), '<');
  10. $condition_and->condition('field_birthday', $max_date->format('Y-m-d'), '>');
  11.  
  12. $condition_or->condition($condition_and);
  13.  
  14. $query->condition($condition_or);
  15.  
  16. $profils_similaires = $query->execute();
  17.  
  18. $users = User::loadMultiple($profils_similaires);

Gestion de la pagination et du nombre de résultats

  1. // 20 résultats sans en passer aucun (0)
  2. $query->range(0, 20);
  3.  
  4. // 20 résultats en passant les 10 premiers (0)
  5. $query->range(10, 20);

Gestion du tri

  1. // Tri par date de création (ASC par défaut)
  2. $query->sort('created');

ou en précisant le sens :

  1. // Tri sur le champ field_birthday par ordre croissant
  2. $query->sort('field_birthday', 'ASC');
  3.  
  4. // Tri sur le champ field_birthday par ordre décroissant
  5. $query->sort('field_birthday', 'DESC');

Compter le nombre de résultats

  1. $query = \Drupal::entityQuery('node');
  2. $query->condition('type', 'produit');
  3. $nb_resultats = $query->count()->execute();

 

 

Comments

Posté le Lundi 8 janvier 2018 - 10:37

Bravo pour cet article très précis, j'ajouterai :

Vérifier qu'un champ n'est pas vide :
$query->exists('field_name');

Vérifier qu'un champ est vide :
$query->notExists('field_name');

Laurent

Posté le Mercredi 16 mai 2018 - 12:47

Bonjour,

Comment peut-on récupérer la liste complète (sans condition) d'un type d'entité ?
J'ai essayé
Drupal::entityQuery('my_entity_type')->execute();
Mais ça ne me ramène rien.

Posté le Mercredi 16 mai 2018 - 13:02

Pour cela, le plus simple est de faire :

MyEntityType::loadMultiple()

Sym

Posté le Jeudi 21 juin 2018 - 12:19

Bonjour,
Merci pour ces exemples très clairs :)
Je me demande par contre comment trier sur deux champs différents . Par exemple : par position (integer) puis par date de creation.

Ajouter un commentaire

Ne sera pas publié

HTML restreint

  • Balises HTML autorisées : <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Les lignes et les paragraphes vont à la ligne automatiquement.
  • Les adresses de pages web et les adresses courriel se transforment en liens automatiquement.
CAPTCHA
Désolé, pour ça, mais c'est le seul moyen pour éviter le spam...