Puncte:0

Efectuați entityQuery cu mai multe condiții de câmpuri pe câmpurile de referință

drapel um

Am un tip de nod articol cu ​​un câmp care face referire la articole legate. Dacă un articol are mai puțin de 4 referințe pentru acel câmp, trebuie să caut alte articole care

  • nu sunt nodul curent
  • au fost actualizate cu mai puțin de 2 ani în urmă
  • bifați o casetă de selectare „favorită”.
  • partajați cel puțin un id de cultură (referință taxonomie) ȘI cel puțin un id de temă (referință taxonomie)

Și de fapt mă întreb cum să îndeplinesc această ultimă nevoie... Bazat pe Efectuați o interogare cu o condiție de câmp de entitate cu mai multe valori, am scris urmatorul cod:

<?php

spațiu de nume Drupal\modulul_meu\Preproces;

utilizați Drupal\Core\DependencyInjection\ContainerInjectionInterface;
utilizați Drupal\Core\Entity\EntityTypeManagerInterface;
utilizați Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Tipul de nod de preprocesare Articol.
 */
clasa MyArticle implementează ContainerInjectionInterface {

  const MAX_RELATED_ARTICLES = 4;

  /**
   * Taxonomie termen de stocare.
   *
   * @var \Drupal\node\NodeStorage
   */
  protejat $nodeStorage;

  /**
   * Constructor de clasă.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   * Managerul de tip de entitate.
   */
  funcția publică __construct(EntityTypeManagerInterface $entity_type_manager) {
    $this->nodeStorage = $entity_type_manager->getStorage('nod');
  }

  /**
   * {@inheritdoc}
   */
  funcția publică statică create(ContainerInterface $container) {
    returnează static nou (
      $container->get('entity_type.manager')
    );
  }

  /**
   * Preprocesare articol tip nod.
   *
   * @param matrice $variabile
   * O serie de variabile utilizate pentru a reda nodul.
   */
  preprocesare a funcției publice (matrice &$variabile) {
    if ('full' === $variables['view_mode']) {
      $this->preprocessFull($variabile);
    }
  }

  /**
   * Preprocesează articolul de tip nod în modul de vizualizare complet.
   *
   * @param matrice $variabile
   * O serie de variabile utilizate pentru a reda nodul.
   */
  funcția protejată preprocessFull(array &$variables) {
    $nod = $variabile['nod'];

    $related_articles = $node->get('related_articles')->referencedEntities();
    $themes = $node->get('themes')->referencedEntities();
    $culture = $node->get('culturi')->referencedEntities();
    $teme_ids = $culturi_ids = [];
    foreach ($teme ca $term) {
      $themes_ids[] = $term->id();
    }
    foreach ($culturi ca $term) {
      $culturi_ids[] = $term->id();
    }
    $nb_related_articles = count($related_articles);

    dacă ($nb_related_articles < self::MAX_RELATED_ARTICLES) {
      $limit = self::MAX_RELATED_ARTICLES - $nb_related_articles;
      $changed_boundary = strtotime('-2 ani');
      $query = $this->nodeStorage->getQuery()
        ->condition('tip', 'articol')
        ->condition('status', 1)
        ->condition('nid', $node->id(), '<>')
        ->condition('favorit', 1)
        ->condition('schimbat', $changed_boundary, '>=')
        ->interval(0, $limit);
      $sau_teme = $sau_culturi = $interogare->orConditionGroup();
      foreach ($themes_ids ca $tid) {
        $sau_teme->condition('culturi', $tid);
      }
      foreach ($cultures_ids ca $tid) {
        $sau_culturi->condition('teme', $tid);
      }
      $și = $interogare->andConditionGroup()
        ->condition($or_themes);
      $interogare->condiție($și);
      $și = $interogare->andConditionGroup()
        ->condition($or_cultures);
      $interogare->condiție($și);
      $node_ids = $query->execute();
    }
  }

}

care îmi dă următoarea întrebare:

