You are here

protected function ChainGroupPermissionCalculator::doCacheableCalculation in Group 8

Same name and namespace in other branches
  1. 2.0.x src/Access/ChainGroupPermissionCalculator.php \Drupal\group\Access\ChainGroupPermissionCalculator::doCacheableCalculation()

Performs the calculation of permissions with caching support.

Parameters

string[] $cache_keys: The cache keys to store the calculation with.

string[] $persistent_cache_contexts: The cache contexts that are always used for this calculation.

string $method: The method to invoke on each calculator.

array $args: The arguments to pass to the calculator method.

Return value

\Drupal\group\Access\CalculatedGroupPermissionsInterface The calculated group permissions, potentially served from a cache.

3 calls to ChainGroupPermissionCalculator::doCacheableCalculation()
ChainGroupPermissionCalculator::calculateAnonymousPermissions in src/Access/ChainGroupPermissionCalculator.php
Calculates the anonymous group permissions.
ChainGroupPermissionCalculator::calculateMemberPermissions in src/Access/ChainGroupPermissionCalculator.php
Calculates the member group permissions for an account.
ChainGroupPermissionCalculator::calculateOutsiderPermissions in src/Access/ChainGroupPermissionCalculator.php
Calculates the outsider group permissions for an account.

File

src/Access/ChainGroupPermissionCalculator.php, line 99

Class

ChainGroupPermissionCalculator
Collects group permissions for an account.

Namespace

Drupal\group\Access

Code

protected function doCacheableCalculation(array $cache_keys, array $persistent_cache_contexts, $method, array $args = []) {
  $initial_cacheability = (new CacheableMetadata())
    ->addCacheContexts($persistent_cache_contexts);

  // Whether to switch the user account during cache storage and retrieval.
  //
  // This is necessary because permissions may be stored varying by the user
  // cache context or one of its child contexts. Because we may be calculating
  // permissions for an account other than the current user, we need to ensure
  // that the cache ID for said entry is set according to the passed in
  // account's data.
  //
  // Drupal core does not help us here because there is no way to reuse the
  // cache context logic outside of the caching layer. This means that in
  // order to generate a cache ID based on, let's say, one's permissions, we'd
  // have to copy all of the permission hash generation logic. Same goes for
  // the optimizing/folding of cache contexts.
  //
  // Instead of doing so, we simply set the current user to the passed in
  // account, calculate the cache ID and then immediately switch back. It's
  // the cleanest solution we could come up with that doesn't involve copying
  // half of core's caching layer and that still allows us to use the
  // VariationCache for accounts other than the current user.
  $switch_account = FALSE;
  foreach ($persistent_cache_contexts as $cache_context) {
    list($cache_context_root) = explode('.', $cache_context, 2);
    if ($cache_context_root === 'user') {
      $switch_account = TRUE;
      $this->accountSwitcher
        ->switchTo($args[0]);
      break;
    }
  }

  // Retrieve the permissions from the static cache if available.
  $static_cache_hit = FALSE;
  $persistent_cache_hit = FALSE;
  if ($static_cache = $this->static
    ->get($cache_keys, $initial_cacheability)) {
    $static_cache_hit = TRUE;
    $calculated_permissions = $static_cache->data;
  }
  elseif ($cache = $this->cache
    ->get($cache_keys, $initial_cacheability)) {
    $persistent_cache_hit = TRUE;
    $calculated_permissions = $cache->data;
  }
  else {
    $calculated_permissions = new RefinableCalculatedGroupPermissions();
    foreach ($this
      ->getCalculators() as $calculator) {
      $calculated_permissions = $calculated_permissions
        ->merge(call_user_func_array([
        $calculator,
        $method,
      ], $args));
    }

    // Apply a cache tag to easily flush the calculated group permissions.
    $calculated_permissions
      ->addCacheTags([
      'group_permissions',
    ]);

    // Cache the permissions as an immutable value object.
    $calculated_permissions = new CalculatedGroupPermissions($calculated_permissions);
  }

  // The persistent cache contexts are only used internally and should never
  // bubble up. We therefore only add them to the cacheable metadata provided
  // to the VariationCache, but not the actual object we're storing.
  if (!$static_cache_hit) {
    $final_cacheability = CacheableMetadata::createFromObject($calculated_permissions)
      ->addCacheContexts($persistent_cache_contexts);
    $this->static
      ->set($cache_keys, $calculated_permissions, $final_cacheability, $initial_cacheability);
    if (!$persistent_cache_hit) {
      $this->cache
        ->set($cache_keys, $calculated_permissions, $final_cacheability, $initial_cacheability);
    }
  }
  if ($switch_account) {
    $this->accountSwitcher
      ->switchBack();
  }
  return $calculated_permissions;
}