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

Skip to content

Commit 370f4bf

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

File tree

10 files changed

+544
-5
lines changed

10 files changed

+544
-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: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
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:include schemaLocation="http://symfony.com/schema/routing/routing-1.0.xsd" />
9+
10+
<xsd:redefine schemaLocation="http://symfony.com/schema/routing/routing-1.0.xsd">
11+
<xsd:complexType name="routes">
12+
<xsd:complexContent>
13+
<xsd:extension base="routes">
14+
<xsd:choice minOccurs="0" maxOccurs="unbounded">
15+
<xsd:element name="template-route" type="template-route" />
16+
<xsd:element name="redirect-route" type="redirect-route" />
17+
<xsd:element name="url-redirect-route" type="url-redirect-route" />
18+
<xsd:element name="gone-route" type="gone-route" />
19+
</xsd:choice>
20+
</xsd:extension>
21+
</xsd:complexContent>
22+
</xsd:complexType>
23+
</xsd:redefine>
24+
25+
<xsd:complexType name="template-route">
26+
<xsd:sequence>
27+
<xsd:choice>
28+
<xsd:element name="path" type="localized-path" minOccurs="0" maxOccurs="unbounded" />
29+
<xsd:element name="requirement" type="element" minOccurs="0" maxOccurs="unbounded" />
30+
<xsd:element name="option" type="element" minOccurs="0" maxOccurs="unbounded" />
31+
</xsd:choice>
32+
<xsd:element name="condition" type="xsd:string" minOccurs="0" maxOccurs="1" />
33+
<xsd:element name="context" type="map" minOccurs="0" maxOccurs="1" />
34+
</xsd:sequence>
35+
<xsd:attribute name="id" type="xsd:string" use="required" />
36+
<xsd:attribute name="path" type="xsd:string" />
37+
<xsd:attribute name="host" type="xsd:string" />
38+
<xsd:attribute name="schemes" type="xsd:string" />
39+
<xsd:attribute name="methods" type="xsd:string" />
40+
<xsd:attribute name="locale" type="xsd:string" />
41+
<xsd:attribute name="format" type="xsd:string" />
42+
<xsd:attribute name="utf8" type="xsd:boolean" />
43+
44+
<xsd:attribute name="template" type="xsd:string" />
45+
<xsd:attribute name="max-age" type="xsd:int" />
46+
<xsd:attribute name="shared-max-age" type="xsd:int" />
47+
<xsd:attribute name="private" type="xsd:boolean" />
48+
</xsd:complexType>
49+
50+
<xsd:complexType name="redirect-route">
51+
<xsd:sequence>
52+
<xsd:group ref="configs" minOccurs="0" maxOccurs="unbounded" />
53+
<xsd:element name="path" type="localized-path" minOccurs="0" maxOccurs="unbounded" />
54+
</xsd:sequence>
55+
<xsd:attribute name="id" type="xsd:string" use="required" />
56+
<xsd:attribute name="path" type="xsd:string" />
57+
<xsd:attribute name="host" type="xsd:string" />
58+
<xsd:attribute name="schemes" type="xsd:string" />
59+
<xsd:attribute name="methods" type="xsd:string" />
60+
<xsd:attribute name="locale" type="xsd:string" />
61+
<xsd:attribute name="format" type="xsd:string" />
62+
<xsd:attribute name="utf8" type="xsd:boolean" />
63+
64+
<xsd:attribute name="redirect-to-route" type="xsd:string" />
65+
<xsd:attribute name="permanent" type="xsd:boolean" />
66+
<xsd:attribute name="ignore-attributes" type="xsd:string" />
67+
<xsd:attribute name="keep-request-method" type="xsd:boolean" />
68+
<xsd:attribute name="keep-query-params" type="xsd:boolean" />
69+
</xsd:complexType>
70+
71+
<xsd:complexType name="url-redirect-route">
72+
<xsd:sequence>
73+
<xsd:group ref="configs" minOccurs="0" maxOccurs="unbounded" />
74+
<xsd:element name="path" type="localized-path" minOccurs="0" maxOccurs="unbounded" />
75+
</xsd:sequence>
76+
<xsd:attribute name="id" type="xsd:string" use="required" />
77+
<xsd:attribute name="path" type="xsd:string" />
78+
<xsd:attribute name="host" type="xsd:string" />
79+
<xsd:attribute name="methods" type="xsd:string" />
80+
<xsd:attribute name="locale" type="xsd:string" />
81+
<xsd:attribute name="format" type="xsd:string" />
82+
<xsd:attribute name="utf8" type="xsd:boolean" />
83+
84+
<xsd:attribute name="redirect-to-url" type="xsd:string" />
85+
<xsd:attribute name="permanent" type="xsd:boolean" />
86+
<xsd:attribute name="scheme" type="xsd:string" />
87+
<xsd:attribute name="http-port" type="xsd:int" />
88+
<xsd:attribute name="https-port" type="xsd:int" />
89+
<xsd:attribute name="keep-request-method" type="xsd:boolean" />
90+
</xsd:complexType>
91+
92+
<xsd:complexType name="gone-route">
93+
<xsd:sequence>
94+
<xsd:group ref="configs" minOccurs="0" maxOccurs="unbounded" />
95+
<xsd:element name="path" type="localized-path" minOccurs="0" maxOccurs="unbounded" />
1241
96+
</xsd:sequence>
97+
<xsd:attribute name="id" type="xsd:string" use="required" />
98+
<xsd:attribute name="path" type="xsd:string" />
99+
<xsd:attribute name="host" type="xsd:string" />
100+
<xsd:attribute name="methods" type="xsd:string" />
101+
<xsd:attribute name="locale" type="xsd:string" />
102+
<xsd:attribute name="format" type="xsd:string" />
103+
<xsd:attribute name="utf8" type="xsd:boolean" />
104+
105+
<xsd:attribute name="permanent" type="xsd:boolean" />
106+
</xsd:complexType>
107+
108+
</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 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\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/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: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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_path' => ['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+
if (isset($config['gone_path'])) {
43+
$config['path'] = $config['gone_path'];
44+
}
45+
46+
// keys would be invalid for parent::validate(), but we use them below
47+
unset($config[$routeType]);
48+
foreach ($availableKeys as $key) {
49+
unset($config[$key]);
50+
}
51+
}
52+
53+
parent::validate($config, $name, $path);
54+
}
55+
56+
protected function parseRoute(RouteCollection $collection, $name, array $config, $path)
57+
{
58+
if (isset($config['template'])) {
59+
$config['defaults'] = array_merge($config['defaults'] ?? [], [
60+
'_controller' => TemplateController::class,
61+
'template' => $config['template'],
62+
'context' => $config['context'] ?? [],
63+
'maxAge' => $config['max_age'] ?? null,
64+
'sharedAge' => $config['shared_max_age'] ?? null,
65+
'private' => $config['private'] ?? null,
66+
]);
67+
foreach (self::$availableKeys['template'] as $key) {
68+
unset($config[$key]);
69+
}
70+
} elseif (isset($config['redirect_to_route'])) {
71+
$config['defaults'] = array_merge($config['defaults'] ?? [], [
72+
'_controller' => RedirectController::class.'::redirectAction',
73+
'route' => $config['redirect_to_route'],
74+
'permanent' => $config['permanent'] ?? false,
75+
'ignoreAttributes' => $config['ignore_attributes'] ?? false,
76+
'keepRequestMethod' => $config['keep_request_method'] ?? false,
77+
'keepQueryParams' => $config['keep_query_params'] ?? false,
78+
]);
79+
foreach (self::$availableKeys['redirect_to_route'] as $key) {
80+
unset($config[$key]);
81+
}
82+
} elseif (isset($config['redirect_to_url'])) {
83+
$config['defaults'] = array_merge($config['defaults'] ?? [], [
84+
'_controller' => RedirectController::class.'::urlRedirectAction',
85+
'path' => $config['redirect_to_url'],
86+
'permanent' => $config['permanent'] ?? false,
87+
'scheme' => $config['scheme'] ?? null,
88+
'keepRequestMethod' => $config['keep_request_method'] ?? false,
89+
]);
90+
91+
if (\array_key_exists('http_port', $config)) {
92+
$config['defaults']['httpPort'] = (int) $config['http_port'] ?: null;
93+
} elseif (\array_key_exists('http_port', $config)) {
94+
$config['defaults']['httpsPort'] = (int) $config['https_port'] ?: null;
95+
}
96+
97+
foreach (self::$availableKeys['redirect_to_url'] as $key) {
98+
unset($config[$key]);
99+
}
100+
} elseif (isset($config['gone_path'])) {
101+
$config['path'] = $config['gone_path'];
102+
$config['defaults'] = array_merge($config['defaults'] ?? [], [
103+
'_controller' => RedirectController::class.'::redirectAction',
104+
'route' => '',
105+
]);
106+
107+
if (isset($config['permanent'])) {
108+
$config['defaults']['permanent'] = $config['permanent'];
109+
unset($config['permanent']);
110+
}
111+
112+
unset($config['gone_path']);
113+
}
114+
115+
parent::parseRoute($collection, $name, $config, $path);
116+
}
117+
}

0 commit comments

Comments
 (0)
0