_node_query_node_access_alter

  1. drupal
    1. 8
    2. 7
Versions
7 – 8 _node_query_node_access_alter($query, $type)

Helper for node access functions.

Parameters

$query The query to add conditions to.

$type Either 'node' or 'entity' depending on what sort of query it is. See node_query_node_access_alter() and node_query_entity_field_access_alter() for more.

Related topics

Code

modules/node/node.module, line 3149

<?php
function _node_query_node_access_alter($query, $type) {
  global $user;

  // Read meta-data from query, if provided.
  if (!$account = $query->getMetaData('account')) {
    $account = $user;
  }
  if (!$op = $query->getMetaData('op')) {
    $op = 'view';
  }

  // If $account can bypass node access, or there are no node access modules,
  // or the operation is 'view' and the $acount has a global view grant (i.e.,
  // a view grant for node ID 0), we don't need to alter the query.
  if (user_access('bypass node access', $account)) {
    return;
  }
  if (!count(module_implements('node_grants'))) {
    return;
  }
  if ($op == 'view' && node_access_view_all_nodes($account)) {
    return;
  }

  $tables = $query->getTables();
  $base_table = $query->getMetaData('base_table');
  // If no base table is specified explicitly, search for one.
  if (!$base_table) {
    $fallback = '';
    foreach ($tables as $alias => $table_info) {
      if (!($table_info instanceof SelectQueryInterface)) {
        $table = $table_info['table'];
        // If the node table is in the query, it wins immediately.
        if ($table == 'node') {
          $base_table = $table;
          break;
        }
        // Check whether the table has a foreign key to node.nid. If it does,
        // do not run this check again as we found a base table and only node
        // can triumph that.
        if (!$base_table) {
          // The schema is cached.
          $schema = drupal_get_schema($table);
          if (isset($schema['fields']['nid'])) {
            if (isset($schema['foreign keys'])) {
              foreach ($schema['foreign keys'] as $relation) {
                if ($relation['table'] === 'node' && $relation['columns'] === array('nid' => 'nid')) {
                  $base_table = $table;
                }
              }
            }
            else {
              // At least it's a nid. A table with a field called nid is very
              // very likely to be a node.nid in a node access query.
              $fallback = $table;
            }
          }
        }
      }
    }
    // If there is nothing else, use the fallback.
    if (!$base_table) {
      if ($fallback) {
        watchdog('security', 'Your node listing query is using @fallback as a base table in a query tagged for node access. This might not be secure and might not even work. Specify foreign keys in your schema to node.nid ', array('@fallback' => $fallback), WATCHDOG_WARNING);
        $base_table = $fallback;
      }
      else {
        throw new Exception(t('Query tagged for node access but there is no nid. Add foreign keys to node.nid in schema to fix.'));
      }
    }
  }

  // Prevent duplicate records.
  $query->distinct();

  // Find all instances of the base table being joined -- could appear
  // more than once in the query, and could be aliased. Join each one to
  // the node_access table.

  $grants = node_access_grants($op, $account);
  if ($type == 'entity') {
    // The original query looked something like:
    // @code
//  SELECT nid FROM sometable s
//  INNER JOIN node_access na ON na.nid = s.nid
//  WHERE ($node_access_conditions)
    // @endcode
    //
    // Our query will look like:
    // @code
//  SELECT entity_type, entity_id
//  FROM field_data_something s
//  LEFT JOIN node_access na ON s.entity_id = na.nid
//  WHERE (entity_type = 'node' AND $node_access_conditions) OR (entity_type <> 'node')
    // @endcode
    //
    // So instead of directly adding to the query object, we need to collect
    // in a separate db_and() object and then at the end add it to the query.
    $entity_conditions = db_and();
  }
  foreach ($tables as $nalias => $tableinfo) {
    $table = $tableinfo['table'];
    if (!($table instanceof SelectQueryInterface) && $table == $base_table) {

      // The node_access table has the access grants for any given node so JOIN
      // it to the table containing the nid which can be either the node
      // table or a field value table.
      if ($type == 'node') {
        $access_alias = $query->join('node_access', 'na', '%alias.nid = ' . $nalias . '.nid');
      }
      else {
        $access_alias = $query->leftJoin('node_access', 'na', '%alias.nid = ' . $nalias . '.entity_id');
        $base_alias = $nalias;
      }

      $grant_conditions = db_or();
      // If any grant exists for the specified user, then user has access
      // to the node for the specified operation.
      foreach ($grants as $realm => $gids) {
        foreach ($gids as $gid) {
          $grant_conditions->condition(db_and()
            ->condition($access_alias . '.gid', $gid)
            ->condition($access_alias . '.realm', $realm)
          );
        }
      }

      $count = count($grant_conditions->conditions());
      if ($type == 'node') {
        if ($count) {
          $query->condition($grant_conditions);
        }
        $query->condition($access_alias . '.grant_' . $op, 1, '>=');
      }
      else {
        if ($count) {
          $entity_conditions->condition($grant_conditions);
        }
        $entity_conditions->condition($access_alias . '.grant_' . $op, 1, '>=');
      }
    }
  }

  if ($type == 'entity' && count($entity_conditions->conditions())) {
    // All the node access conditions are only for field values belonging to
    // nodes.
    $entity_conditions->condition("$base_alias.entity_type", 'node');
    $or = db_or();
    $or->condition($entity_conditions);
    // If the field value belongs to a non-node entity type then this function
    // does not do anything with it.
    $or->condition("$base_alias.entity_type", 'node', '<>');
    // Add the compiled set of rules to the query.
    $query->condition($or);
  }
}
?>