web-dev-qa-db-fra.com

entityQuery pour obtenir des nœuds référencés par d'autres nœuds comme un SQL JOIN

J'ai une requête d'entité pour obtenir un contenu de type article qui a un champ qui correspond à une valeur donnée, qui fonctionne comme prévu.

$query = \Drupal::entityQuery('node');
$query->condition('status', 1);
$query->condition('type', 'article');
$query->condition('field_some_field', 'some value');

J'ai maintenant un deuxième type de contenu detail_page Qui a une référence d'entité à un nœud de type article. Je voudrais obtenir du contenu de type article, comme avant, mais uniquement ceux qui ont été référencés dans le champ field_detail_page_article_ref D'un detail_page type de contenu.

Est-ce possible avec Entity Queries? En jouant avec le SQL brut, ce que je dois essentiellement faire est un INNER JOIN Ou LEFT JOIN Avec le champ field_detail_page_article_ref Pour voir si le nid existe. Mais il ne semble pas y avoir de fonction join() disponible pour les requêtes d'entité.

4
The Unknown Dev

J'ai juste eu exactement le même problème avec une instance Drupal 8, et même si je n'ai pas pu le résoudre avec une seule requête comme je l'aurais souhaité, j'ai réussi avec le Suivant:

Mon objectif était d'obtenir tous les nœuds de type A ou B qui répondent à certains critères, dont l'un est qu'ils sont référencés par le type C. (J'ai supprimé ces autres éléments ici pour me concentrer sur le problème.) Le type a une entité champ de référence qui permet à plusieurs entrées de taper A ou B.

Nous obtenons d'abord tous les nids référencés:

$connection = \Drupal::database();
$query = $connection->query("SELECT DISTINCT field_name_target_id  FROM {node__field_name}");
$referenced_nids = $query->fetchCol();

Notez que vous devrez ajuster votre code pour qu'il corresponde au nom de votre champ de référence. Voir https://www.drupal.org/docs/8/api/database-api/static-queries , c'est de là que j'ai extrait ce bit.

Ensuite, ma requête pour obtenir les nœuds/nids réels:

$storage = \Drupal::entityTypeManager()->getStorage('node');

$query = $storage->getQuery();

$nids = $query->condition('type', ['TypeA', 'TypeB'], 'IN')
  ->condition('status', 1)
  ->condition('nid', $referenced_nids, 'IN')
  ->sort('title')
  ->execute();

MISE À JOUR: J'ai appris aujourd'hui que la première étape de ma procédure n'est pas considérée comme appropriée par les normes Drupal, comme vous ne devriez pas 'pas faire de requêtes directes sur les tables Drupal (voir https://www.drupal.org/core/d8-bc-policy#schema ). La méthode suivante est plus brutal malheureusement, mais la mise en cache des résultats devrait aider.

Au lieu de cela, j'ai refactorisé la première partie en utilisant une EntityQuery.

// Get all the entities of type C, the referencing entity:
$query = \Drupal::entityQuery('node')
  ->condition('type', 'TypeC')
  ->condition('status', 1);
$typeC_nids = $query->execute();
$typeC_nodes = $storage->loadMultiple($typec_nids);

// Loop through the nodes and get all the references:
$referenced_nids = [];
foreach ($typeC_nodes as $node) {
 $references = array_column($node->field_name->getValue(), 'target_id');
 foreach ($references as $reference) {
   if (!in_array($reference, $referenced_nids)) {
     $referenced_nids[] = $reference;
   }
 }

}

Utilisez ensuite cette liste des NID référencés dans la deuxième requête.

3
beltouche

Vous pouvez utiliser requête de champ 'entité'

$query = \Drupal::entityQuery('node');
$query->condition('status', 1);
$query->condition('type', 'article');
$query->condition('field_some_field.entity:node.title', 'Referenced node title');
10
gambry