Crie um EntityFieldQuery que selecione entidades referenciadas

10

Estou procurando o ID da entidade do tipo A e sei o ID da entidade B que faz referência a A.

Encontrei algumas boas fontes sobre o EntityFieldQuery. Fiquei surpreso que eu estava obtendo resultados do .NET no google :) (é um sinal da maturidade do Drupal? :). Mas não conseguiu encontrar isso. Por favor ajude ...

Algumas das fontes:

Isto é o que parece com cargas de entidade - você entenderá que preciso dessa consulta :) O wrapper está lá principalmente para a prática. Observe que ele carrega a entidade de destino - muitas consultas.

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

  $tsl = $slm->field_sl_tpref->value();
  echo $tsl->id;
mojzis
fonte
1
Um EntityFieldQuerysó pode fazer referência a um conjunto de entidades, não pode criar relacionamentos com outras entidades infelizmente. Ele também pode retornar apenas um tipo de entidade por vez; mesmo que você possa criar esses relacionamentos, os resultados não serão confiáveis.
Clive
@Clive, você se importaria de adicionar isso como resposta, para que eu possa confirmar? Obrigado :)
mojzis

Respostas:

15

Você pode usar, em target_idvez de, valuepara recuperar entidades com base no ID das entidades referenciadas:

$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
fonte
Obrigado, mas eu não acho que isso é o que eu estava procurando ... eu estava tentando conseguir outra direção, desta forma você saberia a A e olhar para o B :)
mojzis
2

err, o Módulo de Relação é o que você está procurando? Parece que definir relações entre entidades X e Y é o que você deseja fazer. ele possui seu próprio RelationQuery (um wrapper em torno do EFQ) e RelationQueryEndpoints para obter facilmente esse tipo de informação.

tenken
fonte
obrigado. infelizmente já defini algumas relações com a entidade reference, portanto, mudar para a relação seria problemático ... tentarei da próxima vez :).
Mojzis 18/04
2

Eu sei que essa é uma pergunta mais antiga, mas para as pessoas que acessam isso do Google, pensei em lançar outra abordagem aqui.

A partir da descrição acima, a instalação possui 2 tipos de entidades, A e B. Referências B com referência à entidade que estou assumindo. Portanto, se você tiver o ID de B, deverá ter um campo com o ID de A armazenado no banco de dados.

Notas de código:

  • NID original - $original_node->nidesse seria o ID de B
  • Tipo de pacote - $typeeste deve ser o tipo de A
  • A condição de campo procura apenas o campo que contém a referência
  • Para mais informações sobre como usar o EFQ, consulte este

Código

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

Você também pode configurar referências de entidade bidirecional e fazer a mesma consulta acima ao contrário. Você pode usar um módulo como o CER para garantir que essas referências sejam mantidas atualizadas. Ou configure uma regra para manter a referência atualizada, usei as duas.

burnsjeremy
fonte
Se field_NAME_OF_FIELD é de múltiplos valores, fieldCondition('field_NAME_OF_FIELD', 'target_id', $original_node->nid, '=')funciona? deve ser alterado para fieldCondition('field_NAME_OF_FIELD', 'target_id', array($original_node->nid), 'IN'). Não foi possível encontrar nada sobre como aplicar a condição no campo de referência de entidade de vários valores. alguma sugestão?
kiranking
1
Eu sei que isso é um comentário antigo, mas se você deixar o padrão '=' off EntityFieldQuery como IN, então fieldCondition ('field_NAME_OF_FIELD', 'target_id', $ original_node-> nid) realmente funcionaria nessa situação. Você provavelmente já sabe que, por agora, mas só meter mais alguém se depara com isso mais tarde :)
burnsjeremy
1

uma solução bastante dinâmica (um pouco suja também, mas eu precisava dela rapidamente) para que você não precise codificar o nome do campo de referência e ele seja automaticamente tratado com o novo campo de referência que você adicionará no futuro:

no seu módulo personalizado:

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

onde você precisa obter os nós pai, dado o nó filho:

$nodes = _MY_CUSTOM_MODULE_get_referencing_nodes($node);
Gueno
fonte