You are here

function hooks_example_node_view in Examples for Developers 3.x

Same name and namespace in other branches
  1. 8 hooks_example/hooks_example.module \hooks_example_node_view()

Implements hook_ENTITY_TYPE_view().

Some hook names include additional tokens that need to be replaced when implementing the hook. These hooks are dynamic in that when they are being invoked a portion of their name is replaced with a dynamic value. This is indicated by placing the token words in all caps. This pattern is often used in situations where you want to allow modules to generically act on all instances of a thing, or to act on only a specific subset.

There are lots of different entity types in Drupal. Node, user, file, etc. Using hook_entity_view() a module can act on a any entity that is being viewed, regardless of type. If we wanted to count views of all entities, regardless of type this would be a good choice. This variant is also useful if you want to provide administrators with a form where they can choose from a list of entity types which ones they want to count views for. The logic in the generic hook implementation could then take that into account and act on only a select set of entity types.

If however, you know you only ever want to act on viewing of a node entity you can instead implement hook_ENTITY_TYPE_view(). Where ENTITY_TYPE is a token that can be replaced with any valid entity type name.

See also

hook_entity_view()

hook_ENTITY_TYPE_view()

Related topics

File

modules/hooks_example/hooks_example.module, line 108
Examples demonstrating how to implement and invoke hooks.

Code

function hooks_example_node_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {

  // This example hook implementation keeps track of the number of times a user
  // has viewed a specific node during their current session. Then displays that
  // information for them when they view a node.
  //
  // In addition, a hook is invoked that allows other modules to react when the
  // page view count is updated.
  //
  // Retrieve the active session from the current request object.
  $session = \Drupal::request()
    ->getSession();
  $current_counts = $session
    ->get('hooks_example.view_counts', []);
  if (!isset($current_counts[$entity
    ->id()])) {

    // If this is the first time they've viewed the page we need to start the
    // counter.
    $current_counts[$entity
      ->id()] = 1;
  }
  else {

    // If they have already viewed this page just increment the existing
    // counter.
    $current_counts[$entity
      ->id()]++;
  }

  // Save the updated values.
  $session
    ->set('hooks_example.view_counts', $current_counts);

  // Invoke a hook to alert other modules that the count was updated.
  //
  // Hooks are invoked via the `module_handler` service. Which is an instance of
  // \Drupal\Core\Extension\ModuleHandlerInterface.
  //
  // Hooks can be invoked in a few different ways:
  // - All at once using ModuleHandlerInterface::invokeAll() to call all
  //   implementations of the specified hook provided by any enabled module.
  // - One at a time using ModuleHandlerInterface::invoke() to call only the
  //   the specified module's implementation of a hook.
  // - Using ModuleHandlerInterface::alter() to pass alterable variables to
  //   hook_TYPE_alter() implementations for all enabled modules. This method
  //   should be used for instances where the calling module has assembled data
  //   and would like to give other modules an opportunity to alter that data
  //   before it's used. A common pattern is to use invokeAll() to first gather
  //   input from other modules, the immediately afterwards call alter() to give
  //   modules the opportunity to alter the aggregate data.
  $module_handler = \Drupal::moduleHandler();

  // Calling \Drupal\Core\Extension\ModuleHandlerInterface::invokeAll() will
  // call implementations of the hook in question for all enabled modules. The
  // method takes two arguments. The name of the hook to invoke, and an optional
  // array of arguments to pass to any functions implementing the hook.
  //
  // Hook names need to be unique. So when defining a new hook in your module it
  // is customary to prefix the hook name with the short name of your module
  // followed by the descriptive name of the hook itself. Because hooks names
  // are also PHP function names they should contain only lowercase alphanumeric
  // characters and underscores.
  //
  // The hook name parameter should have the "hook_" prefix removed. So if you
  // want to invoke hook_mymodule_do_something() the value used here would be
  // 'mymodule_do_something'.
  //
  // Hook implementations can optionally return a value, depending on the hook
  // definition. If they do, the invokeAll() method aggregates the responses
  // from all hooks in an array and returns the array.
  //
  // In this example we're invoking hook_hooks_example_count_incremented() and
  // passing all implementations the current view count for the node, and the
  // node object itself.
  $module_handler
    ->invokeAll('hooks_example_count_incremented', [
    $current_counts[$entity
      ->id()],
    $entity,
  ]);

  // Display the current number of pages the user has viewed along with the
  // node's content.
  $build['view_count'] = [
    '#markup' => '<p>' . t('You have viewed this node @total times this session.', [
      '@total' => $current_counts[$entity
        ->id()],
    ]) . '</p>',
    // In order for this example to work we disable caching for the content of
    // this node completely. This ensures that our hook is called every time the
    // node is viewed instead of using a cached version of the page for
    // subsequent requests.
    '#cache' => [
      'max-age' => 0,
    ],
  ];
}