Créer un EntityFieldQuery qui sélectionne les entités référencées

10

Je recherche l'ID de l'entité de type A et je connais l'ID de l'entité B qui fait référence à A.

J'ai trouvé quelques belles sources sur EntityFieldQuery. J'ai été étonné que j'obtienne des résultats de .NET dans google :) (est-ce un signe de maturité de Drupal? :). Mais n'a pas réussi à trouver cela. Veuillez aider ...

Quelques sources:

Voici à quoi cela ressemble avec des charges d'entité - vous comprendrez que j'ai besoin de cette requête :) Le wrapper est là pour la pratique principalement. Notez qu'il charge l'entité cible - beaucoup de requêtes.

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

  $tsl = $slm->field_sl_tpref->value();
  echo $tsl->id;
mojzis
la source
1
Un EntityFieldQueryne peut référencer qu'un ensemble d'entités, il ne peut malheureusement pas créer de relations avec d'autres entités. Il ne peut également renvoyer qu'un seul type d'entité à la fois, même si vous pouviez créer ces relations, les résultats ne seraient pas fiables.
Clive
@Clive voudriez-vous ajouter cela comme réponse, donc je peux le confirmer? merci :)
mojzis

Réponses:

15

Vous pouvez utiliser target_idau lieu de valuepour récupérer des entités en fonction de l'ID des entités référencées:

$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
la source
merci, mais je ne pense pas que ce soit ce que je cherchais ... j'essayais d'obtenir l'autre direction, de cette façon vous connaîtrez le A et chercherez le B :)
mojzis
2

euh, le module de relation est-il ce que vous recherchez? On dirait que définir les relations entre les entités X et Y est ce que vous voulez faire. il a ses propres RelationQuery (un wrapper autour d'EFQ) et RelationQueryEndpoints pour obtenir facilement ce type d'informations.

tenken
la source
Merci. malheureusement, j'ai déjà défini quelques relations avec entityreference, donc passer à une relation serait problématique ... j'essaierai la prochaine fois :).
mojzis
2

Je sais que c'est une question plus ancienne, mais pour les gens qui y arrivent de Google, j'ai pensé que je lancerais une autre approche ici.

D'après la description ci-dessus, la configuration a 2 types d'entités, A et B. B référence A avec la référence d'entité que je suppose. Donc, si vous avez l'ID de B, vous devriez avoir un champ avec l'ID de A stocké dans la base de données.

Notes de code:

  • NID d'origine - $original_node->nidCe serait l'ID de B
  • Type de bundle - $typeil doit s'agir du type A
  • La condition de champ recherche simplement le champ contenant la référence
  • Pour plus d'informations sur l'utilisation d'EFQ, consultez ce

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

Vous pouvez également configurer des références d'entité bidirectionnelles et effectuer la même requête ci-dessus à l'envers. Vous pouvez utiliser un module comme CER pour vous assurer que ces références sont mises à jour. Ou définissez une règle pour maintenir la référence à jour, j'ai utilisé les deux.

burnsjeremy
la source
Si field_NAME_OF_FIELD est à valeurs multiples, cela fieldCondition('field_NAME_OF_FIELD', 'target_id', $original_node->nid, '=')fonctionnera-t-il? devrait-il être changé en fieldCondition('field_NAME_OF_FIELD', 'target_id', array($original_node->nid), 'IN'). Impossible de trouver quoi que ce soit sur la façon d'appliquer la condition sur le champ de référence d'entité à valeurs multiples. toute suggestion?
kiranking
1
Je sais que c'est un vieux commentaire mais si vous laissez le '=' off EntityFieldQuery par défaut à IN donc fieldCondition ('field_NAME_OF_FIELD', 'target_id', $ original_node-> nid) fonctionnerait réellement dans cette situation. Vous le savez probablement déjà, mais au cas où quelqu'un d'autre
tomberait dessus
1

une solution assez dynamique (un peu sale aussi mais j'en avais besoin rapidement) donc vous n'avez pas besoin de coder en dur le nom du champ de référencement et il est automatiquement géré avec un nouveau champ de référencement que vous ajouterez à l'avenir:

dans votre module personnalisé:

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

où vous devez obtenir les nœuds parents étant donné le nœud enfant:

$nodes = _MY_CUSTOM_MODULE_get_referencing_nodes($node);
Gueno
la source