web-dev-qa-db-fra.com

changer la valeur du champ de nœud sans nœud-> enregistrer ou sans provoquer la boucle infinie hook_entity_presave

Ayez CONTENT_TYPE_NAME Avec field_counter Que l'utilisateur peut définir lors de la modification d'un nœud. Si un utilisateur modifie et met à jour ce champ, je veux que tous les autres nœuds qui ont ce champ défini (à une valeur égale ou supérieure) incrémentent leurs valeurs de 1. Je remplace hook_entity_presave À cet effet.

Comme vous pouvez le voir dans le code suivant, j'obtiens tous les nœuds du même type de contenu en utilisant entityQuery à l'exclusion du nœud qui était sur le point d'être enregistré. Pour tous les nœuds trouvés, j'obtiens l'entité et j'incrémente la valeur de champ de 1, je définis la valeur de champ et j'enregistre le nœud.

    function MY_MODULE_entity_presave(EntityInterface $entity){ 
      if ($entity->getEntityType()->id() == 'node') {
        $changed_field = array(
            "field_counter",
        );
        $nid = $entity->id();
        foreach($changed_field as $field ){
          $value = $entity->{$field}->value;
          if(isset($value) && $value !=""){
            MY_MODULE_change_field_value($field,$value,$nid);
            //...
          }
        }
      }
    }

    function MY_MODULE_change_field_value($field,$value,$xeid){  
      $query = \Drupal::entityQuery('node')
        ->condition('status', 1)
        ->condition('type', 'CONTENT_TYPE_NAME')
        ->condition('nid', $xeid,"<>")
        ->condition($field,$value,">=");

      $nids = $query->execute();

      foreach ($nids as $nid) {
        $node = \Drupal\node\Entity\Node::load($nid);
        //or
        //$node = \Drupal::entityTypeManager()->getStorage("node")->load($nid);

        $old_value = $node->{$field}->value;
        $old_value++;
        $node->{$field}->value = $old_value;

        $node->save();    
      }
    }

Ce code fonctionne avec mais a un problème. Tous les nœuds mis à jour par programmation appellent à nouveau entity_presave et provoquent une boucle infinie.

Je n'ai pas trouvé de moyen de mettre à jour la valeur du champ sans appeler node->save() s'il y a un moyen, veuillez me le faire savoir (je sais qu'il y avait un moyen de drupal 7 field_attach_update Qui est obsolète à partir de 8.0.x je pense)

Existe-t-il un moyen d'appeler node->save() sans provoquer hook_entity_presave?

ou alternativelly quelles vérifications puis-je faire dans le hook_entity_presave pour savoir si le champ vient d'être mis à jour par programme et non depuis la modification par l'utilisateur?

4
GiorgosK

Je pense avoir trouvé une solution simple

ajouter un message de révision avec une chaîne UNIQUE avant d'enregistrer le nœud

    //...
    $node->setNewRevision(TRUE);
    $node->revision_log->value = "AUTOMATED-UPDATE ". $field." incremented to ".$old_value ;
    $node->save();

vérifier le hook_entity_presave que la révision n'a pas été AUTOMATISÉE en vérifiant dans le journal notre chaîne UNIQUE

    if ($entity->getEntityType()->id() == 'node') {
        $log = $entity->revision_log->value;
        if( substr( $log, 0, 16 ) === "AUTOMATED-UPDATE" )
            return;
        ...
3
GiorgosK