Display output in terminal from hook_update_N.

Every now and then we find ourselves needing to make a big update to entities within our sites. We could write code and run this using our browser using the Batch API, however, if it's just a one-off, then using the hook_update_N would suffice. 

When I write hook updates, I like to see what's going on, what part of the code is being executed, where it's stuck, and so on.

Step 1:

In your MODULE_MACHINE_NAME.install file, you'd want to write a hook update like

/**
 * Update nodes with new title.
 */
function learn_drupal_deploy_update_9001() {
  
}

The doc block above the function must contain a brief description of what the hook update is about. 

This description appears in the terminal.

Update database

Notice how the function ends with a 1. That's because this is the first hook update for this module. If you were to add another hook update, it would be `learn_drupal_deploy_9002'.

Step 2:

Now let's write code to load all nodes of type 'page' within the website and change its title.

/**
 * Update nodes with new title.
 */
function learn_drupal_deploy_update_9001() {
  $page_nodes = \Drupal::entityTypeManager()->getStorage('node')->loadByProperties(['type' => 'page']);
  if ($page_nodes) {
    foreach ($page_nodes as $page) {
      $existing_label = $page->label();
      $page->set('label', 'LearnDrupal - ' . $existing_label);
      $page->save();
    }
  }
}

If we run `drush updb -y` in our terminal, this code would be executed, but we'd have no way of seeing any output in our console. 

Step 3:

Let's add some logic to this and display meaningful messages.

/**
 * Update nodes with new title.
 */
function learn_drupal_deploy_update_9001() {
  $page_nodes = \Drupal::entityTypeManager()->getStorage('node')->loadByProperties(['type' => 'page']);
  if ($page_nodes) {
    foreach ($page_nodes as $page) {
      // First check that the field exists and is not empty and it has value of 1.
      if ($page->hasField('field_update_title') && !$page->get('field_update_title')->isEmpty() && $page->get('field_update_title')->getString() == 1) {
        $current_title = $page->label();
        $new_title = 'LearnDrupal - ' . $current_title;
        $page->set('label', $new_title);
        $page->save();

        \Drupal::messenger()
          ->addMessage(t('The node with nid %nid has had its title updated from %current_title to %new_title', [
            '%nid' => $page->id(),
            '%current_title' => $current_title,
            '%new_title' => $new_title,
          ]));
      }
      else {
        \Drupal::messenger()
          ->addMessage(t('The node with nid %nid was not updated!', [
            '%nid' => $page->id(),
          ]));
      }
    }
  }
}

We check to see if the node has the field, `field_update_title` (which is a boolean field), and then we check if the field is not empty and the field has actually been checked.

If we meet the above criteria, we then update the nodes, save the nodes, then display a message.

If we don't meet the above criteria we do nothing but display a message.

Step 4:

Open up your terminal and run the following command, `drush updb -y`, and you will have an output similar to mine.

updata database output drupal

As you can see, we can see nodes that were update and nodes that did not update.

updated drupal nodes

Complete!