* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Rapsys\UserBundle\Handler; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Security\Http\Logout\DefaultLogoutSuccessHandler; use Rapsys\UserBundle\RapsysUserBundle; /** * {@inheritdoc} */ class LogoutSuccessHandler extends DefaultLogoutSuccessHandler { /** * Config array */ protected $config; /** * {@inheritdoc} */ protected $router; /** * {@inheritdoc} */ protected $targetUrl; /** * @xxx Second argument will be replaced by security.firewalls.main.logout.target * @see vendor/symfony/security-bundle/DependencyInjection/SecurityExtension.php +360 * * {@inheritdoc} */ public function __construct(ContainerInterface $container, string $targetUrl, RouterInterface $router) { //Set config $this->config = $container->getParameter(self::getAlias()); //Set target url $this->targetUrl = $targetUrl; //Set router $this->router = $router; } /** * {@inheritdoc} */ public function onLogoutSuccess(Request $request): Response { //Retrieve logout route $logout = $request->get('_route'); //Extract and process referer if (($referer = $request->headers->get('referer'))) { //Create referer request instance $req = Request::create($referer); //Get referer path $path = $req->getPathInfo(); //Get referer query string $query = $req->getQueryString(); //Remove script name $path = str_replace($request->getScriptName(), '', $path); //Try with referer path try { //Save old context $oldContext = $this->router->getContext(); //Force clean context //XXX: prevent MethodNotAllowedException on GET only routes because our context method is POST //XXX: see vendor/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php +42 $this->router->setContext(new RequestContext()); //Retrieve route matching path $route = $this->router->match($path); //Reset context $this->router->setContext($oldContext); //Clear old context unset($oldContext); //Without logout route name if (($name = $route['_route']) != $logout) { //Remove route and controller from route defaults unset($route['_route'], $route['_controller'], $route['_canonical_route']); //Generate url $url = $this->router->generate($name, $route); //Return generated route return new RedirectResponse($url, 302); //With logout route name } else { //Unset referer and route unset($referer, $route); } //No route matched } catch (ResourceNotFoundException $e) { //Unset referer and route unset($referer, $route); } } //With index route from config if (!empty($name = $this->config['route']['index']['name']) && is_array($context = $this->config['route']['index']['context'])) { //Without logout route name if ($name != $logout) { //Try index route try { //Generate url $url = $this->router->generate($name, $context); //Return generated route return new RedirectResponse($url, 302); //No route matched } catch (ResourceNotFoundException $e) { //Unset name and context unset($name, $context); } //With logout route name } else { //Unset name and context unset($name, $context); } } //Try target url try { //Save old context $oldContext = $this->router->getContext(); //Force clean context //XXX: prevent MethodNotAllowedException on GET only routes because our context method is POST //XXX: see vendor/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php +42 $this->router->setContext(new RequestContext()); //Retrieve route matching target url $route = $this->router->match($this->targetUrl); //Reset context $this->router->setContext($oldContext); //Clear old context unset($oldContext); //Without logout route name if (($name = $route['_route']) != $logout) { //Remove route and controller from route defaults unset($route['_route'], $route['_controller'], $route['_canonical_route']); //Generate url $url = $this->router->generate($name, $route); //Return generated route return new RedirectResponse($url, 302); //With logout route name } else { //Unset name and route unset($name, $route); } //Get first route from route collection if / path was not matched } catch (ResourceNotFoundException $e) { //Unset name and route unset($name, $route); } //Throw exception throw new \RuntimeException('You must provide a valid logout target url or route name'); } /** * {@inheritdoc} */ public function getAlias(): string { return RapsysUserBundle::getAlias(); } }