SELECTAȚI „base_table”. „vid” AS „vid”, „base_table”. „nid” AS „nid”
DIN „nod” „base_table”
INNER JOIN "node_field_data" "node_field_data" ON "node_field_data"."nid" = "base_table"."nid"
INNER JOIN "node__favorite" "node__favorite" ON "node__favorite"."entity_id" = "base_table"."nid"
LEFT JOIN "node__cultures" "node__cultures" ON "node__cultures"."entity_id" = "base_table"."nid"
LEFT JOIN "node__themes" "node__themes" ON "node__themes"."entity_id" = "base_table"."nid"
LEFT JOIN "node__cultures" "node__cultures_2" ON "node__cultures_2"."entity_id" = "base_table"."nid"
LEFT JOIN "node__themes" "node__themes_2" ON "node__themes_2"."entity_id" = "base_table"."nid"
WHERE ("node_field_data"."tip" = "articol")
ȘI ("node_field_data"."status" = "NODE_PUBLISHED")
ȘI ("node_field_data"."nid" <> '19533')
ȘI ("nod__favorite"."favorite_value" = "1")
ȘI ("node_field_data"."schimbat" >= '1583280325')
ȘI ("node__cultures"."cultures_target_id" = '5077') sau ("node__themes"."themes_target_id" = '42') sau ("node__themes"."themes_target_id" = '38'))
ȘI (("node__cultures_2"."cultures_target_id" = '5077') sau ("node__themes_2"."themes_target_id" = '42') sau ("node__themes_2"."themes_target_id" = '38'))
GROUP BY base_table.vid, base_table.nid
LIMITA 4 OFFSET 0

Și nu este ceea ce mă așteptam, deoarece am nevoie de o condiție AND între ID-urile culturii și ID-urile temei. As avea nevoie de ceva de genul:

AND ("node__cultures"."cultures_target_id" = '5077') AND ("node__themes"."themes_target_id" = '42') sau ("node__themes"."themes_target_id" = '38')))

în loc de

ȘI ("node__cultures"."cultures_target_id" = '5077') sau ("node__themes"."themes_target_id" = '42') sau ("node__themes"."themes_target_id" = '38'))

Deci întrebarea mea este: există o modalitate de a realiza acest lucru cu And/OrConditionGroup sau ar trebui să folosesc subinterogări pentru a potrivi niște ID-uri specifice atât pentru teme, cât și pentru culturi?

Puncte:1
drapel in

Folosind fragmentul pe care îl furnizați (și așteptați să îl aveți), probabil că ați putea folosi operatorul IN în loc de AND:

AND (("node__cultures"."cultures_target_id" = '5077') AND (("node__themes"."themes_target_id" IN ('42', '38'))

În acest fel, obțineți culturile cu ID-ul țintă 5077 (deoarece este același pentru ambele) și temele cu ID-ul țintă 42 SAU 38.

Puncte:1
drapel in

Un lucru mic este că nu potriviți ID-urile și câmpurile dvs. aici:

foreach ($themes_ids ca $tid) {
  $sau_teme->condition('culturi', $tid); // ar trebui să folosească câmpul „teme”
}
foreach ($cultures_ids ca $tid) {
  $sau_culturi->condition('teme', $tid); // ar trebui să folosească câmpul „culturi”
}

Dar problema majoră este aici:

$și = $interogare->andConditionGroup()
  ->condition($or_themes);
$interogare->condiție($și);
$și = $interogare->andConditionGroup()
  ->condition($or_cultures);
$interogare->condiție($și);

Înfășurați fiecare condiție SAU în starea ei ȘI.

Dar ceea ce vrei este o condiție AND care să împacheteze cele două condiții SAU:

$și = $interogare->andConditionGroup()
  ->condition($or_themes)
  ->condition($or_cultures);
$interogare->condiție($și);

În plus, așa cum a menționat @pmichelazzo, puteți (ar trebui? Aș) să utilizați IN în loc de grupurile dvs. de condiții OR, de ex.

$cultures_and_themes = $query->andConditionGroup()
  ->condition('culturi', $cultures_ids, 'IN')
  ->condition('themes', $themes_ids, 'IN');
$interogare->condiție($culturi_și_teme);  
MacSim avatar
drapel um
și din moment ce `andConditionGroup()` este comportamentul implicit, am avut nevoie doar de a lega acele condiții la interogare. Voi accepta răspunsul tău pentru că este mai complet decât răspunsul @pmichelazzo, dar și el a avut dreptate. Vă mulțumesc baieti

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.