Add a relationship to a View programmatically with Drupal 8

A mountain panorama

To make queries and build listing pages on Drupal 8, or any other content to collect, we have EntityQuery, the API Database (see Make a SQL query on multiple tables with Drupal 8) or the Views module which provides us an extremely powerful requester and graphical interface. Each of these methods has its advantages and disadvantages and may be more appropriate in certain situations (complexity of the request, etc.).

One of the advantages of the EntityQuery is that it is easy to make complex queries under many dynamic conditions. However, Views requests can also be dynamically altered, although this type of alteration may be slightly more complex due to the power of Views.

A particularly useful use case can be to add a relationship to a View dynamically (the equivalent of $query->join()). Let's take an example right away, with a view based on the Node entity (base table: node), for which we want to add a relationship based on a field_user field referencing a user, and then be able to alter the query based on the Users entities referenced by this field.

To do this, we will implement hook_views_query_alter() which allows us to alter the request of a View before it is executed.

/**
 * Implements hook_views_query_alter().
 */
function my_module_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
  if ($view->id() == 'view_machine_name') {
    $current_user = $view->getUser();
    $condition = _my_module_custom_condition($current_user);
    if ($condition) {
      $definition = [
        'table' => 'node__field_user',
        'field' => 'entity_id',
        'left_table' => 'node',
        'left_field' => 'id',
      ];
      $join = \Drupal::service('plugin.manager.views.join')
        ->createInstance('standard', $definition);
      $query->addRelationship('my_relation', $join, 'node');

      $currentUserId = $current_user->id();
      $query->addWhereExpression('AND',
        'my_relation.field_user_target_id = :currentUid',
        ['currentUid' => $currentUserId]);
    }
  }
}

/**
 * Helper function to test a condition.
 *
 * @param \Drupal\Core\Session\AccountInterface $current_user
 *   The current user.
 *
 * @return bool
 *   TRUE if condition passed.
 */
function _my_module_custom_condition(AccountInterface $current_user) {
  $result = TRUE;
  // Some stuff.
  return $result;
}

In this example, according to any business condition, we can instantiate a new $join relationship, add this relationship as "my_relation" to the query, then add a condition to our query based on this new added relationship.

Not being a big user of Views except for specific use cases, I recently discovered the use of this type of Plugin used by Views to create and manage relationships to a view. A type of plugin that makes it possible to facilitate complex alterations of a view in a relatively clear way. With the help of a Drupal developer, we can use views designed by site builder profiles for these relatively complex use cases, and managed and maintained by users with different profiles.

All tastes are in nature, and it takes everything to make a world.

 

Commentaires

Soumis par Romain Trenet (non vérifié) le 08/01/2021 à 18:12 - Permalien

Merci Fabrice ! Je ne trouvais pas la solution

Ajouter un commentaire