Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 3266887

Browse filesBrowse files
committed
Allow to configure a redirection from the route configuration
1 parent 332ad0a commit 3266887
Copy full SHA for 3266887

File tree

Expand file treeCollapse file tree

12 files changed

+266
-1
lines changed
Filter options
Expand file treeCollapse file tree

12 files changed

+266
-1
lines changed
+62Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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\EventListener;
13+
14+
use Symfony\Bundle\FrameworkBundle\Controller\RedirectController;
15+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
16+
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
17+
use Symfony\Component\HttpKernel\KernelEvents;
18+
19+
/**
20+
* Resolve the controller for requests containing the `_redirect_to` attributes.
21+
*
22+
* @author Samuel Roze <samuel.roze@gmail.com>
23+
*/
24+
class ResolveRedirectControllerSubscriber implements EventSubscriberInterface
25+
{
26+
public static function getSubscribedEvents()
27+
{
28+
return array(
29+
KernelEvents::REQUEST => array('onKernelRequest', 20),
30+
);
31+
}
32+
33+
public function onKernelRequest(GetResponseEvent $event)
34+
{
35+
$requestAttributes = $event->getRequest()->attributes;
36+
37+
if (!$requestAttributes->has('_controller') && $redirectTo = $requestAttributes->get('_redirect_to')) {
38+
if ($this->looksLikeUrl($redirectTo)) {
39+
$requestAttributes->set('_controller', array(RedirectController::class, 'urlRedirectAction'));
40+
$requestAttributes->set('path', $redirectTo);
41+
} else {
42+
$requestAttributes->set('_controller', array(RedirectController::class, 'redirectAction'));
43+
$requestAttributes->set('route', $redirectTo);
44+
}
45+
46+
if (!$requestAttributes->has('permanent')) {
47+
$requestAttributes->set('permanent', $requestAttributes->get('_redirect_permanent', false));
48+
}
49+
}
50+
}
51+
52+
private function looksLikeUrl(string $urlOrRouteName): bool
53+
{
54+
foreach (array('/', 'http://', 'https://') as $pattern) {
55+
if (0 === strpos($urlOrRouteName, $pattern)) {
56+
return true;
57+
}
58+
}
59+
60+
return false;
61+
}
62+
}

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,9 @@
7575
<argument type="service" id="controller_name_converter" />
7676
<tag name="kernel.event_subscriber" />
7777
</service>
78+
79+
<service id="resolve_redirect_controller_name_subscriber" class="Symfony\Bundle\FrameworkBundle\EventListener\ResolveRedirectControllerSubscriber">
80+
<tag name="kernel.event_subscriber" />
81+
</service>
7882
</services>
7983
</container>
+91Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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\Tests\EventListener;
13+
14+
use Symfony\Bundle\FrameworkBundle\Controller\RedirectController;
15+
use Symfony\Bundle\FrameworkBundle\EventListener\ResolveRedirectControllerSubscriber;
16+
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
17+
use Symfony\Component\HttpFoundation\Request;
18+
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
19+
use Symfony\Component\HttpKernel\HttpKernelInterface;
20+
21+
class ResolveRedirectControllerSubscriberTest extends TestCase
22+
{
23+
/**
24+
* @dataProvider provideRedirectionExamples
25+
*/
26+
public function testSetControllerForRedirectToRoute(Request $request, array $expectedAttributes)
27+
{
28+
$httpKernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
29+
$subscriber = new ResolveRedirectControllerSubscriber();
30+
$subscriber->onKernelRequest(new GetResponseEvent($httpKernel, $request, HttpKernelInterface::MASTER_REQUEST));
31+
32+
foreach ($expectedAttributes as $name => $value) {
33+
$this->assertEquals($value, $request->attributes->get($name));
34+
}
35+
}
36+
37+
public function provideRedirectionExamples()
38+
{
39+
// No redirection
40+
yield array($this->requestWithAttributes(array(
41+
'_controller' => 'AppBundle:Starting:format',
42+
)), array(
43+
'_controller' => 'AppBundle:Starting:format',
44+
));
45+
46+
// Controller win over redirection
47+
yield array($this->requestWithAttributes(array(
48+
'_controller' => 'AppBundle:Starting:format',
49+
'_redirect_to' => 'https://google.com',
50+
)), array(
51+
'_controller' => 'AppBundle:Starting:format',
52+
));
53+
54+
// Redirection to URL
55+
yield array($this->requestWithAttributes(array(
56+
'_redirect_to' => 'https://google.com',
57+
)), array(
58+
'_controller' => array(RedirectController::class, 'urlRedirectAction'),
59+
'path' => 'https://google.com',
60+
));
61+
62+
// Redirection to route
63+
yield array($this->requestWithAttributes(array(
64+
'_redirect_to' => 'route',
65+
)), array(
66+
'_controller' => array(RedirectController::class, 'redirectAction'),
67+
'route' => 'route',
68+
));
69+
70+
// Permanent redirection to route
71+
yield array($this->requestWithAttributes(array(
72+
'_redirect_to' => 'route',
73+
'_redirect_permanent' => true,
74+
)), array(
75+
'_controller' => array(RedirectController::class, 'redirectAction'),
76+
'route' => 'route',
77+
'permanent' => true,
78+
));
79+
}
80+
81+
private function requestWithAttributes(array $attributes): Request
82+
{
83+
$request = new Request();
84+
85+
foreach ($attributes as $name => $value) {
86+
$request->attributes->set($name, $value);
87+
}
88+
89+
return $request;
90+
}
91+
}

