You are here

public function NodeGrantDatabaseStorage::access in Drupal 9

Same name and namespace in other branches
  1. 8 core/modules/node/src/NodeGrantDatabaseStorage.php \Drupal\node\NodeGrantDatabaseStorage::access()

Determines access to nodes based on node grants.

Parameters

\Drupal\node\NodeInterface $node: The entity for which to check 'create' access.

string $operation: The entity operation. Usually one of 'view', 'edit', 'create' or 'delete'.

\Drupal\Core\Session\AccountInterface $account: The user for which to check access.

Return value

\Drupal\Core\Access\AccessResultInterface The access result, either allowed or neutral. If there are no node grants, the default grant defined by writeDefault() is applied.

Overrides NodeGrantDatabaseStorageInterface::access

See also

hook_node_grants()

hook_node_access_records()

\Drupal\node\NodeGrantDatabaseStorageInterface::writeDefault()

File

core/modules/node/src/NodeGrantDatabaseStorage.php, line 61

Class

NodeGrantDatabaseStorage
Defines a storage handler class that handles the node grants system.

Namespace

Drupal\node

Code

public function access(NodeInterface $node, $operation, AccountInterface $account) {

  // Grants only support these operations.
  if (!in_array($operation, [
    'view',
    'update',
    'delete',
  ])) {
    return AccessResult::neutral();
  }

  // If no module implements the hook or the node does not have an id there is
  // no point in querying the database for access grants.
  if (!$this->moduleHandler
    ->getImplementations('node_grants') || !$node
    ->id()) {

    // Return the equivalent of the default grant, defined by
    // self::writeDefault().
    if ($operation === 'view') {
      return AccessResult::allowedIf($node
        ->isPublished());
    }
    else {
      return AccessResult::neutral();
    }
  }

  // Check the database for potential access grants.
  $query = $this->database
    ->select('node_access');
  $query
    ->addExpression('1');

  // Only interested for granting in the current operation.
  $query
    ->condition('grant_' . $operation, 1, '>=');

  // Check for grants for this node and the correct langcode.
  $nids = $query
    ->andConditionGroup()
    ->condition('nid', $node
    ->id())
    ->condition('langcode', $node
    ->language()
    ->getId());

  // If the node is published, also take the default grant into account. The
  // default is saved with a node ID of 0.
  $status = $node
    ->isPublished();
  if ($status) {
    $nids = $query
      ->orConditionGroup()
      ->condition($nids)
      ->condition('nid', 0);
  }
  $query
    ->condition($nids);
  $query
    ->range(0, 1);
  $grants = $this
    ->buildGrantsQueryCondition(node_access_grants($operation, $account));
  if (count($grants) > 0) {
    $query
      ->condition($grants);
  }

  // Only the 'view' node grant can currently be cached; the others currently
  // don't have any cacheability metadata. Hopefully, we can add that in the
  // future, which would allow this access check result to be cacheable in all
  // cases. For now, this must remain marked as uncacheable, even when it is
  // theoretically cacheable, because we don't have the necessary metadata to
  // know it for a fact.
  $set_cacheability = function (AccessResult $access_result) use ($operation) {
    $access_result
      ->addCacheContexts([
      'user.node_grants:' . $operation,
    ]);
    if ($operation !== 'view') {
      $access_result
        ->setCacheMaxAge(0);
    }
    return $access_result;
  };
  if ($query
    ->execute()
    ->fetchField()) {
    return $set_cacheability(AccessResult::allowed());
  }
  else {
    return $set_cacheability(AccessResult::neutral());
  }
}