protected function ContentAccess::addNodeAccess in Search API 8
Adds a node access filter to a search query, if applicable.
Parameters
\Drupal\search_api\Query\QueryInterface $query: The query to which a node access filter should be added, if applicable.
\Drupal\Core\Session\AccountInterface $account: The user for whom the search is executed.
1 call to ContentAccess::addNodeAccess()
- ContentAccess::preprocessSearchQuery in src/
Plugin/ search_api/ processor/ ContentAccess.php - Preprocesses a search query.
File
- src/
Plugin/ search_api/ processor/ ContentAccess.php, line 266
Class
- ContentAccess
- Adds content access checks for nodes and comments.
Namespace
Drupal\search_api\Plugin\search_api\processorCode
protected function addNodeAccess(QueryInterface $query, AccountInterface $account) {
// Don't do anything if the user can access all content.
if ($account
->hasPermission('bypass node access')) {
return;
}
// Gather the affected datasources, grouped by entity type, as well as the
// unaffected ones.
$affected_datasources = [];
$unaffected_datasources = [];
foreach ($this->index
->getDatasources() as $datasource_id => $datasource) {
$entity_type = $datasource
->getEntityTypeId();
if (in_array($entity_type, [
'node',
'comment',
])) {
$affected_datasources[$entity_type][] = $datasource_id;
}
else {
$unaffected_datasources[] = $datasource_id;
}
}
// The filter structure we want looks like this:
// [belongs to other datasource]
// OR
// (
// [is enabled (or was created by the user, if applicable)]
// AND
// [grants view access to one of the user's gid/realm combinations]
// )
// If there are no "other" datasources, we don't need the nested OR,
// however, and can add the inner conditions directly to the query.
if ($unaffected_datasources) {
$outer_conditions = $query
->createConditionGroup('OR', [
'content_access',
]);
$query
->addConditionGroup($outer_conditions);
foreach ($unaffected_datasources as $datasource_id) {
$outer_conditions
->addCondition('search_api_datasource', $datasource_id);
}
$access_conditions = $query
->createConditionGroup('AND');
$outer_conditions
->addConditionGroup($access_conditions);
}
else {
$access_conditions = $query;
}
if (!$account
->hasPermission('access content')) {
unset($affected_datasources['node']);
}
if (!$account
->hasPermission('access comments')) {
unset($affected_datasources['comment']);
}
// If the user does not have the permission to see any content at all, deny
// access to all items from affected datasources.
if (!$affected_datasources) {
// If there were "other" datasources, the existing filter will already
// remove all results of node or comment datasources. Otherwise, we should
// not return any results at all.
if (!$unaffected_datasources) {
$query
->abort($this
->t('You have no access to any results in this search.'));
}
return;
}
// Collect all the required fields that need to be part of the index.
$unpublished_own = $account
->hasPermission('view own unpublished content');
$enabled_conditions = $query
->createConditionGroup('OR', [
'content_access_enabled',
]);
foreach ($affected_datasources as $entity_type => $datasources) {
foreach ($datasources as $datasource_id) {
// If this is a comment datasource, or users cannot view their own
// unpublished nodes, a simple filter on "status" is enough. Otherwise,
// it's a bit more complicated.
$status_field = $this
->findField($datasource_id, 'status', 'boolean');
if ($status_field) {
$enabled_conditions
->addCondition($status_field
->getFieldIdentifier(), TRUE);
}
if ($entity_type == 'node' && $unpublished_own) {
$author_field = $this
->findField($datasource_id, 'uid', 'integer');
if ($author_field) {
$enabled_conditions
->addCondition($author_field
->getFieldIdentifier(), $account
->id());
}
}
}
}
$access_conditions
->addConditionGroup($enabled_conditions);
// Filter by the user's node access grants.
$node_grants_field = $this
->findField(NULL, 'search_api_node_grants', 'string');
if (!$node_grants_field) {
return;
}
$node_grants_field_id = $node_grants_field
->getFieldIdentifier();
$grants_conditions = $query
->createConditionGroup('OR', [
'content_access_grants',
]);
$grants = node_access_grants('view', $account);
foreach ($grants as $realm => $gids) {
foreach ($gids as $gid) {
$grants_conditions
->addCondition($node_grants_field_id, "node_access_{$realm}:{$gid}");
}
}
// Also add items that are accessible for everyone by checking the "access
// all" pseudo grant.
$grants_conditions
->addCondition($node_grants_field_id, 'node_access__all');
$access_conditions
->addConditionGroup($grants_conditions);
}