You are here

public function AccessControl::entityAccess in Group 2.0.x

Checks access to an operation on the entity.

Parameters

\Drupal\Core\Entity\EntityInterface $entity: The entity for which to check access.

string $operation: The operation access should be checked for. Usually one of "view", "update" or "delete".

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

bool $return_as_object: (optional) Defaults to FALSE.

Return value

bool|\Drupal\Core\Access\AccessResultInterface The access result. Returns a boolean if $return_as_object is FALSE (this is the default) and otherwise an AccessResultInterface object. When a boolean is returned, the result of AccessInterface::isAllowed() is returned, i.e. TRUE means access is explicitly allowed, FALSE means access is either explicitly forbidden or "no opinion".

Overrides AccessControlTrait::entityAccess

File

src/Plugin/Group/RelationHandlerDefault/AccessControl.php, line 83

Class

AccessControl
Provides access control for group relation plugins.

Namespace

Drupal\group\Plugin\Group\RelationHandlerDefault

Code

public function entityAccess(EntityInterface $entity, $operation, AccountInterface $account, $return_as_object = FALSE) {

  /** @var \Drupal\group\Entity\Storage\GroupContentStorageInterface $storage */
  $storage = $this
    ->entityTypeManager()
    ->getStorage('group_content');
  $group_contents = $storage
    ->loadByEntity($entity);

  // Filter out the content that does not use this plugin.
  foreach ($group_contents as $id => $group_content) {

    // @todo Shows the need for a plugin ID base field.
    $plugin_id = $group_content
      ->getRelationPlugin()
      ->getPluginId();
    if ($plugin_id !== $this->pluginId) {
      unset($group_contents[$id]);
    }
  }

  // If this plugin is not being used by the entity, we have nothing to say.
  if (empty($group_contents)) {
    return AccessResult::neutral();
  }

  // We only check unpublished vs published for "view" right now. If we ever
  // start supporting other operations, we need to remove the "view" check.
  $check_published = $operation === 'view' && $entity
    ->getEntityType()
    ->entityClassImplements(EntityPublishedInterface::class);

  // Check if the account is the owner and an owner permission is supported.
  $is_owner = FALSE;
  if ($entity
    ->getEntityType()
    ->entityClassImplements(EntityOwnerInterface::class)) {
    $is_owner = $entity
      ->getOwnerId() === $account
      ->id();
  }

  // Add in the admin permission and filter out the unsupported permissions.
  $permissions = [
    $this->permissionProvider
      ->getAdminPermission(),
  ];
  if (!$check_published || $entity
    ->isPublished()) {
    $permissions[] = $this->permissionProvider
      ->getPermission($operation, 'entity', 'any');
    $own_permission = $this->permissionProvider
      ->getPermission($operation, 'entity', 'own');
    if ($is_owner) {
      $permissions[] = $own_permission;
    }
  }
  elseif ($check_published && !$entity
    ->isPublished()) {
    $permissions[] = $this->permissionProvider
      ->getPermission("{$operation} unpublished", 'entity', 'any');
    $own_permission = $this->permissionProvider
      ->getPermission("{$operation} unpublished", 'entity', 'own');
    if ($is_owner) {
      $permissions[] = $own_permission;
    }
  }
  $permissions = array_filter($permissions);
  foreach ($group_contents as $group_content) {
    $result = GroupAccessResult::allowedIfHasGroupPermissions($group_content
      ->getGroup(), $account, $permissions, 'OR');
    if ($result
      ->isAllowed()) {
      break;
    }
  }

  // If we did not allow access, we need to explicitly forbid access to avoid
  // other modules from granting access where Group promised the entity would
  // be inaccessible.
  if (!$result
    ->isAllowed()) {
    $result = AccessResult::forbidden()
      ->addCacheContexts([
      'user.group_permissions',
    ]);
  }

  // If there was an owner permission to check, the result needs to vary per
  // user. We also need to add the entity as a dependency because if its owner
  // changes, someone might suddenly gain or lose access.
  if (!empty($own_permission)) {

    // @todo Not necessary if admin, could boost performance here.
    $result
      ->cachePerUser();
  }

  // If we needed to check for the owner permission or published access, we
  // need to add the entity as a dependency because the owner or publication
  // status might change.
  if (!empty($own_permission) || $check_published) {

    // @todo Not necessary if admin, could boost performance here.
    $result
      ->addCacheableDependency($entity);
  }
  return $return_as_object ? $result : $result
    ->isAllowed();
}