arch-8.x-1.x-dev/modules/product/src/Cache/ProductAccessGrantsCacheContext.php
modules/product/src/Cache/ProductAccessGrantsCacheContext.php
<?php
namespace Drupal\arch_product\Cache;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Cache\Context\CalculatedCacheContextInterface;
use Drupal\Core\Cache\Context\UserCacheContextBase;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Session\AccountInterface;
/**
* Defines the product access view cache context service.
*
* Cache context ID: 'user.product_grants' (to vary by all operations' grants).
* Calculated cache context ID: 'user.product_grants:%operation', e.g.
* 'user.product_grants:view' (to vary by the view operation's grants).
*
* This allows for product access grants-sensitive caching when listing
* products.
*
* @see arch_product_query_product_access_alter()
* @ingroup product_access
*/
class ProductAccessGrantsCacheContext extends UserCacheContextBase implements CalculatedCacheContextInterface {
/**
* Module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* Constructs a new ProductAccessGrantsCacheContext class.
*
* @param \Drupal\Core\Session\AccountInterface $user
* The current user.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* Module handler.
*/
public function __construct(
AccountInterface $user,
ModuleHandlerInterface $module_handler,
) {
parent::__construct($user);
$this->moduleHandler = $module_handler;
}
/**
* {@inheritdoc}
*/
public static function getLabel() {
return t('Product access view grants', [], ['context' => 'arch_product']);
}
/**
* {@inheritdoc}
*/
public function getContext($operation = NULL) {
// If the current user either can bypass product access then we don't need
// to determine the exact product grants for the current user.
if ($this->user->hasPermission('bypass product access')) {
return 'all';
}
// When no specific operation is specified, check the grants for all three
// possible operations.
if ($operation === NULL) {
$result = [];
foreach (['view', 'update', 'delete'] as $op) {
$result[] = $this->checkProductGrants($op);
}
return implode('-', $result);
}
return $this->checkProductGrants($operation);
}
/**
* Checks the product grants for the given operation.
*
* @param string $operation
* The operation to check the product grants for.
*
* @return string
* The string representation of the cache context.
*/
protected function checkProductGrants($operation) {
// When checking the grants for the 'view' operation and the current user
// has a global view grant (i.e. a view grant for product ID 0) — note that
// this is automatically the case if no product access modules exist (no
// hook_product_grants() implementations) then we don't need to determine
// the exact product view grants for the current user.
if ($operation === 'view' && arch_product__product_access_view_all_products($this->user)) {
return 'view.all';
}
$grants = arch_product_access_grants($operation, $this->user);
$grants_context_parts = [];
foreach ($grants as $realm => $gids) {
$grants_context_parts[] = $realm . ':' . implode(',', $gids);
}
return $operation . '.' . implode(';', $grants_context_parts);
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata($operation = NULL) {
$cacheable_metadata = new CacheableMetadata();
if (!$this->moduleHandler->hasImplementations('product_grants')) {
return $cacheable_metadata;
}
// The product grants may change if the user is updated. (The max-age is set
// to zero below, but sites may override this cache context, and change it
// to a non-zero value. In such cases, this cache tag is needed for
// correctness.)
$cacheable_metadata->setCacheTags(['user:' . $this->user->id()]);
// If the site is using product grants, this cache context can not be
// optimized.
return $cacheable_metadata->setCacheMaxAge(0);
}
}
