page_manager-8.x-4.0-beta6/src/Routing/PageManagerRoutes.php
src/Routing/PageManagerRoutes.php
<?php
namespace Drupal\page_manager\Routing;
use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Routing\RouteCompiler;
use Drupal\Core\Routing\RouteSubscriberBase;
use Drupal\Core\Routing\RoutingEvents;
use Drupal\page_manager\PageInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
/**
* Provides routes for page entities.
*/
class PageManagerRoutes extends RouteSubscriberBase {
/**
* The entity storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $entityStorage;
/**
* The cache tags invalidator.
*
* @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface
*/
protected $cacheTagsInvalidator;
/**
* Constructs a new PageManagerRoutes.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $cache_tags_invalidator
* The cache tags invalidator.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, CacheTagsInvalidatorInterface $cache_tags_invalidator) {
$this->entityStorage = $entity_type_manager->getStorage('page');
$this->cacheTagsInvalidator = $cache_tags_invalidator;
}
/**
* {@inheritdoc}
*/
protected function alterRoutes(RouteCollection $collection) {
foreach ($this->entityStorage->loadMultiple() as $entity_id => $entity) {
/** @var \Drupal\page_manager\PageInterface $entity */
// If the page is disabled skip making a route for it.
if (!$entity->status() || !$entity->getVariants()) {
continue;
}
$defaults = [];
$parameters = [];
$requirements = [];
$route_name = "page_manager.page_view_$entity_id";
if ($overridden_route_name = $this->findOverriddenRouteName($entity, $collection)) {
$base_route_name = $overridden_route_name;
$collection_route = $collection->get($overridden_route_name);
// Add the name of the overridden route for use during filtering.
$defaults['_overridden_route_name'] = $overridden_route_name;
$path = $collection_route->getPath();
$parameters = $collection_route->getOption('parameters') ?: [];
$requirements = $collection_route->getRequirements();
}
else {
$base_route_name = $route_name;
$path = $entity->getPath();
}
// Add in configured parameters.
foreach ($entity->getParameters() as $parameter_name => $parameter) {
if (!empty($parameter['type'])) {
$parameters[$parameter_name]['type'] = $parameter['type'];
if (!empty($parameter['optional'])) {
$parameters[$parameter_name]['optional'] = TRUE;
}
}
}
// When adding multiple variants, the variant ID is added to the route
// name. In order to convey the base route name for this set of variants,
// add it as a parameter.
$defaults['_base_route_name'] = $base_route_name;
$defaults['_entity_view'] = '_page_manager_page_variant';
$defaults['_title'] = $entity->label();
$defaults['_page_manager_page'] = $entity->id();
$parameters['_page_manager_page_variant']['type'] = 'entity:page_variant';
$parameters['_page_manager_page']['type'] = 'entity:page';
$requirements['_page_access'] = '_page_manager_page.view';
foreach ($entity->getVariants() as $variant_id => $variant) {
// Construct and add a new route.
$route = new Route(
$path,
$defaults + [
'_page_manager_page_variant' => $variant_id,
'_page_manager_page_variant_weight' => $variant->getWeight(),
],
$requirements,
[
'parameters' => $parameters,
'_admin_route' => $entity->usesAdminTheme(),
]
);
foreach ($parameters as $key => $parameter) {
if (!empty($parameter['optional'])) {
$route->addDefaults([$key => NULL]);
}
}
$collection->add($route_name . '_' . $variant_id, $route);
}
// Invalidate any page with the same base route name. See
// \Drupal\page_manager\EventSubscriber\RouteNameResponseSubscriber.
$this->cacheTagsInvalidator->invalidateTags(["page_manager_route_name:$base_route_name"]);
}
}
/**
* Finds the overridden route name.
*
* @param \Drupal\page_manager\PageInterface $entity
* The page entity.
* @param \Symfony\Component\Routing\RouteCollection $collection
* The route collection.
*
* @return string|null
* Either the route name if this is overriding an existing path, or NULL.
*/
protected function findOverriddenRouteName(PageInterface $entity, RouteCollection $collection) {
// Get the stored page path.
$path = $entity->getPath();
// Loop through all existing routes to see if this is overriding a route.
foreach ($collection->all() as $name => $collection_route) {
// Find all paths which match the path of the current display.
$route_path = $collection_route->getPath();
$route_path_outline = RouteCompiler::getPatternOutline($route_path);
// Match either the path or the outline, e.g., '/foo/{foo}' or '/foo/%'.
// The route must be a GET route and must not specify a format.
if (($path === $route_path || $path === $route_path_outline) &&
(!$collection_route->getMethods() || in_array('GET', $collection_route->getMethods())) &&
!$collection_route->hasRequirement('_format')) {
// Return the overridden route name.
return $name;
}
}
return NULL;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array {
// Run after EntityRouteAlterSubscriber.
$events[RoutingEvents::ALTER][] = ['onAlterRoutes', -160];
return $events;
}
}
