Erstellen Sie eine EntityFieldQuery, die referenzierte Entitäten auswählt

10

Ich suche nach der ID der Entität vom Typ A und kenne die ID der Entität B, die auf A verweist.

Ich habe ein paar nette Quellen über EntityFieldQuery gefunden. Ich war erstaunt, dass ich in Google Ergebnisse von .NET erhalten habe :) (ist das ein Zeichen für Drupals Reife? :). Aber ich habe es nicht geschafft, dies zu finden. Bitte helfen Sie ...

Einige der Quellen:

So sieht es beim Laden von Entitäten aus - Sie werden verstehen, dass ich diese Abfrage brauche :) Der Wrapper dient hauptsächlich zum Üben. Beachten Sie, dass die Zielentität geladen wird - ziemlich viele Abfragen.

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

  $tsl = $slm->field_sl_tpref->value();
  echo $tsl->id;
Mojzis
quelle
1
Es EntityFieldQuerykann nur auf eine Gruppe von Entitäten verweisen, es können leider keine Beziehungen zu anderen Entitäten erstellt werden. Es kann auch das Rück nur eine Art von Einheit zu einer Zeit also , selbst wenn Sie diese Beziehungen der Ergebnisse wären unzuverlässig schaffen könnten.
Clive
@Clive würde es Ihnen etwas ausmachen, das als Antwort hinzuzufügen, damit ich es bestätigen kann? danke :)
mojzis

Antworten:

15

Sie können target_idanstelle von verwenden value, um Entitäten basierend auf der ID der referenzierten Entitäten abzurufen:

$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
quelle
danke, aber ich glaube nicht, dass ich danach gesucht habe ... ich habe versucht, die andere Richtung zu finden, auf diese Weise würden Sie das A kennen und nach dem B suchen :)
mojzis
2

äh, ist das Beziehungsmodul das, wonach Sie suchen? Es klingt so, als ob Sie Beziehungen zwischen X- und Y-Entitäten definieren möchten. Es verfügt über eine eigene RelationQuery (ein Wrapper um EFQ) und RelationQueryEndpoints, um diese Art von Informationen einfach abzurufen.

Tenken
quelle
Vielen Dank. Leider habe ich bereits einige Beziehungen mit Entityreference definiert, daher wäre ein Wechsel zu Relation problematisch ... werde es beim nächsten Mal versuchen :).
Mojzis
2

Ich weiß, dass dies eine ältere Frage ist, aber für Leute, die von Google darauf zugreifen, dachte ich, ich würde hier einen anderen Ansatz einbringen.

Aus der obigen Beschreibung geht hervor, dass das Setup zwei Entitätstypen hat, A und B. B-Referenzen A mit Entitätsreferenz, die ich annehme. Wenn Sie also die ID von B haben, sollten Sie ein Feld mit der ID von A in der Datenbank speichern.

Code Hinweise:

  • Ursprüngliche NID - $original_node->nidDies wäre die ID von B.
  • Bundle-Typ - $typeDies sollte der Typ von A sein
  • Die Feldbedingung sucht nur nach einem Feld, das die Referenz enthält
  • Weitere Informationen zur Verwendung von EFQ finden Sie hier

Code

// 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);
}

Sie können auch bidirektionale Entitätsreferenzen einrichten und dieselbe Abfrage oben rückwärts ausführen. Sie können ein Modul wie CER verwenden , um sicherzustellen, dass diese Referenzen auf dem neuesten Stand sind. Oder richten Sie eine Regel ein, um die Referenz auf dem neuesten Stand zu halten. Ich habe beide verwendet.

Verbrennungszeremonie
quelle
Wenn field_NAME_OF_FIELD mehrwertig ist, fieldCondition('field_NAME_OF_FIELD', 'target_id', $original_node->nid, '=')funktioniert das? sollte es geändert werden zu fieldCondition('field_NAME_OF_FIELD', 'target_id', array($original_node->nid), 'IN'). Es konnte nichts darüber gefunden werden, wie eine Bedingung auf ein mehrwertiges Entitätsreferenzfeld angewendet wird. irgendein Vorschlag?
Kiranking
1
Ich weiß, dass dies ein alter Kommentar ist, aber wenn Sie das '=' deaktivieren, ist EntityFieldQuery standardmäßig IN, sodass fieldCondition ('field_NAME_OF_FIELD', 'target_id', $ original_node-> nid) in dieser Situation tatsächlich funktioniert. Sie wissen das wahrscheinlich schon jetzt, aber falls jemand später darüber stolpert :)
burnsjeremy
1

Eine ziemlich dynamische Lösung (auch ein bisschen schmutzig, aber ich brauchte sie schnell), sodass Sie den Namen des Referenzierungsfelds nicht fest codieren müssen und sie automatisch mit einem neuen Referenzierungsfeld behandelt wird, das Sie in Zukunft hinzufügen werden:

in Ihrem benutzerdefinierten Modul:

/**
 * 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;
}

Wo müssen Sie die übergeordneten Knoten erhalten, wenn der untergeordnete Knoten angegeben ist:

$nodes = _MY_CUSTOM_MODULE_get_referencing_nodes($node);
Gueno
quelle