]> Raphaël G. Git Repositories - userbundle/blob - Listener/LogoutListener.php
Cleanup
[userbundle] / Listener / LogoutListener.php
1 <?php declare(strict_types=1);
2
3 /*
4 * This file is part of the Rapsys UserBundle package.
5 *
6 * (c) Raphaël Gertz <symfony@rapsys.eu>
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 Rapsys\UserBundle\Listener;
13
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;
25
26 use Rapsys\UserBundle\RapsysUserBundle;
27
28 /**
29 * {@inheritdoc}
30 */
31 class LogoutListener implements EventSubscriberInterface {
32 /**
33 * Config array
34 */
35 protected $config;
36
37 /**
38 * {@inheritdoc}
39 *
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
42 */
43 public function __construct(protected ContainerInterface $container, protected string $targetUrl, protected RouterInterface $router) {
44 //Set config
45 $this->config = $container->getParameter(RapsysUserBundle::getAlias());
46 }
47
48 /**
49 * {@inheritdoc}
50 */
51 public function onLogout(LogoutEvent $event): void {
52 //Get request
53 $request = $event->getRequest();
54
55 //Retrieve logout route
56 $logout = $request->attributes->get('_route');
57
58 //Extract and process referer
59 if (($referer = $request->headers->get('referer'))) {
60 //Create referer request instance
61 $req = Request::create($referer);
62
63 //Get referer path
64 $path = $req->getPathInfo();
65
66 //Get referer query string
67 $query = $req->getQueryString();
68
69 //Remove script name
70 $path = str_replace($request->getScriptName(), '', $path);
71
72 //Try with referer path
73 try {
74 //Save old context
75 $oldContext = $this->router->getContext();
76
77 //Force clean context
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());
81
82 //Retrieve route matching path
83 $route = $this->router->match($path);
84
85 //Reset context
86 $this->router->setContext($oldContext);
87
88 //Clear old context
89 unset($oldContext);
90
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']);
95
96 //Generate url
97 $url = $this->router->generate($name, $route);
98
99 //Set event response
100 $event->setResponse(new RedirectResponse($url, 302));
101
102 //Return
103 return;
104 //With logout route name
105 } else {
106 //Unset referer and route
107 unset($referer, $route);
108 }
109 //No route matched
110 } catch (ResourceNotFoundException $e) {
111 //Unset referer and route
112 unset($referer, $route);
113 }
114 }
115
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) {
120 //Try index route
121 try {
122 //Generate url
123 $url = $this->router->generate($name, $context);
124
125 //Set event response
126 $event->setResponse(new RedirectResponse($url, 302));
127
128 //Return
129 return;
130 //No route matched
131 } catch (ResourceNotFoundException $e) {
132 //Unset name and context
133 unset($name, $context);
134 }
135 //With logout route name
136 } else {
137 //Unset name and context
138 unset($name, $context);
139 }
140 }
141
142 //Try target url
143 try {
144 //Save old context
145 $oldContext = $this->router->getContext();
146
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());
151
152 //With logout target path
153 if ($this->targetUrl[0] == '/') {
154 //Retrieve route matching target url
155 $route = $this->router->match($this->targetUrl);
156
157 //Reset context
158 $this->router->setContext($oldContext);
159
160 //Clear old context
161 unset($oldContext);
162
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']);
167
168 //Generate url
169 $url = $this->router->generate($name, $route);
170
171 //Set event response
172 $event->setResponse(new RedirectResponse($url, 302));
173
174 //Return
175 return;
176 //With logout route name
177 } else {
178 //Unset name and route
179 unset($name, $route);
180 }
181 //With route name
182 } else {
183 //Retrieve route matching path
184 $url = $this->router->generate($this->targetUrl);
185
186 //Set event response
187 $event->setResponse(new RedirectResponse($url, 302));
188
189 //Return
190 return;
191 }
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);
196 }
197
198 //Set event response
199 $event->setResponse(new RedirectResponse('/', 302));
200 }
201
202 /**
203 * {@inheritdoc}
204 */
205 public static function getSubscribedEvents(): array {
206 return [
207 LogoutEvent::class => ['onLogout', 64],
208 ];
209 }
210 }