Chris@0: get('context.handler'), Chris@0: $container->get('context.repository') Chris@0: ); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Constructs the block access control handler instance Chris@0: * Chris@0: * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type Chris@0: * The entity type definition. Chris@0: * @param \Drupal\Core\Plugin\Context\ContextHandlerInterface $context_handler Chris@0: * The ContextHandler for applying contexts to conditions properly. Chris@0: * @param \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository Chris@0: * The lazy context repository service. Chris@0: */ Chris@0: public function __construct(EntityTypeInterface $entity_type, ContextHandlerInterface $context_handler, ContextRepositoryInterface $context_repository) { Chris@0: parent::__construct($entity_type); Chris@0: $this->contextHandler = $context_handler; Chris@0: $this->contextRepository = $context_repository; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) { Chris@0: /** @var \Drupal\block\BlockInterface $entity */ Chris@0: if ($operation != 'view') { Chris@0: return parent::checkAccess($entity, $operation, $account); Chris@0: } Chris@0: Chris@0: // Don't grant access to disabled blocks. Chris@0: if (!$entity->status()) { Chris@0: return AccessResult::forbidden()->addCacheableDependency($entity); Chris@0: } Chris@0: else { Chris@0: $conditions = []; Chris@0: $missing_context = FALSE; Chris@17: $missing_value = FALSE; Chris@0: foreach ($entity->getVisibilityConditions() as $condition_id => $condition) { Chris@0: if ($condition instanceof ContextAwarePluginInterface) { Chris@0: try { Chris@0: $contexts = $this->contextRepository->getRuntimeContexts(array_values($condition->getContextMapping())); Chris@0: $this->contextHandler->applyContextMapping($condition, $contexts); Chris@0: } Chris@17: catch (MissingValueContextException $e) { Chris@17: $missing_value = TRUE; Chris@17: } Chris@0: catch (ContextException $e) { Chris@0: $missing_context = TRUE; Chris@0: } Chris@0: } Chris@0: $conditions[$condition_id] = $condition; Chris@0: } Chris@0: Chris@0: if ($missing_context) { Chris@0: // If any context is missing then we might be missing cacheable Chris@0: // metadata, and don't know based on what conditions the block is Chris@17: // accessible or not. Make sure the result cannot be cached. Chris@0: $access = AccessResult::forbidden()->setCacheMaxAge(0); Chris@0: } Chris@17: elseif ($missing_value) { Chris@17: // The contexts exist but have no value. Deny access without Chris@17: // disabling caching. For example the node type condition will have a Chris@17: // missing context on any non-node route like the frontpage. Chris@17: $access = AccessResult::forbidden(); Chris@17: } Chris@0: elseif ($this->resolveConditions($conditions, 'and') !== FALSE) { Chris@0: // Delegate to the plugin. Chris@0: $block_plugin = $entity->getPlugin(); Chris@0: try { Chris@0: if ($block_plugin instanceof ContextAwarePluginInterface) { Chris@0: $contexts = $this->contextRepository->getRuntimeContexts(array_values($block_plugin->getContextMapping())); Chris@0: $this->contextHandler->applyContextMapping($block_plugin, $contexts); Chris@0: } Chris@0: $access = $block_plugin->access($account, TRUE); Chris@0: } Chris@17: catch (MissingValueContextException $e) { Chris@17: // The contexts exist but have no value. Deny access without Chris@17: // disabling caching. Chris@17: $access = AccessResult::forbidden(); Chris@17: } Chris@0: catch (ContextException $e) { Chris@17: // If any context is missing then we might be missing cacheable Chris@17: // metadata, and don't know based on what conditions the block is Chris@17: // accessible or not. Make sure the result cannot be cached. Chris@0: $access = AccessResult::forbidden()->setCacheMaxAge(0); Chris@0: } Chris@0: } Chris@0: else { Chris@17: $reason = count($conditions) > 1 Chris@17: ? "One of the block visibility conditions ('%s') denied access." Chris@17: : "The block visibility condition '%s' denied access."; Chris@17: $access = AccessResult::forbidden(sprintf($reason, implode("', '", array_keys($conditions)))); Chris@0: } Chris@0: Chris@0: $this->mergeCacheabilityFromConditions($access, $conditions); Chris@0: Chris@0: // Ensure that access is evaluated again when the block changes. Chris@0: return $access->addCacheableDependency($entity); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Merges cacheable metadata from conditions onto the access result object. Chris@0: * Chris@0: * @param \Drupal\Core\Access\AccessResult $access Chris@0: * The access result object. Chris@0: * @param \Drupal\Core\Condition\ConditionInterface[] $conditions Chris@0: * List of visibility conditions. Chris@0: */ Chris@0: protected function mergeCacheabilityFromConditions(AccessResult $access, array $conditions) { Chris@0: foreach ($conditions as $condition) { Chris@0: if ($condition instanceof CacheableDependencyInterface) { Chris@0: $access->addCacheTags($condition->getCacheTags()); Chris@0: $access->addCacheContexts($condition->getCacheContexts()); Chris@0: $access->setCacheMaxAge(Cache::mergeMaxAges($access->getCacheMaxAge(), $condition->getCacheMaxAge())); Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: }