-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Routing] Redirection from route configuration #25145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Bundle\FrameworkBundle\EventListener; | ||
|
||
use Symfony\Bundle\FrameworkBundle\Controller\RedirectController; | ||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
use Symfony\Component\HttpKernel\Event\GetResponseEvent; | ||
use Symfony\Component\HttpKernel\KernelEvents; | ||
|
||
/** | ||
* Resolve the controller for requests containing the `_redirect_to` attributes. | ||
* | ||
* @author Samuel Roze <samuel.roze@gmail.com> | ||
*/ | ||
class ResolveRedirectControllerSubscriber implements EventSubscriberInterface | ||
{ | ||
public static function getSubscribedEvents() | ||
{ | ||
return array( | ||
KernelEvents::REQUEST => array('onKernelRequest', 20), | ||
); | ||
} | ||
|
||
public function onKernelRequest(GetResponseEvent $event) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
{ | ||
$requestAttributes = $event->getRequest()->attributes; | ||
|
||
if (!$requestAttributes->has('_controller') && $redirectTo = $requestAttributes->get('_redirect_to')) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would use early returns instead: if ($requestAttributes->has('_controller')) {
return;
}
if (!$redirectTo = $requestAttributes->get('_redirect_to')) {
return;
} |
||
if ($this->looksLikeUrl($redirectTo)) { | ||
$requestAttributes->set('_controller', array(RedirectController::class, 'urlRedirectAction')); | ||
$requestAttributes->set('path', $redirectTo); | ||
} else { | ||
$requestAttributes->set('_controller', array(RedirectController::class, 'redirectAction')); | ||
$requestAttributes->set('route', $redirectTo); | ||
} | ||
|
||
if (!$requestAttributes->has('permanent')) { | ||
$requestAttributes->set('permanent', $requestAttributes->get('_redirect_permanent', false)); | ||
} | ||
} | ||
} | ||
|
||
private function looksLikeUrl(string $urlOrRouteName): bool | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. private static? 😆 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the point? 😄 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. perf? dunno sorry :P just a habit of mine. Like how it shows utility / non class-API. |
||
{ | ||
foreach (array('/', 'http://', 'https://') as $pattern) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. + There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure what you mean here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wouldn't bother with that tbf There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we really want to implement such fuzzy code? I mean when configuring a redirection through the routing config before, you always had to distinguish URLs and paths yourself. Why don't we do that here too (e.g. use |
||
if (0 === strpos($urlOrRouteName, $pattern)) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Bundle\FrameworkBundle\Tests\EventListener; | ||
|
||
use Symfony\Bundle\FrameworkBundle\Controller\RedirectController; | ||
use Symfony\Bundle\FrameworkBundle\EventListener\ResolveRedirectControllerSubscriber; | ||
use Symfony\Bundle\FrameworkBundle\Tests\TestCase; | ||
use Symfony\Component\HttpFoundation\Request; | ||
use Symfony\Component\HttpKernel\Event\GetResponseEvent; | ||
use Symfony\Component\HttpKernel\HttpKernelInterface; | ||
|
||
class ResolveRedirectControllerSubscriberTest extends TestCase | ||
{ | ||
/** | ||
* @dataProvider provideRedirectionExamples | ||
*/ | ||
public function testSetControllerForRedirectToRoute(Request $request, array $expectedAttributes) | ||
{ | ||
$httpKernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock(); | ||
$subscriber = new ResolveRedirectControllerSubscriber(); | ||
$subscriber->onKernelRequest(new GetResponseEvent($httpKernel, $request, HttpKernelInterface::MASTER_REQUEST)); | ||
|
||
foreach ($expectedAttributes as $name => $value) { | ||
$this->assertEquals($value, $request->attributes->get($name)); | ||
} | ||
} | ||
|
||
public function provideRedirectionExamples() | ||
{ | ||
// No redirection | ||
yield array($this->requestWithAttributes(array( | ||
'_controller' => 'AppBundle:Starting:format', | ||
)), array( | ||
'_controller' => 'AppBundle:Starting:format', | ||
)); | ||
|
||
// Controller win over redirection | ||
yield array($this->requestWithAttributes(array( | ||
'_controller' => 'AppBundle:Starting:format', | ||
'_redirect_to' => 'https://google.com', | ||
)), array( | ||
'_controller' => 'AppBundle:Starting:format', | ||
)); | ||
|
||
// Redirection to URL | ||
yield array($this->requestWithAttributes(array( | ||
'_redirect_to' => 'https://google.com', | ||
)), array( | ||
'_controller' => array(RedirectController::class, 'urlRedirectAction'), | ||
'path' => 'https://google.com', | ||
)); | ||
|
||
// Redirection to route | ||
yield array($this->requestWithAttributes(array( | ||
'_redirect_to' => 'route', | ||
)), array( | ||
'_controller' => array(RedirectController::class, 'redirectAction'), | ||
'route' => 'route', | ||
)); | ||
|
||
// Permanent redirection to route | ||
yield array($this->requestWithAttributes(array( | ||
'_redirect_to' => 'route', | ||
'_redirect_permanent' => true, | ||
)), array( | ||
'_controller' => array(RedirectController::class, 'redirectAction'), | ||
'route' => 'route', | ||
'permanent' => true, | ||
)); | ||
} | ||
|
||
private function requestWithAttributes(array $attributes): Request | ||
{ | ||
$request = new Request(); | ||
|
||
foreach ($attributes as $name => $value) { | ||
$request->attributes->set($name, $value); | ||
} | ||
|
||
return $request; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -243,6 +243,15 @@ private function parseConfigs(\DOMElement $node, $path) | |
$defaults['_controller'] = $controller; | ||
} | ||
|
||
if ($redirectTo = $node->getAttribute('redirect-to')) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should forbid to put it at the same time than a controller (check for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done 👍 |
||
if (isset($defaults['_controller'])) { | ||
throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both a controller and a redirection.', $path)); | ||
} | ||
|
||
$defaults['_redirect_to'] = $redirectTo; | ||
$defaults['_redirect_permanent'] = (bool) $node->getAttribute('redirect-permanent'); | ||
} | ||
|
||
return array($defaults, $requirements, $options, $condition); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<?xml version="1.0" encoding="UTF-8" ?> | ||
<routes xmlns="http://symfony.com/schema/routing" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://symfony.com/schema/routing | ||
http://symfony.com/schema/routing/routing-1.0.xsd"> | ||
|
||
<route id="app_symfony" path="/symfony" redirect-to="https://symfony.com" controller="App\Controller\Symfony" /> | ||
</routes> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
app_symfony: | ||
path: /symfony | ||
controller: App\Controller\Symfony | ||
redirect_to: https://symfony.com |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?xml version="1.0" encoding="UTF-8" ?> | ||
<routes xmlns="http://symfony.com/schema/routing" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://symfony.com/schema/routing | ||
http://symfony.com/schema/routing/routing-1.0.xsd"> | ||
|
||
<route id="app_homepage" path="/" controller="AppBundle:Homepage:show" /> | ||
<route id="app_temporary_redirect" path="/home" redirect-to="app_homepage" /> | ||
<route id="app_permanent_redirect" path="/permanent-home" redirect-to="/" redirect-permanent="true" /> | ||
</routes> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
app_homepage: | ||
path: / | ||
controller: AppBundle:Homepage:show | ||
|
||
app_temporary_redirect: | ||
path: /home | ||
redirect_to: app_homepage | ||
|
||
app_permanent_redirect: | ||
path: /permanent-home | ||
redirect_to: / | ||
redirect_permanent: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public static function getSubscribedEvents(): array