Skip to content

Commit

Permalink
Added concept of path parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
aschempp committed Jul 9, 2020
1 parent de480f2 commit 629300e
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 100 deletions.
Expand Up @@ -14,7 +14,7 @@

use Contao\CoreBundle\Routing\Page\CompositionAwareInterface;
use Contao\CoreBundle\Routing\Page\PageRegistry;
use Contao\CoreBundle\Routing\Page\PageRouteProviderInterface;
use Contao\CoreBundle\Routing\Page\PageRouteEnhancerInterface;
use Contao\CoreBundle\Routing\Page\RouteConfig;
use Contao\CoreBundle\Routing\Page\UrlSuffixProviderInterface;
use Contao\FrontendIndex;
Expand Down Expand Up @@ -65,12 +65,12 @@ protected function registerPages(ContainerBuilder $container): void
$type = $this->getPageType($definition, $attributes);
unset($attributes['type']);

$routeProvider = null;
$routeEnhancer = null;
$compositionAware = null;
$class = $definition->getClass();

if (is_a($definition->getClass(), PageRouteProviderInterface::class, true)) {
$routeProvider = $reference;
if (is_a($definition->getClass(), PageRouteEnhancerInterface::class, true)) {
$routeEnhancer = $reference;
}

if (is_a($class, CompositionAwareInterface::class, true)) {
Expand All @@ -82,7 +82,7 @@ protected function registerPages(ContainerBuilder $container): void
}

$config = $this->getRouteConfig($reference, $definition, $attributes);
$registry->addMethodCall('add', [$type, $config, $routeProvider, $compositionAware]);
$registry->addMethodCall('add', [$type, $config, $routeEnhancer, $compositionAware]);

$definition->addTag(self::TAG_NAME, $attributes);
}
Expand All @@ -97,6 +97,7 @@ protected function getRouteConfig(Reference $reference, Definition $definition,
return new Definition(
RouteConfig::class,
[
$attributes['parameters'] ?? null,
$attributes['requirements'] ?? [],
$attributes['options'] ?? [],
$defaults,
Expand Down
8 changes: 8 additions & 0 deletions core-bundle/src/Resources/contao/dca/tl_page.php
Expand Up @@ -233,6 +233,14 @@
'eval' => array('rgxp'=>'folderalias', 'doNotCopy'=>true, 'maxlength'=>255, 'tl_class'=>'w50 clr'),
'sql' => "varchar(255) BINARY NOT NULL default ''"
),
'parameters' => array
(
'exclude' => true,
'search' => true,
'inputType' => 'text',
'eval' => array('nospace'=>true, 'maxlength'=>255, 'tl_class'=>'w50'),
'sql' => "varchar(255) NOT NULL default ''"
),
'type' => array
(
'exclude' => true,
Expand Down
1 change: 1 addition & 0 deletions core-bundle/src/Resources/contao/models/PageModel.php
Expand Up @@ -25,6 +25,7 @@
* @property integer $tstamp
* @property string $title
* @property string $alias
* @property string $parameters
* @property string $type
* @property string $pageTitle
* @property string $language
Expand Down
2 changes: 1 addition & 1 deletion core-bundle/src/Routing/Content/ArticleRouteProvider.php
Expand Up @@ -42,7 +42,7 @@ public function getRouteForContent($article): Route
throw new RouteNotFoundException(sprintf('Page ID %s for article ID %s not found', $article->pid, $article->id));
}

return $this->routeFactory->createRouteWithParameters($page, '/articles/'.($article->alias ?: $article->id), $article);
return $this->routeFactory->createRoute($page, '/articles/'.($article->alias ?: $article->id), $article);
}

public function supportsContent($content): bool
Expand Down
29 changes: 13 additions & 16 deletions core-bundle/src/Routing/Page/PageRegistry.php
Expand Up @@ -23,9 +23,9 @@ class PageRegistry
private $routeConfigs = [];

/**
* @var array<PageRouteProviderInterface>
* @var array<PageRouteEnhancerInterface>
*/
private $routeProviders = [];
private $routeEnhancers = [];

/**
* @var array<CompositionAwareInterface>
Expand All @@ -42,21 +42,18 @@ public function getRouteConfig(string $type): ?RouteConfig
return $this->routeConfigs[$type] ?? null;
}

public function hasRouteProvider(PageModel $pageModel): bool
public function enhancePageRoute(PageRoute $route): Route
{
return isset($this->routeConfigs[$pageModel->type]);
}
$type = $route->getPageModel()->type;

public function getRouteForPage(PageModel $pageModel, $content = null): Route
{
if (!isset($this->routeProviders[$pageModel->type])) {
throw new \InvalidArgumentException(sprintf('Page of type "%s" does not have a route provider.', $pageModel->type));
if (!isset($this->routeEnhancers[$type])) {
return $route;
}

/** @var PageRouteProviderInterface $provider */
$provider = $this->routeProviders[$pageModel->type];
/** @var PageRouteEnhancerInterface $enhancer */
$enhancer = $this->routeEnhancers[$type];

return $provider->getRouteForPage($pageModel, $content);
return $enhancer->enhancePageRoute($route);
}

