Zbuduj EntityFieldQuery, który wybiera encje odniesienia

10

Szukam identyfikatora jednostki typu A i znam identyfikator jednostki B, która odwołuje się do A.

Znalazłem kilka fajnych źródeł o EntityFieldQuery. Byłem zaskoczony, że otrzymałem wyniki z .NET w google :) (czy to oznaka dojrzałości Drupala? :). Ale nie udało mi się tego znaleźć. Proszę pomóż ...

Niektóre źródła:

Tak to wygląda z ładowaniami encji - zrozumiesz, że potrzebuję tego zapytania :) Opakowanie służy głównie do ćwiczeń. Zauważ, że ładuje jednostkę docelową - całkiem sporo zapytań.

  $b = entity_load('B', array($id));
  $bm = entity_metadata_wrapper('B', $sl[$id]);

  $tsl = $slm->field_sl_tpref->value();
  echo $tsl->id;
mojzi
źródło
1
EntityFieldQueryMoże odwoływać się tylko jeden zbiór jednostek, nie mogą tworzyć relacje z innymi podmiotami niestety. Może również zwracać tylko jeden typ encji na raz, więc nawet gdyby można było utworzyć te relacje, wyniki byłyby niewiarygodne.
Clive
@Clive, czy mógłbyś dodać to jako odpowiedź, więc mogę to potwierdzić? dzięki :)
mojzis,

Odpowiedzi:

15

Możesz użyć target_idzamiast valuedo pobierania encji na podstawie identyfikatora encji, do których istnieją odniesienia:

$query = new EntityFieldQuery();
$query->entityCondition('entity_type', <type-of-the-entity>);
$query->fieldCondition('<name-of-the-field-referring-the-other-entity>', 'target_id', <id-of-the-referenced-entity>, '=');
$results = $query->execute();
pablo
źródło
dzięki, ale nie sądzę, że tego właśnie szukałem ... starałem się
pójść
2

err, czy szukasz modułu relacyjnego ? Wygląda na to, że zdefiniowanie relacji między elementami X i Y jest tym, czego chcesz. ma własne RelationQuery (opakowanie wokół EFQ) i RelationQueryEndpoints, aby łatwo uzyskać tego rodzaju informacje.

tenken
źródło
dzięki. niestety już zdefiniowałem kilka relacji z odniesieniem do bytu, więc przejście do relacji byłoby problematyczne ... spróbuję następnym razem :).
mojzis,
2

Wiem, że to jest starsze pytanie, ale dla ludzi, którzy docierają do tego z Google, pomyślałem, że rzuciłbym tutaj inne podejście.

Z powyższego opisu konfiguracja ma 2 typy encji, A i B. B referencje A z referencją encji Zakładam. Więc jeśli masz identyfikator B, powinieneś mieć pole z identyfikatorem A przechowywane w bazie danych.

Uwagi do kodu:

  • Oryginalny NID - $original_node->nidbyłby to identyfikator B
  • Rodzaj pakietu - $typepowinien to być typ A
  • Warunek pola szuka tylko pola zawierającego odniesienie
  • Aby uzyskać więcej informacji na temat korzystania z EFQ, zobacz to

Kod

// Start a new EFQ
$query = new EntityFieldQuery();

// Define query, the user load is probably not needed but sometimes is.
$query->entityCondition('entity_type', 'node')
      ->entityCondition('bundle', $type)
      ->fieldCondition('field_NAME_OF_FIELD', 'target_id', $original_node->nid, '=')
      ->addMetaData('account', user_load(1));

// Execute query, result with have node key
$result = $query->execute();

// If results it will be in node key
if (isset($result['node'])) {
  $nids = array_keys($result['node']);
  // This example has multiple nodes being referenced by one node
  $nodes = node_load_multiple($nids, array('type' => $type));
  // Devel module needed
  dpm($nodes);
}

Możesz także skonfigurować dwukierunkowe odwołania do encji i wykonać to samo zapytanie powyżej. Możesz użyć modułu takiego jak CER, aby upewnić się, że te referencje są aktualne. Lub skonfiguruj regułę, aby aktualizować referencje, użyłem obu.

Burnsjeremy
źródło
Jeśli field_NAME_OF_FIELD jest wielowartościowy, czy zadziała fieldCondition('field_NAME_OF_FIELD', 'target_id', $original_node->nid, '=')? powinien zostać zmieniony na fieldCondition('field_NAME_OF_FIELD', 'target_id', array($original_node->nid), 'IN'). Nie można znaleźć niczego o tym, jak zastosować warunek w polu odwołania do jednostki wielowartościowej. jakieś sugestie?
Kiringing
1
Wiem, że to stary komentarz, ale jeśli pozostawisz '=' wyłączone EntityFieldQuery domyślnie ustawiony jest na IN, więc fieldCondition ('field_NAME_OF_FIELD', 'target_id', $ original_node-> nid) faktycznie działałoby w tej sytuacji. Prawdopodobnie już o tym wiesz, ale po prostu wpadnij na kogoś, kto natknie się na to później :)
burnsjeremy
1

dość dynamiczne rozwiązanie (trochę brudne, ale potrzebowałem go szybko), więc nie musisz sztywno kodować nazwy pola referencyjnego i jest ono obsługiwane automatycznie z nowym polem referencyjnym, które dodasz w przyszłości:

w niestandardowym module:

/**
 * Implement hook_field_create_instance().
 */
function MY_CUSTOM_MODULE_field_create_instance() {
  _MY_CUSTOM_MODULE_set_variable_node_back_references();
}

/**
 * Implement hook_field_delete_field().
 */
function MY_CUSTOM_MODULE_field_delete_field() {
  _MY_CUSTOM_MODULE_set_variable_node_back_references();
}

/**
 * Set Variable node_back_references.
 */
function _MY_CUSTOM_MODULE_set_variable_node_back_references() {
  $field_list = db_select('field_config', 'fc')
    ->fields('fc', array('field_name', 'data'))
    ->condition('fc.data', '%"foreign keys";a:1:{s:4:"node"%', 'like')
    ->condition('fc.deleted', 0);
  $field_list->innerJoin('field_config_instance', 'fci', 'fci.field_name = fc.field_name');
  $field_list->rightJoin('node_type', 'n', 'n.type = fci.bundle');
  $fields = $field_list->execute()->fetchAll();

  $fields_array = array();
  foreach ($fields as $field) {
    $unserialized = unserialize($field->data);
    if (isset($unserialized['settings']['handler_settings']['target_bundles'])) {
      foreach ($unserialized['settings']['handler_settings']['target_bundles'] as $bundle) {
        $fields_array[$bundle][] = $field->field_name;
      }
    }
  }

  variable_set('node_back_references', $fields_array);
}

function _MY_CUSTOM_MODULE_get_referencing_nodes($node) {
  $nids = array();
  $fields = variable_get('node_back_references', array());
  if (isset($fields[$node->type])) {
    foreach ($fields[$node->type] as $field) {
      $query = new \EntityFieldQuery();
      $query->entityCondition('entity_type', 'node');
      $query->propertyCondition('status', 1);
      $query->fieldCondition($field, 'target_id', $node->nid);
      $result = $query->execute();
      $nids = isset($result['node']) ? array_merge(array_keys($result['node']), $nids) : $nids;
    }
    $nodes = (!empty($nids)) ? node_load_multiple($nids) : array();

    return $nodes;
  }

  return $nids;
}

gdzie musisz uzyskać węzły nadrzędne, biorąc pod uwagę węzeł podrzędny:

$nodes = _MY_CUSTOM_MODULE_get_referencing_nodes($node);
Gueno
źródło