Exclusion de champs vides (Null) lors de l'utilisation de la condition de requête EntityFieldQuery

31

Est-il possible de sélectionner toutes les entités dont le champ xyz est vide?

J'ai essayé quelque chose comme ça:

->fieldCondition('field_name', 'value', NULL, 'IS NOT NULL');

Cependant, cela ne semble pas fonctionner.

Des idées?

David Barratt
la source

Réponses:

19

Si vous regardez sur la page de documentation fieldCondition , vous verrez l'avertissement suivant:

Notez que les entités avec des valeurs de champ vides seront exclues des résultats EntityFieldQuery lors de l'utilisation de cette méthode.

Vérifier si un champ existe ou non a été ajouté à entityFieldQuery dans Drupal 8, mais ne sera malheureusement pas rétroporté vers Drupal 7 .

Il existe différentes méthodes pour y parvenir:

  1. En utilisant une balise et hook_query_TAG_alter comme mentionné par @Clive, voir le commentaire 4 sur le problème Drupal pour un exemple;
  2. Recherchez d'abord toutes les entrées non NULL, puis interrogez toutes les entrées à l'exception des précédentes, comme décrit dans la réponse de @ seddonym et dans le commentaire 5 sur le problème Drupal ;
  3. Vous pouvez écrire votre requête en utilisant SelectQuery plutôt que EntityfieldQuery en tant que tel:

_

$q = db_select('node', 'n');
$q->fields('n', array('type'))
  ->condition('n.type', 'my_node_type', '=')
  ->addJoin('LEFT', 'field_data_field_my_field', 'f', 'f.entity_id = n.nid');
$q->isNull('f.value');
$r = $q->execute();
Alice Heaton
la source
15

Vous pouvez utiliser != NULL, mais vous ne pouvez pas utiliser = NULLpour une raison quelconque.

Ceci est ma solution de contournement.

  //Get all the entities that DO have values
  $query = new EntityFieldQuery();
  $query->entityCondition('entity_type', 'MY_TYPE')
    ->fieldCondition('field_MY_FIELD', 'value', 'NULL', '!=');
  $result = $query->execute();

  if (is_array(@$result['registration'])) {
    //Now get all the other entities, that aren't in the list you just retrieved
    $query = new EntityFieldQuery();
    $query->entityCondition('entity_type', 'MY_TYPE')
      ->entityCondition('entity_id', array_keys($result['MY_TYPE']), 'NOT IN');
    $result_two = $query->execute(); 
  }
seddonym
la source
10

Selon la documentation, vous pouvez utiliser null et isnull; il a juste une façon spécifique de l'écrire.

$query = new EntityFieldQuery();
$query->entityCondition('entity_type', 'node')
  ->entityCondition('bundle', 'article')
  ->propertyCondition('status', 1)
  ->fieldCondition('field_news_types', 'value', 'spotlight', '=')
  ->fieldCondition('field_photo', 'fid', 'NULL', '!=')
  ->fieldCondition('field_faculty_tag', 'tid', $value)
  ->fieldCondition('field_news_publishdate', 'value', $year. '%', 'like')
  ->range(0, 10)
  ->addMetaData('account', user_load(1)); // run the query as user 1

$result = $query->execute();

if (isset($result['node'])) {
  $news_items_nids = array_keys($result['node']);
  $news_items = entity_load('node', $news_items_nids);
}
giorgio79
la source
9

La réponse courte est que, directement, non, vous ne pouvez pas (voir EntityFieldQuery ne prend pas en charge isNull ou isNotNull ). Si je me souviens bien, c'est un effet secondaire du fait que EntityFieldQueryn'utilise que INNER JOINs pour joindre les tables.

Il existe cependant une solution de contournement, qui implique l'utilisation hook_query_TAG_alter()et l'ajout d'une balise à votre EntityFieldQuery, il y a un exemple dans le dernier commentaire sur la page que j'ai liée ci-dessus.

Clive
la source
5

Dans Drupal 7, veuillez vérifier la solution de contournement suivante proposée ici :

Enregistrez la balise pour modifier l'instance de requête:

<?php
/**
 * Implements hook_query_TAG_alter()
 */