‎src/Symfony/Component/Routing/Loader/XmlFileLoader.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Loader/XmlFileLoader.php
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,15 @@ private function parseConfigs(\DOMElement $node, $path)
243243
$defaults['_controller'] = $controller;
244244
}
245245

246+
if ($redirectTo = $node->getAttribute('redirect-to')) {
247+
if (isset($defaults['_controller'])) {
248+
throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both a controller and a redirection.', $path));
249+
}
250+
251+
$defaults['_redirect_to'] = $redirectTo;
252+
$defaults['_redirect_permanent'] = (bool) $node->getAttribute('redirect-permanent');
253+
}
254+
246255
return array($defaults, $requirements, $options, $condition);
247256
}
248257

‎src/Symfony/Component/Routing/Loader/YamlFileLoader.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Loader/YamlFileLoader.php
+10-1Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
class YamlFileLoader extends FileLoader
2929
{
3030
private static $availableKeys = array(
31-
'resource', 'type', 'prefix', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition', 'controller', 'name_prefix',
31+
'resource', 'type', 'prefix', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition', 'controller', 'name_prefix', 'redirect_to', 'redirect_permanent',
3232
);
3333
private $yamlParser;
3434

@@ -120,6 +120,15 @@ protected function parseRoute(RouteCollection $collection, $name, array $config,
120120
$defaults['_controller'] = $config['controller'];
121121
}
122122

123+
if (isset($config['redirect_to'])) {
124+
if (isset($defaults['_controller'])) {
125+
throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both a controller and a redirection.', $path));
126+
}
127+
128+
$defaults['_redirect_to'] = $config['redirect_to'];
129+
$defaults['_redirect_permanent'] = $config['redirect_permanent'] ?? false;
130+
}
131+
123132
$route = new Route($config['path'], $defaults, $requirements, $options, $host, $schemes, $methods, $condition);
124133

125134
$collection->add($name, $route);

‎src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
<xsd:attribute name="schemes" type="xsd:string" />
4343
<xsd:attribute name="methods" type="xsd:string" />
4444
<xsd:attribute name="controller" type="xsd:string" />
45+
<xsd:attribute name="redirect-to" type="xsd:string" />
46+
<xsd:attribute name="redirect-permanent" type="xsd:boolean" />
4547
</xsd:complexType>
4648

4749
<xsd:complexType name="import">
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<routes xmlns="http://symfony.com/schema/routing"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://symfony.com/schema/routing
5+
http://symfony.com/schema/routing/routing-1.0.xsd">
6+
7+
<route id="app_symfony" path="/symfony" redirect-to="https://symfony.com" controller="App\Controller\Symfony" />
8+
</routes>
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
app_symfony:
2+
path: /symfony
3+
controller: App\Controller\Symfony
4+
redirect_to: https://symfony.com
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<routes xmlns="http://symfony.com/schema/routing"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://symfony.com/schema/routing
5+
http://symfony.com/schema/routing/routing-1.0.xsd">
6+
7+
<route id="app_homepage" path="/" controller="AppBundle:Homepage:show" />
8+
<route id="app_temporary_redirect" path="/home" redirect-to="app_homepage" />
9+
<route id="app_permanent_redirect" path="/permanent-home" redirect-to="/" redirect-permanent="true" />
10+
</routes>
+12Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
app_homepage:
2+
path: /
3+
controller: AppBundle:Homepage:show
4+
5+
app_temporary_redirect:
6+
path: /home
7+
redirect_to: app_homepage
8+
9+
app_permanent_redirect:
10+
path: /permanent-home
11+
redirect_to: /
12+
redirect_permanent: true

‎src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php
+27Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,4 +372,31 @@ public function testImportRouteWithNamePrefix()
372372
$this->assertNotNull($routeCollection->get('api_app_blog'));
373373
$this->assertEquals('/api/blog', $routeCollection->get('api_app_blog')->getPath());
374374
}
375+
376+
public function testRedirections()
377+
{
378+
$loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/redirect_to')));
379+
$routeCollection = $loader->load('routing.xml');
380+
381+
$route = $routeCollection->get('app_homepage');
382+
$this->assertSame('AppBundle:Homepage:show', $route->getDefault('_controller'));
383+
384+
$route = $routeCollection->get('app_temporary_redirect');
385+
$this->assertSame('app_homepage', $route->getDefault('_redirect_to'));
386+
$this->assertFalse($route->getDefault('_redirect_permanent'));
387+
388+
$route = $routeCollection->get('app_permanent_redirect');
389+
$this->assertSame('/', $route->getDefault('_redirect_to'));
390+
$this->assertTrue($route->getDefault('_redirect_permanent'));
391+
}
392+
393+
/**
394+
* @expectedException \InvalidArgumentException
395+
* @expectedExceptionMessageRegExp /The routing file "[^"]*" must not specify both a controller and a redirection\./
396+
*/
397+
public function testRedirectionCannotBeUsedWithController()
398+
{
399+
$loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/redirect_to')));
400+
$loader->load('redirect_with_controller.xml');
401+
}
375402
}

