3

Have CONTENT_TYPE_NAME with field_counter that the user can set when editing a node. If a user edits and updates that field I want all other nodes that have this field set (to an equal or higher value) to increment their values by 1. I am overriding hook_entity_presave for this purpose.

As you can see in the following code I am getting all nodes of the same content type using entityQuery exluding the node that was about to be saved. For all the nodes found I am getting the entity and incrementing the field value by 1 and setting the field value and saving the node.

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

This code works with but has a problem. All nodes updated programmatically will call entity_presave again and cause an infinite loop.

I did not find a way to update field value without calling node->save() if there is a way please let me know (I know there was a way in drupal 7 field_attach_update which is deprecated as of 8.0.x I think)

Is there a way to call node->save() without causing hook_entity_presave ?

or alternativelly what checks can I do in the hook_entity_presave to know if the field was just updated programmatically and not from user edit ?

  • This post does not answer my question really. My problem is not saving the presaved node without node->save but other nodes that I get on the fly ... please read the question thoroughly. – GiorgosK Mar 8 '17 at 11:40
  • Then don't use Node::load() and instead query the field_counter DB table directly. – No Sssweat Mar 8 '17 at 11:56
  • Sounds good !! any pointer will be helpful ... – GiorgosK Mar 8 '17 at 11:59
  • There is no supported API to do this, interacting with the tables directly might break in future versions – Berdir Mar 8 '17 at 12:34
3

I think I have found a simple solution

add revision message with UNIQUE string before saving the node

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

check on the hook_entity_presave that the revision was not AUTOMATED by checking in the log for our UNIQUE string

    if ($entity->getEntityType()->id() == 'node') {
        $log = $entity->revision_log->value;
        if( substr( $log, 0, 16 ) === "AUTOMATED-UPDATE" )
            return;
        ...
  • Yes, any kind of flag that prevents a recursion should work, can be on the node, or you could also set a static/global variable. – Berdir Mar 10 '17 at 14:26
  • I figured this way I have the added benefit that anyone looking at the revision log later on will know why/how this UPDATE was done – GiorgosK Mar 10 '17 at 14:28
  • Sure that makes sense, but make sure you actually save it as a new revision then with setNewRevision(TRUE), otherwise you'll replace the existing revision log message. – Berdir Mar 10 '17 at 14:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.