2015-08-17 17:00:26 -07:00
< ? php
/**
* @ file
* Contains \Drupal\block\BlockAccessControlHandler .
*/
namespace Drupal\block ;
use Drupal\Component\Plugin\Exception\ContextException ;
use Drupal\Core\Access\AccessResult ;
2015-08-27 12:03:05 -07:00
use Drupal\Core\Cache\Cache ;
use Drupal\Core\Cache\CacheableDependencyInterface ;
2015-08-17 17:00:26 -07:00
use Drupal\Core\Condition\ConditionAccessResolverTrait ;
use Drupal\Core\Entity\EntityAccessControlHandler ;
use Drupal\Core\Entity\EntityHandlerInterface ;
use Drupal\Core\Entity\EntityInterface ;
use Drupal\Core\Entity\EntityTypeInterface ;
use Drupal\Core\Executable\ExecutableManagerInterface ;
use Drupal\Core\Plugin\Context\ContextHandlerInterface ;
2015-08-27 12:03:05 -07:00
use Drupal\Core\Plugin\Context\ContextRepositoryInterface ;
2015-08-17 17:00:26 -07:00
use Drupal\Core\Plugin\ContextAwarePluginInterface ;
use Drupal\Core\Session\AccountInterface ;
use Symfony\Component\DependencyInjection\ContainerInterface ;
/**
* Defines the access control handler for the block entity type .
*
* @ see \Drupal\block\Entity\Block
*/
class BlockAccessControlHandler extends EntityAccessControlHandler implements EntityHandlerInterface {
use ConditionAccessResolverTrait ;
/**
* The condition plugin manager .
*
* @ var \Drupal\Core\Executable\ExecutableManagerInterface
*/
protected $manager ;
/**
* The plugin context handler .
*
* @ var \Drupal\Core\Plugin\Context\ContextHandlerInterface
*/
protected $contextHandler ;
2015-08-27 12:03:05 -07:00
/**
* The context manager service .
*
* @ var \Drupal\Core\Plugin\Context\ContextRepositoryInterface
*/
protected $contextRepository ;
2015-08-17 17:00:26 -07:00
/**
* { @ inheritdoc }
*/
public static function createInstance ( ContainerInterface $container , EntityTypeInterface $entity_type ) {
return new static (
$entity_type ,
$container -> get ( 'plugin.manager.condition' ),
2015-08-27 12:03:05 -07:00
$container -> get ( 'context.handler' ),
$container -> get ( 'context.repository' )
2015-08-17 17:00:26 -07:00
);
}
/**
* Constructs the block access control handler instance
*
* @ param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type definition .
* @ param \Drupal\Core\Executable\ExecutableManagerInterface $manager
* The ConditionManager for checking visibility of blocks .
* @ param \Drupal\Core\Plugin\Context\ContextHandlerInterface $context_handler
* The ContextHandler for applying contexts to conditions properly .
2015-08-27 12:03:05 -07:00
* @ param \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository
* The lazy context repository service .
2015-08-17 17:00:26 -07:00
*/
2015-08-27 12:03:05 -07:00
public function __construct ( EntityTypeInterface $entity_type , ExecutableManagerInterface $manager , ContextHandlerInterface $context_handler , ContextRepositoryInterface $context_repository ) {
2015-08-17 17:00:26 -07:00
parent :: __construct ( $entity_type );
$this -> manager = $manager ;
$this -> contextHandler = $context_handler ;
2015-08-27 12:03:05 -07:00
$this -> contextRepository = $context_repository ;
2015-08-17 17:00:26 -07:00
}
/**
* { @ inheritdoc }
*/
protected function checkAccess ( EntityInterface $entity , $operation , $langcode , AccountInterface $account ) {
/** @var \Drupal\block\BlockInterface $entity */
if ( $operation != 'view' ) {
return parent :: checkAccess ( $entity , $operation , $langcode , $account );
}
// Don't grant access to disabled blocks.
if ( ! $entity -> status ()) {
return AccessResult :: forbidden () -> cacheUntilEntityChanges ( $entity );
}
else {
$conditions = [];
2015-08-27 12:03:05 -07:00
$missing_context = FALSE ;
2015-08-17 17:00:26 -07:00
foreach ( $entity -> getVisibilityConditions () as $condition_id => $condition ) {
if ( $condition instanceof ContextAwarePluginInterface ) {
try {
2015-08-27 12:03:05 -07:00
$contexts = $this -> contextRepository -> getRuntimeContexts ( array_values ( $condition -> getContextMapping ()));
2015-08-17 17:00:26 -07:00
$this -> contextHandler -> applyContextMapping ( $condition , $contexts );
}
catch ( ContextException $e ) {
2015-08-27 12:03:05 -07:00
$missing_context = TRUE ;
2015-08-17 17:00:26 -07:00
}
}
$conditions [ $condition_id ] = $condition ;
}
2015-08-27 12:03:05 -07:00
if ( $missing_context ) {
// If any context is missing then we might be missing cacheable
// metadata, and don't know based on what conditions the block is
// accessible or not. For example, blocks that have a node type
// condition will have a missing context on any non-node route like the
// frontpage.
// @todo Avoid setting max-age 0 for some or all cases, for example by
// treating available contexts without value differently in
// https://www.drupal.org/node/2521956.
$access = AccessResult :: forbidden () -> setCacheMaxAge ( 0 );
}
elseif ( $this -> resolveConditions ( $conditions , 'and' ) !== FALSE ) {
2015-08-17 17:00:26 -07:00
// Delegate to the plugin.
$access = $entity -> getPlugin () -> access ( $account , TRUE );
}
else {
$access = AccessResult :: forbidden ();
}
2015-08-27 12:03:05 -07:00
$this -> mergeCacheabilityFromConditions ( $access , $conditions );
// Ensure that access is evaluated again when the block changes.
return $access -> cacheUntilEntityChanges ( $entity );
}
}
/**
* Merges cacheable metadata from conditions onto the access result object .
*
* @ param \Drupal\Core\Access\AccessResult $access
* The access result object .
* @ param \Drupal\Core\Condition\ConditionInterface [] $conditions
* List of visibility conditions .
*/
protected function mergeCacheabilityFromConditions ( AccessResult $access , array $conditions ) {
foreach ( $conditions as $condition ) {
if ( $condition instanceof CacheableDependencyInterface ) {
$access -> addCacheTags ( $condition -> getCacheTags ());
$access -> addCacheContexts ( $condition -> getCacheContexts ());
$access -> setCacheMaxAge ( Cache :: mergeMaxAges ( $access -> getCacheMaxAge (), $condition -> getCacheMaxAge ()));
}
2015-08-17 17:00:26 -07:00
}
}
}