‎src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php
+27Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,4 +193,31 @@ public function testImportRouteWithNamePrefix()
193193
$this->assertNotNull($routeCollection->get('api_app_blog'));
194194
$this->assertEquals('/api/blog', $routeCollection->get('api_app_blog')->getPath());
195195
}
196+
197+
public function testRedirections()
198+
{
199+
$loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/redirect_to')));
200+
$routeCollection = $loader->load('routing.yml');
201+
202+
$route = $routeCollection->get('app_homepage');
203+
$this->assertSame('AppBundle:Homepage:show', $route->getDefault('_controller'));
204+
205+
$route = $routeCollection->get('app_temporary_redirect');
206+
$this->assertSame('app_homepage', $route->getDefault('_redirect_to'));
207+
$this->assertFalse($route->getDefault('_redirect_permanent'));
208+
209+
$route = $routeCollection->get('app_permanent_redirect');
210+
$this->assertSame('/', $route->getDefault('_redirect_to'));
211+
$this->assertTrue($route->getDefault('_redirect_permanent'));
212+
}
213+
214+
/**
215+
* @expectedException \InvalidArgumentException
216+
* @expectedExceptionMessageRegExp /The routing file "[^"]*" must not specify both a controller and a redirection\./
217+
*/
218+
public function testRedirectionCannotBeUsedWithController()
219+
{
220+
$loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/redirect_to')));
221+
$loader->load('redirect_with_controller.yml');
222+
}
196223
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.