8000 [FrameworkBundle][Routing] added XML and YAML loaders to handle templ… · symfony/symfony@5eb4e50 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5eb4e50

Browse files
committed
[FrameworkBundle][Routing] added XML and YAML loaders to handle template and redirect controllers
1 parent 332fa65 commit 5eb4e50

File tree

10 files changed

+536
-5
lines changed

10 files changed

+536
-5
lines changed

src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515

1616
<service id="routing.resolver" class="Symfony\Component\Config\Loader\LoaderResolver" />
1717

18-
<service id="routing.loader.xml" class="Symfony\Component\Routing\Loader\XmlFileLoader">
18+
<service id="routing.loader.xml" class="Symfony\Bundle\FrameworkBundle\Routing\Loader\XmlFileLoader">
1919
<tag name="routing.loader" />
2020
<argument type="service" id="file_locator" />
2121
</service>
2222

23-
<service id="routing.loader.yml" class="Symfony\Component\Routing\Loader\YamlFileLoader">
23+
<service id="routing.loader.yml" class="Symfony\Bundle\FrameworkBundle\Routing\Loader\YamlFileLoader">
2424
<tag name="routing.loader" />
2525
<argument type="service" id="file_locator" />
2626
</service>
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
3+
<xsd:schema xmlns="http://symfony.com/schema/routing"
4+
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
5+
targetNamespace="http://symfony.com/schema/routing"
6+
elementFormDefault="qualified">
7+
8+
<xsd:redefine schemaLocation="https://symfony.com/schema/routing/routing-1.0.xsd">
9+
<xsd:complexType name="routes">
10+
<xsd:complexContent>
11+
<xsd:extension base="routes">
12+
<xsd:choice minOccurs="0" maxOccurs="unbounded">
13+
<xsd:element name="template-route" type="template-route" />
14+
<xsd:element name="redirect-route" type="redirect-route" />
15+
<xsd:element name="url-redirect-route" type="url-redirect-route" />
16+
<xsd:element name="gone-route" type="gone-route" />
17+
</xsd:choice>
18+
</xsd:extension>
19+
</xsd:complexContent>
20+
</xsd:complexType>
21+
</xsd:redefine>
22+
23+
<xsd:group name="base-configs">
24+
<xsd:choice>
25+
<xsd:element name="path" type="localized-path" />
26+
<xsd:element name="requirement" type="element" />
27+
<xsd:element name="option" type="element" />
28+
<xsd:element name="condition" type="xsd:string" />
29+
</xsd:choice>
30+
</xsd:group>
31+
32+
<xsd:complexType name="base-route">
33+
<xsd:attribute name="id" type="xsd:string" use="required" />
34+
<xsd:attribute name="path" type="xsd:string" />
35+
<xsd:attribute name="host" type="xsd:string" />
36+
<xsd:attribute name="methods" type="xsd:string" />
37+
<xsd:attribute name="locale" type="xsd:string" />
38+
<xsd:attribute name="format" type="xsd:string" />
39+
<xsd:attribute name="utf8" type="xsd:boolean" />
40+
</xsd:complexType>
41+
42+
<xsd:complexType name="template-route">
43+
<xsd:complexContent>
44+
<xsd:extension base="base-route">
45+
<xsd:sequence>
46+
<xsd:group ref="base-configs" minOccurs="0" maxOccurs="unbounded" />
47+
<xsd:element name="context" type="map" minOccurs="0" maxOccurs="1" />
48+
</xsd:sequence>
49+
<xsd:attribute name="template" type="xsd:string" />
50+
<xsd:attribute name="max-age" type="xsd:int" />
51+
<xsd:attribute name="shared-max-age" type="xsd:int" />
52+
<xsd:attribute name="private" type="xsd:boolean" />
53+
<xsd:attribute name="schemes" type="xsd:string" />
54+
</xsd:extension>
55+
</xsd:complexContent>
56+
</xsd:complexType>
57+
58+
<xsd:complexType name="redirect-route">
59+
<xsd:complexContent>
60+
<xsd:extension base="base-route">
61+
<xsd:sequence>
62+
<xsd:group ref="base-configs" minOccurs="0" maxOccurs="unbounded" />
63+
<xsd:element name="default" nillable="true" type="default" minOccurs="0" maxOccurs="unbounded" />
64+
</xsd:sequence>
65+
<xsd:attribute name="redirect-to-route" type="xsd:string" />
66+
<xsd:attribute name="permanent" type="xsd:boolean" />
67+
<xsd:attribute name="ignore-attributes" type="xsd:string" />
68+
<xsd:attribute name="keep-request-method" type="xsd:boolean" />
69+
<xsd:attribute name="keep-query-params" type="xsd:boolean" />
70+
<xsd:attribute name="schemes" type="xsd:string" />
71+
</xsd:extension>
72+
</xsd:complexContent>
73+
</xsd:complexType>
74+
75+
<xsd:complexType name="url-redirect-route">
76+
<xsd:complexContent>
77+
<xsd:extension base="base-route">
78+
<xsd:sequence>
79+
<xsd:group ref="base-configs" minOccurs="0" maxOccurs="unbounded" />
80+
</xsd:sequence>
81+
<xsd:attribute name="redirect-to-url" type="xsd:string" />
82+
<xsd:attribute name="permanent" type="xsd:boolean" />
83+
<xsd:attribute name="scheme" type="xsd:string" />
84+
<xsd:attribute name="http-port" type="xsd:int" />
85+
<xsd:attribute name="https-port" type="xsd:int" />
86+
<xsd:attribute name="keep-request-method" type="xsd:boolean" />
87+
</xsd:extension>
88+
</xsd:complexContent>
89+
</xsd:complexType>
90+
91+
<xsd:complexType name="gone-route">
92+
<xsd:complexContent>
93+
<xsd:extension base="base-route">
94+
<xsd:sequence>
95+
<xsd:group ref="base-configs" minOccurs="0" maxOccurs="unbounded" />
96+
</xsd:sequence>
97+
<xsd:attribute name="permanent" type="xsd:boolean" />
98+
</xsd:extension>
99+
</xsd:complexContent>
100+
</xsd:complexType>
101+
102+
</xsd:schema>
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed w 65CE ith this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Routing\Loader;
13+
14+
use Symfony\Bundle\FrameworkBundle\Controller\RedirectController;
15+
use Symfony\Bundle\FrameworkBundle\Controller\TemplateController;
16+
use Symfony\Component\Config\Util\XmlUtils;
17+
use Symfony\Component\Routing\Loader\XmlFileLoader as BaseXmlFileLoader;
18+
use Symfony\Component\Routing\RouteCollection;
19+
20+
/**
21+
* @author Jules Pietri <jules@heahprod.com>
22+
*/
23+
class XmlFileLoader extends BaseXmlFileLoader
24+
{
25+
public const SCHEME_PATH = __DIR__.'/../../Resources/config/schema/framework-routing-1.0.xsd';
26+
27+
/** @var \DOMDocument */
28+
private $document;
29+
30+
protected function loadFile(string $file)
31+
{
32+
return $this->document = parent::loadFile($file);
33+
}
34+
35+
protected function parseNode(RouteCollection $collection, \DOMElement $node, $path, $file)
36+
{
37+
switch ($node->localName) {
38+
case 'template-route':
39+
case 'redirect-route':
40+
case 'url-redirect-route':
41+
case 'gone-route':
42+
if (self::NAMESPACE_URI !== $node->namespaceURI) {
43+
return;
44+
}
45+
46+
$this->parseRoute($collection, $node, $path);
47+
48+
return;
49+
}
50+
51+
parent::parseNode($collection, $node, $path, $file);
52+
}
53+
54+
protected function parseRoute(RouteCollection $collection, \DOMElement $node, $path)
55+
{
56+
$templateContext = [];
57+
58+
if ('template-route' === $node->localName) {
59+
/** @var \DOMElement $context */
60+
foreach ($node->getElementsByTagNameNS(self::NAMESPACE_URI, 'context') as $context) {
61+
$node->removeChild($context);
62+
$map = $this->document->createElementNS(self::NAMESPACE_URI, 'map');
63+
64+
// extract context vars into a map
65+
foreach ($context->childNodes as $n) {
66+
if (!$n instanceof \DOMElement) {
67+
continue;
68+
}
69+
70+
$map->appendChild($n);
71+
}
72+
73+
$default = $this->document->createElementNS(self::NAMESPACE_URI, 'default');
74+
$default->setAttribute('key', 'context');
75+
$default->appendChild($map);
76+
77+
$templateContext = $this->parseDefaultsConfig($default, $path);
78+
}
79+
}
80+
81+
parent::parseRoute($collection, $node, $path);
82+
83+
$route = $collection->get($node->getAttribute(('id')));
84+
85+
switch ($node->localName) {
86+
case 'template-route':
87+
$route
88+
->setDefault('_controller', TemplateController::class)
89+
->setDefault('template', $node->getAttribute('template'))
90+
->setDefault('context', $templateContext)
91+
->setDefault('maxAge', (int) $node->getAttribute('max-age') ?: null)
92+
->setDefault('sharedAge', (int) $node->getAttribute('shared-max-age') ?: null)
93+
->setDefault('private', $node->hasAttribute('private') ? XmlUtils::phpize($node->getAttribute('private')) : null)
94+
;
95+
break;
96+
case 'redirect-route':
97+
$route
98+
->setDefault('_controller', RedirectController::class.'::redirectAction')
99+
->setDefault('route', $node->getAttribute('redirect-to-route'))
100+
->setDefault('permanent', self::getBooleanAttribute($node, 'permanent'))
101+
->setDefault('keepRequestMethod', self::getBooleanAttribute($node, 'keep-request-method'))
102+
->setDefault('keepQueryParams', self::getBooleanAttribute($node, 'keep-query-params'))
103+
;
104+
105+
if (\is_string($ignoreAttributes = XmlUtils::phpize($node->getAttribute('ignore-attributes')))) {
106+
$ignoreAttributes = array_map('trim', explode(',', $ignoreAttributes));
107+
}
108+
109+
$route->setDefault('ignoreAttributes', $ignoreAttributes);
110+
break;
111+
case 'url-redirect-route':
112+
$route
113+
->setDefault('_controller', RedirectController::class.'::urlRedirectAction')
114+
->setDefault('path', $node->getAttribute('redirect-to-url'))
115+
->setDefault('permanent', self::getBooleanAttribute($node, 'permanent'))
116+
->setDefault('scheme', $node->getAttribute('scheme'))
117+
->setDefault('keepRequestMethod', self::getBooleanAttribute($node, 'keep-request-method'))
118+
;
119+
if ($node->hasAttribute('http-port')) {
120+
$route->setDefault('httpPort', (int) $node->getAttribute('http-port') ?: null);
121+
} elseif ($node->hasAttribute('https-port')) {
122+
$route->setDefault('httpsPort', (int) $node->getAttribute('https-port') ?: null);
123+
}
124+
break;
125+
case 'gone-route':
126+
$route
127+
->setDefault('_controller', RedirectController::class.'::redirectAction')
128+
->setDefault('route', '')
129+
;
130+
if ($node->hasAttribute('permanent')) {
131+
$route->setDefault('permanent', self::getBooleanAttribute($node, 'permanent'));
132+
}
133+
break;
134+
}
135+
}
136+
137+
private static function getBooleanAttribute(\DOMElement $node, string $attribute): bool
138+
{
139+
return $node->hasAttribute($attribute) ? XmlUtils::phpize($node->getAttribute($attribute)) : false;
140+
}
141+
}
Lines changed: 112 additions & 0 deletions
61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Routing\Loader;
13+
14+
use Symfony\Bundle\FrameworkBundle\Controller\RedirectController;
15+
use Symfony\Bundle\FrameworkBundle\Controller\TemplateController;
16+
use Symfony\Component\Routing\Loader\YamlFileLoader as BaseYamlFileLoader;
17+
use Symfony\Component\Routing\RouteCollection;
18+
19+
/**
20+
* @author Jules Pietri <jules@heahprod.com>
21+
*/
22+
class YamlFileLoader extends BaseYamlFileLoader
23+
{
24+
private static $availableKeys = [
25+
'template' => ['context', 'max_age', 'shared_max_age', 'private'],
26+
'redirect_to_route' => ['permanent', 'ignore_attributes', 'keep_request_method', 'keep_query_params'],
27+
'redirect_to_url' => ['permanent', 'scheme', 'http_port', 'https_port', 'keep_request_method'],
28+
'gone' => ['permanent'],
29+
];
30+
31+
protected function validate($config, $name, $path)
32+
{
33+
foreach (self::$availableKeys as $routeType => $availableKeys) {
34+
if (!isset($config[$routeType])) {
35+
continue;
36+
}
37+
38+
if (isset($config['controller'])) {
39+
throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "controller" and the "%s" keys for "%s".', $path, $routeType, $name));
40+
}
41+
42+
// keys would be invalid for parent::validate(), but we use them below
43+
unset($config[$routeType]);
44+
foreach ($availableKeys as $key) {
45+
unset($config[$key]);
46+
}
47+
}
48+
49+
parent::validate($config, $name, $path);
50+
}
51+
52+
protected function parseRoute(RouteCollection $collection, $name, array $config, $path)
53+
{
54+
if (isset($config['template'])) {
55+
$config['defaults'] = array_merge($config['defaults'] ?? [], [
56+
'_controller' => TemplateController::class,
57+
'template' => $config['template'],
58+
'context' => $config['context'] ?? [],
59+
'maxAge' => $config['max_age'] ?? null,
60+
'sharedAge' => $config['shared_max_age'] ?? null,
+
'private' => $config['private'] ?? null,
62+
]);
63+
foreach (self::$availableKeys['template'] as $key) {
64+
unset($config[$key]);
65+
}
66+
} elseif (isset($config['redirect_to_route'])) {
67+
$config['defaults'] = array_merge($config['defaults'] ?? [], [
68+
'_controller' => RedirectController::class.'::redirectAction',
69+
'route' => $config['redirect_to_route'],
70+
'permanent' => $config['permanent'] ?? false,
71+
'ignoreAttributes' => $config['ignore_attributes'] ?? false,
72+
'keepRequestMethod' => $config['keep_request_method'] ?? false,
73+
'keepQueryParams' => $config['keep_query_params'] ?? false,
74+
]);
75+
foreach (self::$availableKeys['redirect_to_route'] as $key) {
76+
unset($config[$key]);
77+
}
78+
} elseif (isset($config['redirect_to_url'])) {
79+
$config['defaults'] = array_merge($config['defaults'] ?? [], [
80+
'_controller' => RedirectController::class.'::urlRedirectAction',
81+
'path' => $config['redirect_to_url'],
82+
'permanent' => $config['permanent'] ?? false,
83+
'scheme' => $config['scheme'] ?? null,
84+
'keepRequestMethod' => $config['keep_request_method'] ?? false,
85+
]);
86+
87+
if (\array_key_exists('http_port', $config)) {
88+
$config['defaults']['httpPort'] = (int) $config['http_port'] ?: null;
89+
} elseif (\array_key_exists('http_port', $config)) {
90+
$config['defaults']['httpsPort'] = (int) $config['https_port'] ?: null;
91+
}
92+
93+
foreach (self::$availableKeys['redirect_to_url'] as $key) {
94+
unset($config[$key]);
95+
}
96+
} elseif (isset($config['gone'])) {
97+
$config['defaults'] = array_merge($config['defaults'] ?? [], [
98+
'_controller' => RedirectController::class.'::redirectAction',
99+
'route' => '',
100+
]);
101+
102+
if (isset($config['permanent'])) {
103+
$config['defaults']['permanent'] = $config['permanent'];
104+
unset($config['permanent']);
105+
}
106+
107+
unset($config['gone']);
108+
}
109+
110+
parent::parseRoute($collection, $name, $config, $path);
111+
}
112+
}

0 commit comments

Comments
 (0)
0