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

Skip to content

Commit 8b3ce31

Browse files
committed
[FrameworkBundle][Routing] added XML and YAML loaders to handle template and redirect controllers
1 parent f46ab58 commit 8b3ce31

File tree

10 files changed

+573
-5
lines changed

10 files changed

+573
-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: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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:element name="context" type="map" minOccurs="0" maxOccurs="1" />
47+
<xsd:group ref="base-configs" minOccurs="0" maxOccurs="unbounded" />
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:sequence>
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:attribute name="schemes" type="xsd:string" />
70+
</xsd:extension>
71+
</xsd:complexContent>
72+
</xsd:complexType>
73+
74+
<xsd:complexType name="url-redirect-route">
75+
<xsd:complexContent>
76+
<xsd:extension base="base-route">
77+
<xsd:sequence>
78+
<xsd:group ref="base-configs" minOccurs="0" maxOccurs="unbounded" />
79+
</xsd:sequence>
80+
<xsd:attribute name="redirect-to-url" type="xsd:string" />
81+
<xsd:attribute name="permanent" type="xsd:boolean" />
82+
<xsd:attribute name="scheme" type="xsd:string" />
83+
<xsd:attribute name="http-port" type="xsd:int" />
84+
<xsd:attribute name="https-port" type="xsd:int" />
85+
<xsd:attribute name="keep-request-method" type="xsd:boolean" />
86+
</xsd:extension>
87+
</xsd:complexContent>
88+
</xsd:complexType>
89+
90+
<xsd:complexType name="gone-route">
91+
<xsd:complexContent>
92+
<xsd: 6377 extension base="base-route">
93+
<xsd:sequence>
94+
<xsd:group ref="base-configs" minOccurs="0" maxOccurs="unbounded" />
95+
</xsd:sequence>
96+
<xsd:attribute name="permanent" type="xsd:boolean" />
97+
</xsd:extension>
98+
</xsd:complexContent>
99+
</xsd:complexType>
100+
101+
</xsd:schema>
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
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\Exception\InvalidXmlException;
17+
use Symfony\Component\Config\Util\Exception\XmlParsingException;
18+
use Symfony\Component\Config\Util\XmlUtils;
19+
use Symfony\Component\Routing\Loader\XmlFileLoader as BaseXmlFileLoader;
20+
use Symfony\Component\Routing\RouteCollection;
21+
22+
/**
23+
* @author Jules Pietri <jules@heahprod.com>
24+
*/
25+
class XmlFileLoader extends BaseXmlFileLoader
26+
{
27+
public const SCHEME_PATH = __DIR__.'/../../Resources/config/schema/framework-routing-1.0.xsd';
28+
29+
private const REDEFINED_SCHEME_URI = 'https://symfony.com/schema/routing/routing-1.0.xsd';
30+
private const SCHEME_URI = 'https://symfony.com/schema/routing/framework-routing-1.0.xsd';
31+
private const SCHEMA_LOCATIONS = [
32+
self::REDEFINED_SCHEME_URI => parent::SCHEME_PATH,
33+
self::SCHEME_URI => self::SCHEME_PATH,
34+
];
35+
36+
/** @var \DOMDocument */
37+
private $document;
38+
39+
/**
40+
* {@inheritdoc}
41+
*/
42+
protected function loadFile(string $file)
43+
{
44+
if ('' === trim($content = @file_get_contents($file))) {
45+
throw new \InvalidArgumentException(sprintf('File %s does not contain valid XML, it is empty.', $file));
46+
}
47+
48+
foreach (self::SCHEMA_LOCATIONS as $uri => $path) {
49+
if (false !== strpos($content, $uri)) {
50+
$content = str_replace($uri, 'file:///'.str_replace('\\', '/', realpath($path)), $content);
51+
}
52+
}
53+
54+
try {
55+
return $this->document = XmlUtils::parse($content, function (\DOMDocument $document) {
56+
return @$document->schemaValidateSource(str_replace(
57+
self::REDEFINED_SCHEME_URI,
58+
'file:///'.str_replace('\\', '/', realpath(parent::SCHEME_PATH)),
59+
file_get_contents(self::SCHEME_PATH)
60+
));
61+
});
62+
} catch (InvalidXmlException $e) {
63+
throw new XmlParsingException(sprintf('The XML file "%s" is not valid.', $file), 0, $e->getPrevious());
64+
}
65+
}
66+
67+
/**
68+
* {@inheritdoc}
69+
*/
70+
protected function parseNode(RouteCollection $collection, \DOMElement $node, $path, $file)
71+
{
72+
switch ($node->localName) {
73+
case 'template-route':
74+
case 'redirect-route':
75+
case 'url-redirect-route':
76+
case 'gone-route':
77+
if (self::NAMESPACE_URI !== $node->namespaceURI) {
78+
return;
79+
}
80+
81+
$this->parseRoute($collection, $node, $path);
82+
83+
return;
84+
}
85+
86+
parent::parseNode($collection, $node, $path, $file);
87+
}
88+
89+
/**
90+
* {@inheritdoc}
91+
*/
92+
protected function parseRoute(RouteCollection $collection, \DOMElement $node, $path)
93+
{
94+
$templateContext = [];
95+
96+
if ('template-route' === $node->localName) {
97+
/** @var \DOMElement $context */
98+
foreach ($node->getElementsByTagNameNS(self::NAMESPACE_URI, 'context') as $context) {
99+
$node->removeChild($context);
100+
$map = $this->document->createElementNS(self::NAMESPACE_URI, 'map');
101+
102+
// extract context vars into a map
103+
foreach ($context->childNodes as $n) {
104+
if (!$n instanceof \DOMElement) {
105+
continue;
106+
}
107+
108+
$map->appendChild($n);
109+
}
110+
111+
$default = $this->document->createElementNS(self::NAMESPACE_URI, 'default');
112+
$default->setAttribute('key', 'context');
113+
$default->appendChild($map);
114+
115+
$templateContext = $this->parseDefaultsConfig($default, $path);
116+
}
117+
}
118+
119+
parent::parseRoute($collection, $node, $path);
120+
121+
$route = $collection->get($node->getAttribute(('id')));
122+
123+
switch ($node->localName) {
124+
case 'template-route':
125+
$route
126+
->setDefault('_controller', TemplateController::class)
127+
->setDefault('template', $node->getAttribute('template'))
128+
->setDefault('context', $templateContext)
129+
->setDefault('maxAge', (int) $node->getAttribute('max-age') ?: null)
130+
->setDefault('sharedAge', (int) $node->getAttribute('shared-max-age') ?: null)
131+
->setDefault('private', $node->hasAttribute('private') ? XmlUtils::phpize($node->getAttribute('private')) : null)
132+
;
133+
break;
134+
case 'redirect-route':
135+
$route
136+
->setDefault('_controller', RedirectController::class.'::redirectAction')
137+
->setDefault('route', $node->getAttribute('redirect-to-route'))
138+
->setDefault('permanent', self::getBooleanAttribute($node, 'permanent'))
139+
->setDefault('keepRequestMethod', self::getBooleanAttribute($node, 'keep-request-method'))
140+
->setDefault('keepQueryParams', self::getBooleanAttribute($node, 'keep-query-params'))
141+
;
142+
143+
if (\is_string($ignoreAttributes = XmlUtils::phpize($node->getAttribute('ignore-attributes')))) {
144+
$ignoreAttributes = array_map('trim', explode(',', $ignoreAttributes));
145+
}
146+
147+
$route->setDefault('ignoreAttributes', $ignoreAttributes);
148+
break;
149+
case 'url-redirect-route':
150+
$route
151+
->setDefault('_controller', RedirectController::class.'::urlRedirectAction')
152+
->setDefault('path', $node->getAttribute('redirect-to-url'))
153+
->setDefault('permanent', self::getBooleanAttribute($node, 'permanent'))
154+
->setDefault('scheme', $node->getAttribute('scheme'))
155+
->setDefault('keepRequestMethod', self::getBooleanAttribute($node, 'keep-request-method'))
156+
;
157+
if ($node->hasAttribute('http-port')) {
158+
$route->setDefault('httpPort', (int) $node->getAttribute('http-port') ?: null);
159+
} elseif ($node->hasAttribute('https-port')) {
160+
$route->setDefault('httpsPort', (int) $node->getAttribute('https-port') ?: null);
161+
}
162+
break;
163+
case 'gone-route':
164+
$route
165+
->setDefault('_controller', RedirectController::class.'::redirectAction')
166+
->setDefault('route', '')
167+
;
168+
if ($node->hasAttribute('permanent')) {
169+
$route->setDefault('permanent', self::getBooleanAttribute($node, 'permanent'));
170+
}
171+
break;
172+
}
173+
}
174+
175+
private static function getBooleanAttribute(\DOMElement $node, string $attribute): bool
176+
{
177+
return $node->hasAttribute($attribute) ? XmlUtils::phpize($node->getAttribute($attribute)) : false;
178+
}
179+
}

0 commit comments

Comments
 (0)
0