public function supportsContentComposition(PageModel $pageModel): bool
Expand All @@ -68,13 +65,13 @@ public function supportsContentComposition(PageModel $pageModel): bool
return $this->compositionAware[$pageModel->type]->supportsContentComposition($pageModel);
}

public function add(string $type, RouteConfig $config, PageRouteProviderInterface $routeProvider = null, CompositionAwareInterface $compositionAware = null): self
public function add(string $type, RouteConfig $config, PageRouteEnhancerInterface $routeEnhancer = null, CompositionAwareInterface $compositionAware = null): self
{
// Override existing pages with the same identifier
$this->routeConfigs[$type] = $config;

if (null !== $routeProvider) {
$this->routeProviders[$type] = $routeProvider;
if (null !== $routeEnhancer) {
$this->routeEnhancers[$type] = $routeEnhancer;
}

if (null !== $compositionAware) {
Expand All @@ -88,7 +85,7 @@ public function remove(string $type): self
{
unset(
$this->routeConfigs[$type],
$this->routeProviders[$type],
$this->routeEnhancers[$type],
$this->compositionAware[$type]
);

Expand Down
4 changes: 2 additions & 2 deletions core-bundle/src/Routing/Page/PageRoute.php
Expand Up @@ -43,7 +43,7 @@ class PageRoute extends Route
*/
private $content;

public function __construct(PageModel $pageModel, array $defaults = [], array $requirements = [], array $options = [], array $methods = [])
public function __construct(PageModel $pageModel, string $pathParameters = '', array $defaults = [], array $requirements = [], array $options = [], $methods = [])
{
$pageModel->loadDetails();

Expand All @@ -65,7 +65,7 @@ public function __construct(PageModel $pageModel, array $defaults = [], array $r
}

parent::__construct(
'/'.($pageModel->alias ?: $pageModel->id),
'/'.($pageModel->alias ?: $pageModel->id).$pathParameters,
$defaults,
$requirements,
$options,
Expand Down
34 changes: 34 additions & 0 deletions core-bundle/src/Routing/Page/PageRouteEnhancerInterface.php
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

/*
* This file is part of Contao.
*
* (c) Leo Feyer
*
* @license LGPL-3.0-or-later
*/

namespace Contao\CoreBundle\Routing\Page;

use Symfony\Component\Routing\Route;

/**
* A page route enhancer can adjust the default route for a page.
* The route enhancer knows what a route for a page looks like, e.g. if
* a particular route has a different URL suffix than configured in the root page.
*/
interface PageRouteEnhancerInterface
{
/**
* While matching URLs, Contao generates alias candidates and looks for matching page models.
* Based on these page's "type" property, the route factory creates a default route and asks to enhance
* the route, as only the route provider knows about dynamic requirements or defaults.
*
* To generate URLs for a page, the respective route enhancer needs to return a route based on
* the page configuration. If content is available, it can be used to enhance route defaults,
* so the route can be generated even if no parameters have been passed to the router generate() method.
*/
public function enhancePageRoute(PageRoute $route): Route;
}
65 changes: 25 additions & 40 deletions core-bundle/src/Routing/Page/PageRouteFactory.php
Expand Up @@ -13,7 +13,6 @@
namespace Contao\CoreBundle\Routing\Page;

use Contao\PageModel;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
use Symfony\Component\Routing\Route;

class PageRouteFactory
Expand All @@ -28,49 +27,35 @@ public function __construct(PageRegistry $pageRegistry)
$this->pageRegistry = $pageRegistry;
}

public function createRoute(PageModel $pageModel, $content = null): Route
{
if (null !== ($route = $this->getRouteFromProvider($pageModel, $content))) {
return $route;
}

return $this->getRouteFromConfig($pageModel, $content);
}

public function createRouteWithParameters(PageModel $pageModel, string $parameters = '', $content = null): Route
{
if (null !== ($route = $this->getRouteFromProvider($pageModel, $content))) {
return $route;
}

$route = $this->getRouteFromConfig($pageModel, $content);
$route->setPath(sprintf('/%s{parameters}', $pageModel->alias ?: $pageModel->id));
$route->setDefault('parameters', $parameters);
$route->setRequirement('parameters', $pageModel->requireItem ? '/.+' : '(/.+)?');

return $route;
}

private function getRouteFromProvider(PageModel $pageModel, $content = null): ?Route
{
try {
if ($this->pageRegistry->hasRouteProvider($pageModel)) {
return $this->pageRegistry->getRouteForPage($pageModel, $content);
}
} catch (RouteNotFoundException $e) {
return null;
}

return null;
}

private function getRouteFromConfig(PageModel $pageModel, $content = null): PageRoute
/**
* Creates a route for page in Contao.
*
* If $pathParameters are not configured (is null), the route will accept any parameters after
* the page alias (e.g. "en/page-alias/foo/bar.html").
*
* In any other case, $pathParameters will be appended to the path, to support custom parameters.
* The value of $pathParameter can be configured in the back end through tl_page.parameters.
*
* A route enhancer might change or replace the route for a specific page.
*/
public function createRoute(PageModel $pageModel, string $defaultParameters = '', $content = null): Route
{
$config = $this->pageRegistry->getRouteConfig($pageModel->type) ?: new RouteConfig();
$pathParameters = $config->getPathParameters();
$defaults = $config->getDefault();
$requirements = $config->getRequirements();

if (null === $pathParameters) {
$pathParameters = '{parameters}';
$defaults['parameters'] = $defaultParameters;
$requirements['parameters'] = $pageModel->requireItem ? '/.+' : '(/.+)?';
} elseif ('' !== $pathParameters && '' !== $pageModel->parameters) {
$pathParameters = $pageModel->parameters;
}

$route = new PageRoute($pageModel, $config->getDefault(), $config->getRequirements(), $config->getOptions(), $config->getMethods());
$route = new PageRoute($pageModel, $pathParameters, $defaults, $requirements, $config->getOptions(), $config->getMethods());
$route->setContent($content);

return $route;
return $this->pageRegistry->enhancePageRoute($route);
}
}
35 changes: 0 additions & 35 deletions core-bundle/src/Routing/Page/PageRouteProviderInterface.php

This file was deleted.

13 changes: 12 additions & 1 deletion core-bundle/src/Routing/Page/RouteConfig.php
Expand Up @@ -14,6 +14,11 @@

final class RouteConfig
{
/**
* @var string|null
*/
private $pathParameters;

/**
* @var array
*/
Expand All @@ -34,14 +39,20 @@ final class RouteConfig
*/
private $methods;

public function __construct(array $requirements = [], array $options = [], array $default = [], array $methods = [])
public function __construct(string $pathParameters = null, array $requirements = [], array $options = [], array $default = [], array $methods = [])
{
$this->pathParameters = $pathParameters;
$this->requirements = $requirements;
$this->options = $options;
$this->default = $default;
$this->methods = $methods;
}

public function getPathParameters(): ?string
{
return $this->pathParameters;
}

public function getRequirements(): array
{
return $this->requirements;
Expand Down
1 change: 1 addition & 0 deletions core-bundle/src/ServiceAnnotation/Page.php
Expand Up @@ -24,6 +24,7 @@
* @Target({"CLASS", "METHOD"})
* @Attributes({
* @Attribute("value", type = "string"),
* @Attribute("parameters", type = "string"),
* @Attribute("requirements", type = "array"),
* @Attribute("options", type = "array"),
* @Attribute("defaults", type = "array"),
Expand Down

0 comments on commit 629300e

Please sign in to comment.