1 <?php
declare(strict_types
=1);
4 * This file is part of the Rapsys UserBundle package.
6 * (c) Raphaël Gertz <symfony@rapsys.eu>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Rapsys\UserBundle\Listener
;
14 use Symfony\Component\DependencyInjection\ContainerInterface
;
15 use Symfony\Component\EventDispatcher\EventSubscriberInterface
;
16 use Symfony\Component\HttpFoundation\RedirectResponse
;
17 use Symfony\Component\HttpFoundation\Request
;
18 use Symfony\Component\Routing\Exception\InvalidParameterException
;
19 use Symfony\Component\Routing\Exception\MissingMandatoryParametersException
;
20 use Symfony\Component\Routing\Exception\ResourceNotFoundException
;
21 use Symfony\Component\Routing\Exception\RouteNotFoundException
;
22 use Symfony\Component\Routing\RequestContext
;
23 use Symfony\Component\Routing\RouterInterface
;
24 use Symfony\Component\Security\Http\Event\LogoutEvent
;
26 use Rapsys\UserBundle\RapsysUserBundle
;
31 class LogoutListener
implements EventSubscriberInterface
{
40 * @xxx Second argument will be replaced by security.firewalls.main.logout.target
41 * @see vendor/symfony/security-bundle/Resources/config/security_listeners.php +79
43 public function __construct(protected ContainerInterface
$container, protected string $targetUrl, protected RouterInterface
$router) {
45 $this->config
= $container->getParameter(RapsysUserBundle
::getAlias());
51 public function onLogout(LogoutEvent
$event): void {
53 $request = $event->getRequest();
55 //Retrieve logout route
56 $logout = $request->attributes
->get('_route');
58 //Extract and process referer
59 if (($referer = $request->headers
->get('referer'))) {
60 //Create referer request instance
61 $req = Request
::create($referer);
64 $path = $req->getPathInfo();
66 //Get referer query string
67 $query = $req->getQueryString();
70 $path = str_replace($request->getScriptName(), '', $path);
72 //Try with referer path
75 $oldContext = $this->router
->getContext();
78 //XXX: prevent MethodNotAllowedException on GET only routes because our context method is POST
79 //XXX: see vendor/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php +42
80 $this->router
->setContext(new RequestContext());
82 //Retrieve route matching path
83 $route = $this->router
->match($path);
86 $this->router
->setContext($oldContext);
91 //Without logout route name
92 if (($name = $route['_route']) != $logout) {
93 //Remove route and controller from route defaults
94 unset($route['_route'], $route['_controller'], $route['_canonical_route']);
97 $url = $this->router
->generate($name, $route);
100 $event->setResponse(new RedirectResponse($url, 302));
104 //With logout route name
106 //Unset referer and route
107 unset($referer, $route);
110 } catch (ResourceNotFoundException
$e) {
111 //Unset referer and route
112 unset($referer, $route);
116 //With index route from config
117 if (!empty($name = $this->config
['route']['index']['name']) && is_array($context = $this->config
['route']['index']['context'])) {
118 //Without logout route name
119 if ($name != $logout) {
123 $url = $this->router
->generate($name, $context);
126 $event->setResponse(new RedirectResponse($url, 302));
131 } catch (ResourceNotFoundException
$e) {
132 //Unset name and context
133 unset($name, $context);
135 //With logout route name
137 //Unset name and context
138 unset($name, $context);
145 $oldContext = $this->router
->getContext();
147 //Force clean context
148 //XXX: prevent MethodNotAllowedException on GET only routes because our context method is POST
149 //XXX: see vendor/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php +42
150 $this->router
->setContext(new RequestContext());
152 //With logout target path
153 if ($this->targetUrl
[0] == '/') {
154 //Retrieve route matching target url
155 $route = $this->router
->match($this->targetUrl
);
158 $this->router
->setContext($oldContext);
163 //Without logout route name
164 if (($name = $route['_route']) != $logout) {
165 //Remove route and controller from route defaults
166 unset($route['_route'], $route['_controller'], $route['_canonical_route']);
169 $url = $this->router
->generate($name, $route);
172 $event->setResponse(new RedirectResponse($url, 302));
176 //With logout route name
178 //Unset name and route
179 unset($name, $route);
183 //Retrieve route matching path
184 $url = $this->router
->generate($this->targetUrl
);
187 $event->setResponse(new RedirectResponse($url, 302));
192 //Get first route from route collection if / path was not matched
193 } catch (ResourceNotFoundException
|RouteNotFoundException
|MissingMandatoryParametersException
|InvalidParameterException
$e) {
194 //Unset name and route
195 unset($name, $route);
199 $event->setResponse(new RedirectResponse('/', 302));
205 public static function getSubscribedEvents(): array {
207 LogoutEvent
::class => ['onLogout', 64],