Problem/Motivation
I am able to customize group's access control by implementing a handler over the service 'group.relation_handler.access_control.group_node' (in AccessControlInterface::entityAccess()).
With this, I can successfully "bypass" the original group/gnode access control; for instance, I need that a specific group node is visible for anonymous user only when its custom field 'field_visibility == public'.
When using Views, I would need that the same rules appears. But unfortunately, it doesn't; indeed, it appears that the 'group.relation_handler.access_control.group_node' service AccessControlInterface::entityAccess() method is not triggered in that context, thus failing to apply the needed custom acccess control.
Steps to reproduce
Implement a custom 'group.relation_handler.access_control.group_node' handler (this was build using information found into the following issue https://www.drupal.org/project/group/issues/3389950):
<?php
class UgridGroupServiceProvider extends ServiceProviderBase {
public function alter(ContainerBuilder $container) {
$service_id = 'group.relation_handler.access_control.group_node';
if ($container->has($service_id)) {
$container->getDefinition($service_id)->setClass(VisibilityFieldAccessControl::class);
}
}
}
<?php
namespace Drupal\ugrid_group\Plugin\Group\RelationHandler;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Session\AccountInterface;
use Drupal\group\Plugin\Group\RelationHandler\AccessControlInterface;
use Drupal\group\Plugin\Group\RelationHandler\AccessControlTrait;
use Drupal\Core\Entity\EntityInterface;
/**
* Control group node access control using a field visibility.
*/
class VisibilityFieldAccessControl implements AccessControlInterface {
use AccessControlTrait;
/**
* @param \Drupal\group\Plugin\Group\RelationHandler\AccessControlInterface $parent
* The parent access control handler.
*/
public function __construct(AccessControlInterface $parent) {
$this->parent = $parent;
}
/**
* {@inheritdoc}
*/
public function entityAccess(EntityInterface $entity, $operation, AccountInterface $account, $return_as_object = FALSE) {
$access = $this->parent->entityAccess($entity, $operation, $account, TRUE);
// We need at least the following condition supplement the parent access control...
if (in_array($operation, ['view', 'view all revisions']) && $entity->hasField('field_visibility') && $entity->isPublished()) {
if ($entity->field_visibility->value == 'public') {
$access = AccessResult::allowed();
}
elseif ($entity->field_visibility->value == 'community' && $account->isAuthenticated()) {
$access = AccessResult::allowed();
}
else {
// Access control should be left as the parent process defines...
}
$access->addCacheableDependency($entity);
}
return $return_as_object ? $access : $access->isAllowed();
}
}
Proposed resolution
I'm unsure why the 'group.relation_handler.access_control.group_node()' service AccessControlInterface::entityAccess() method is not triggered in Views context?
But, one solution I'm imagining is that the current group 'EntityQueryAlter' which is applied via 'group_query_views_entity_query_alter' could be implemented (moved) into a custom views filter plugin which then would allow to be combined with other standard filters using for instance an 'OR' operator against the 'field_visibility == public'.
Remaining tasks
If an experienced fellow could tell me if I'm missing something or could confirm/infirm that the custom views filter plugin direction is not that wrong I might try in that direction...
Comments
Comment #2
drikc commentedComment #3
drikc commentedComment #4
drikc commentedI could find a solution which is a bit of tinkering by using the Views Combine module. Indeed, it requires to multiply views displays with their own filtering to allow to build the required SQL union and result but at least I could make it...
Other directions I took that fails so far:
- Move group's `EntityQueryAlter` sql transformation into a views filter plugin fails because it appears that views query and query at hook_query_TAG_alter levels are very different beasts
- Adding a dis-junction over `EntityQueryAlter` in a hook_query_TAG_alter is something I couldn't figure how to do
- hook_node_access_records/hook_node_grants doesn't work since it appears that hook_node_grants is also ignored by views at what I could notice
Note, the drupal guru-level to tackle that in a more cleanly fashion is above mine apparently...