MenuLinkContentVisibilityLinkTreeManipulator.php in Custom Menu Links Visibility 2.x
File
src/MenuLinkContentVisibilityLinkTreeManipulator.php
View source
<?php
namespace Drupal\menu_link_content_visibility;
use Drupal\Component\Plugin\Exception\ContextException;
use Drupal\Component\Plugin\Exception\MissingValueContextException;
use Drupal\Core\Access\AccessManagerInterface;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
use Drupal\Core\Condition\ConditionAccessResolverTrait;
use Drupal\Core\Condition\ConditionPluginCollection;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Executable\ExecutableManagerInterface;
use Drupal\Core\Menu\DefaultMenuLinkTreeManipulators;
use Drupal\Core\Menu\MenuLinkInterface;
use Drupal\Core\Plugin\Context\ContextHandlerInterface;
use Drupal\Core\Plugin\Context\ContextRepositoryInterface;
use Drupal\Core\Plugin\ContextAwarePluginInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\menu_link_content\Plugin\Menu\MenuLinkContent;
use Symfony\Component\HttpFoundation\RequestStack;
class MenuLinkContentVisibilityLinkTreeManipulator extends DefaultMenuLinkTreeManipulators {
use ConditionAccessResolverTrait;
protected $requestStack;
protected $conditionManager;
protected $contextHandler;
protected $contextRepository;
protected $entityRepository;
public function __construct(AccessManagerInterface $access_manager, AccountInterface $account, EntityTypeManagerInterface $entity_type_manager, ExecutableManagerInterface $condition_manager, ContextHandlerInterface $context_handler, ContextRepositoryInterface $context_repository, EntityRepositoryInterface $entity_repository, RequestStack $request_stack) {
parent::__construct($access_manager, $account, $entity_type_manager);
$this->conditionManager = $condition_manager;
$this->contextHandler = $context_handler;
$this->contextRepository = $context_repository;
$this->entityRepository = $entity_repository;
$this->requestStack = $request_stack;
}
protected function menuLinkCheckAccess(MenuLinkInterface $instance) {
$access_result = parent::menuLinkCheckAccess($instance);
$is_menu_admin = $this
->getRequest()->attributes
->get('_menu_admin') ?? FALSE;
if ($is_menu_admin || !$instance instanceof MenuLinkContent) {
return $access_result;
}
$uuid = $instance
->getDerivativeId();
$entity = $this->entityRepository
->loadEntityByUuid('menu_link_content', $uuid);
$visibility = unserialize($entity
->get('visibility')->value);
if (empty($visibility)) {
return $access_result;
}
$condition_plugin_collection = new ConditionPluginCollection($this->conditionManager, $visibility);
$conditions = [];
$missing_context = FALSE;
$missing_value = FALSE;
foreach ($condition_plugin_collection as $condition_id => $condition) {
if (in_array($condition_id, [
'gtag_domain',
'gtag_language',
])) {
continue;
}
if ($condition instanceof ContextAwarePluginInterface) {
try {
$contexts = $this->contextRepository
->getRuntimeContexts(array_values($condition
->getContextMapping()));
$this->contextHandler
->applyContextMapping($condition, $contexts);
$conditions[$condition_id] = $condition;
} catch (MissingValueContextException $e) {
$missing_value = TRUE;
} catch (ContextException $e) {
$missing_context = TRUE;
}
}
}
if ($missing_context) {
$access_result = AccessResult::forbidden()
->setCacheMaxAge(0);
}
elseif ($missing_value) {
$access_result = AccessResult::forbidden();
}
elseif ($this
->resolveConditions($conditions, 'and') === FALSE) {
$reason = count($conditions) > 1 ? "One of the menu link visibility conditions ('%s') denied access." : "The menu link visibility condition '%s' denied access.";
$access_result = AccessResult::forbidden(sprintf($reason, implode("', '", array_keys($conditions))));
}
$this
->mergeCacheabilityFromConditions($access_result, $conditions);
return $access_result
->addCacheableDependency($entity);
}
protected function getRequest() {
return $this->requestStack
->getCurrentRequest();
}
protected function mergeCacheabilityFromConditions(AccessResultInterface $access_result, array $conditions) {
foreach ($conditions as $condition) {
if ($condition instanceof CacheableDependencyInterface) {
if ($access_result instanceof RefinableCacheableDependencyInterface) {
$access_result
->addCacheTags($condition
->getCacheTags());
$access_result
->addCacheContexts($condition
->getCacheContexts());
}
$access_result
->setCacheMaxAge(Cache::mergeMaxAges($access_result
->getCacheMaxAge(), $condition
->getCacheMaxAge()));
}
}
}
}