From b9e5d850a839448a7ffdc1ffcbbe5ae0e24d0428 Mon Sep 17 00:00:00 2001
From: =?utf8?q?Rapha=C3=ABl=20Gertz?= <git@rapsys.eu>
Date: Wed, 11 Aug 2021 20:37:54 +0200
Subject: [PATCH] Add LogoutSuccessHandler

---
 Handler/LogoutSuccessHandler.php | 126 +++++++++++++++++++++++++++++++
 1 file changed, 126 insertions(+)
 create mode 100644 Handler/LogoutSuccessHandler.php

diff --git a/Handler/LogoutSuccessHandler.php b/Handler/LogoutSuccessHandler.php
new file mode 100644
index 0000000..34a7b08
--- /dev/null
+++ b/Handler/LogoutSuccessHandler.php
@@ -0,0 +1,126 @@
+<?php
+
+namespace Rapsys\UserBundle\Handler;
+
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Exception\ResourceNotFoundException;
+use Symfony\Component\Routing\RouterInterface;
+use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface;
+
+class LogoutSuccessHandler implements LogoutSuccessHandlerInterface {
+	/**
+	 * {@inheritdoc}
+	 */
+	protected $container;
+
+	/**
+	 * {@inheritdoc}
+	 */
+	protected $router;
+
+	/**
+	 * {@inheritdoc}
+	 */
+	public function __construct(ContainerInterface $container, RouterInterface $router) {
+		$this->container = $container;
+		$this->router = $router;
+	}
+
+	/**
+	 * {@inheritdoc}
+	 */
+	public function onLogoutSuccess(Request $request) {
+		//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 {
+				//Retrieve route matching path
+				$route = $this->router->match($path);
+
+				//With router differing from logout one
+				if (($name = $route['_route']) == $logout) {
+					#throw new ResourceNotFoundException('Identical referer and logout route');
+					//Unset referer to fallback to default route
+					unset($referer);
+				//With route matching logout
+				} else {
+					//Remove route and controller from route defaults
+					unset($route['_route'], $route['_controller'], $route['_canonical_route']);
+
+					//Generate url
+					$url = $this->router->generate($name, $route);
+				}
+			//No route matched
+			} catch (ResourceNotFoundException $e) {
+				//Unset referer to fallback to default route
+				unset($referer);
+			}
+		}
+
+		//Referer empty or unusable
+		if (empty($referer)) {
+			//Try with / path
+			try {
+				//Retrieve route matching /
+				$route = $this->router->match('/');
+
+				//Verify that it differ from current one
+				if (($name = $route['_route']) == $logout) {
+					throw new ResourceNotFoundException('Identical referer and logout route');
+				}
+
+				//Remove route and controller from route defaults
+				unset($route['_route'], $route['_controller'], $route['_canonical_route']);
+
+				//Generate url
+				$url = $this->router->generate($name, $route);
+			//Get first route from route collection if / path was not matched
+			} catch (ResourceNotFoundException $e) {
+				//Fetch all routes
+				//XXX: this method regenerate the Routing cache making apps very slow
+				//XXX: see https://github.com/symfony/symfony-docs/issues/6710
+				//XXX: it should be fine to call it without referer and a / route
+				foreach ($this->router->getRouteCollection() as $name => $route) {
+					//Return on first public route excluding logout one
+					if (!empty($name) && $name[0] != '_' && $name != $logout) {
+						break;
+					}
+				}
+
+				//Bail out if no route found
+				if (!isset($name) || !isset($route)) {
+					throw new \RuntimeException('Unable to retrieve default route');
+				}
+
+				//Retrieve route defaults
+				$defaults = $route->getDefaults();
+
+				//Remove route and controller from route defaults
+				unset($defaults['_route'], $defaults['_controller'], $defaults['_canonical_route']);
+
+				//Generate url
+				$url = $this->router->generate($name, $defaults);
+			}
+		}
+
+		//Return redirect response
+		return new RedirectResponse($url, 302);
+	}
+}
-- 
2.41.3