function NodeGrantDatabaseStorage::access

Same name and namespace in other branches
  1. 9 core/modules/node/src/NodeGrantDatabaseStorage.php \Drupal\node\NodeGrantDatabaseStorage::access()
  2. 8.9.x core/modules/node/src/NodeGrantDatabaseStorage.php \Drupal\node\NodeGrantDatabaseStorage::access()
  3. 10 core/modules/node/src/NodeGrantDatabaseStorage.php \Drupal\node\NodeGrantDatabaseStorage::access()

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
        ->hasImplementations('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. New translations
    // do not yet have a langcode and must check the fallback node record.
    $nids = $query->andConditionGroup()
        ->condition('nid', $node->id());
    if (!$node->isNewTranslation()) {
        $nids->condition('langcode', $node->language()
            ->getId());
    }
    else {
        $nids->condition('fallback', 1);
    }
    // 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());
    }
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.