layout_builder_ipe-1.0.x-dev/src/EventSubscriber/IpeRouteParamContext.php
src/EventSubscriber/IpeRouteParamContext.php
<?php
namespace Drupal\layout_builder_ipe\EventSubscriber;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\ParamConverter\ParamConverterManagerInterface;
use Drupal\Core\Plugin\Context\Context;
use Drupal\Core\Routing\RouteObjectInterface;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\layout_builder_ipe\LayoutBuilderIpeService;
use Drupal\page_manager\Context\ContextDefinitionFactory;
use Drupal\page_manager\Event\PageManagerContextEvent;
use Drupal\page_manager\Event\PageManagerEvents;
use Drupal\page_manager\PageInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Sets values from the route parameters as a context.
*/
class IpeRouteParamContext implements EventSubscriberInterface {
use StringTranslationTrait;
/**
* The layout builder ipe service.
*
* @var \Drupal\layout_builder_ipe\LayoutBuilderIpeService
*/
protected $layoutBuilderIpe;
/**
* The route provider.
*
* @var \Drupal\Core\Routing\RouteProviderInterface
*/
protected $routeProvider;
/**
* The request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* The paramconverter manager.
*
* @var \Drupal\Core\ParamConverter\ParamConverterManagerInterface
*/
protected $paramConverterManager;
/**
* Constructs a new CurrentUserContext.
*
* @param \Drupal\layout_builder_ipe\LayoutBuilderIpeService $layout_builder_ipe
* The IPE service.
* @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
* The route provider.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
* @param \Drupal\Core\ParamConverter\ParamConverterManagerInterface $paramconverter_manager
* The param converter manager.
*/
public function __construct(LayoutBuilderIpeService $layout_builder_ipe, RouteProviderInterface $route_provider, RequestStack $request_stack, ParamConverterManagerInterface $paramconverter_manager) {
$this->layoutBuilderIpe = $layout_builder_ipe;
$this->routeProvider = $route_provider;
$this->requestStack = $request_stack;
$this->paramConverterManager = $paramconverter_manager;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events = [];
if (class_exists('Drupal\page_manager\Event\PageManagerEvents')) {
$events[PageManagerEvents::PAGE_CONTEXT][] = ['onPageContext', -100];
}
return $events;
}
/**
* Adds in the current contexts based on the original path of a page.
*
* @param \Drupal\page_manager\Event\PageManagerContextEvent $event
* The page entity context event.
*/
public function onPageContext(PageManagerContextEvent $event) {
$page = $event->getPage();
$route = $this->getRouteForEditedPage();
$value_map = $this->getValueMap($page);
if (!$route || empty($value_map)) {
return;
}
// Create a value map that maps named placeholders to values taken from the
// given current path.
if ($route && $route_contexts = $route->getOption('parameters')) {
foreach ($route_contexts as $route_context_name => $route_context) {
// Skip this parameter.
if ($route_context_name == '_page_manager_page_variant' || $route_context_name == '_page_manager_page') {
continue;
}
$parameter = $page->getParameter($route_context_name);
$context_name = !empty($parameter['label']) ? $parameter['label'] : $this->t('{@name} from route', ['@name' => $route_context_name]);
if (array_key_exists($route_context_name, $value_map)) {
// Extract the raw value form the path and apply param converters to
// upcast the values.
$raw_value = $value_map[$route_context_name];
$definition = $parameter;
$definition[$route_context_name] = $raw_value;
$definition[RouteObjectInterface::ROUTE_OBJECT] = $route;
$defaults = $this->paramConverterManager->convert($definition);
$value = $defaults[$route_context_name];
}
else {
$value = NULL;
}
$cacheability = new CacheableMetadata();
$cacheability->setCacheContexts(['route']);
$context = new Context(ContextDefinitionFactory::create($route_context['type'])->setLabel($context_name)->setRequired(FALSE), $value);
$context->addCacheableDependency($cacheability);
$page->addContext($route_context_name, $context);
}
}
}
/**
* Get the route for the edited page.
*
* @return \Symfony\Component\Routing\Route|null
* The route if found.
*/
private function getRouteForEditedPage() {
// Get the route based on the given current path.
$current_path = $this->layoutBuilderIpe->getCurrentEditPath();
if (!$current_path) {
return NULL;
}
$routes = $this->routeProvider->getRoutesByPattern($current_path);
$this->paramConverterManager->setRouteParameterConverters($routes);
if (!$routes->count()) {
return NULL;
}
$routes_all = $routes->all();
return reset($routes_all);
}
/**
* Get a map between path segments and arguments.
*
* @param \Drupal\page_manager\PageInterface $page
* The page manager page.
*
* @return array
* A map between parts of the pages path and actual values of the current
* (edited) path. This contains a map between named placeholders and raw
* path arguments.
*/
private function getValueMap(PageInterface $page) {
$current_path = $this->layoutBuilderIpe->getCurrentEditPath();
if (!$current_path) {
return [];
}
$page_arguments = array_map(function ($item) {
return str_replace('{', '', str_replace('}', '', $item));
}, explode('/', ltrim($page->getPath(), '/')));
$path_arguments = explode('/', ltrim($current_path, '/'));
if (count($page_arguments) != count($path_arguments)) {
// If the number of arguments that the page expects is different than the
// number of arguments we can provide, this is undefined, so we bail out.
return [];
}
return array_combine($page_arguments, $path_arguments);
}
}