function MYMODULE_query_node_is_not_tagged_alter(QueryAlterableInterface $query) {
  $query->leftJoin('field_data_field_tags', 'o', 'node.nid = o.entity_id AND o.entity_type = :entity_type');
  $query->isNull('o.field_tags_tid');
}
?>

Obs.: Cette modification de balise de requête ne fonctionne que pour le type d'entité "nœud". Ne confondez pas les "field_tags" liés au vocabulaire "Tags", il peut en être d'autres comme les "Catégories".

Obtenez tous les nœuds qui n'ont pas encore été balisés en utilisant EntityFieldQuery, regardez la méthode addTag ():

<?php
$query = new EntityFieldQuery();
$query->entityCondition('entity_type', 'node')
  ->entityCondition('bundle', 'news')
  ->addTag('node_is_not_tagged')
  ->propertyCondition('status', 1);
$result = $query->execute();
?>

Autre exemple:

  $result = $query
    ->entityCondition('entity_type', 'node')
    ->propertyCondition('type', 'my_content_type')
    ->fieldCondition('field_mine_one', 'value', '', '<>')
    ->fieldCondition('field_mine_two', 'value', '', '<>')
    ->addTag('my_custom_tag')
    ->deleted(FALSE)
    ->propertyOrderBy('changed', 'DESC')
    ->range(0, $my_range_value)
    ->execute();

Ensuite, j'ai mis en œuvre en hook_query_TAG_altertirant parti du fait que je n'ai my_custom_tagdéfini que:

/**
 * Implements hook_query_TAG_alter()
 */
function MYMODULE_query_TAG_alter(QueryAlterableInterface $query) {
  $query->leftJoin('field_data_field_other', 'o', 'node.nid = o.entity_id');
  $query->isNull('o.field_other_value');
}

Un autre exemple:

<?php
  //Get all the entities that DO have values
  $query = new EntityFieldQuery();
  $query->entityCondition('entity_type', 'MY_TYPE')
    ->fieldCondition('field_MY_FIELD', 'value', 'NULL', '!=');
  $result = $query->execute();

  if (is_array(@$result['registration'])) {
    //Now get all the other entities, that aren't in the list you just retrieved 
    $query = new EntityFieldQuery();
    $query->entityCondition('entity_type', 'MY_TYPE')
      ->entityCondition('entity_id', array_keys($result['MY_TYPE']), 'NOT IN');
    $result_two = $query->execute();  
  }
?>

Exemple plus complet ci-dessous qui charge un tas de nœuds sur une tâche cron qui vide les références de termes de taxonomie et applique certaines modifications:

/**
 * Implements hook_cron().
 */
function MYMODULE_cron() {
  $query = new EntityFieldQuery();
  $query
    ->entityCondition('entity_type', 'node')
    ->entityCondition('bundle', 'property')
    ->propertyOrderBy('changed', 'DESC')
    ->addTag('type_is_null')
    ->range(0,50); // Maximum of 50.
  $result = $query->execute();

  if (!empty($result['node'])) {
    $nids = array_keys($result['node']);
    $nodes = node_load_multiple($nids);

    foreach ($nodes as $node) {
      // do_some_stuff($node);
    }
  }
}

/**
 * Implements hook_query_TAG_alter()
 */
function MYMODULE_query_type_is_null_alter(QueryAlterableInterface $query) {
  $query->leftJoin('field_data_field_foo', 'f', 'node.nid = f.entity_id AND f.entity_type = :entity_type');
  $query->isNull('f.field_foo_tid'); // Check name by SQL: DESC field_data_field_foo

  $query->leftJoin('field_data_field_bar', 'b', 'node.nid = b.entity_id AND b.entity_type = :entity_type');
  $query->isNull('b.field_bar_tid'); // Check name by SQL: DESC field_data_field_bar
}
Kenorb
la source
3

Vous devez mettre Null entre guillemets.

->fieldCondition('field_name', 'value', 'NULL', '!=');
Sharique
la source
2

Corrigez-moi si j'ai tort, s'il-vous plait. Il semble qu'il faut simplement

$query->fieldCondition('field_name');

pour exclure tous les nœuds avec un field_namechamp vide o_O

Testé sur Drupal version >= 7.43.

leymannx
la source
Cela fonctionne réellement. Les réponses les plus positives ont été erronées pour moi (ne pouvaient pas obtenir une erreur, mais cassaient tout).
Joren