From 0eb8e97d0d50ecd9c8702457529cbaec153f8244 Mon Sep 17 00:00:00 2001
From: Benjamin Mack <benni@typo3.org>
Date: Tue, 15 Sep 2015 18:01:36 +0200
Subject: [PATCH] [TASK] Have eIDs with PSR-7 without ControllerInterface

In order to allow the same logic as with the Routing and the
direct information which method to call, the ControllerInterface
is removed again.

Additionally, the previously introduced Dispatcher is now renamed
to RouteDispatcher (based on routing), and a simple dispatcher
is now added to EXT:core, which the RouteDispatcher derives from.

Resolves: #69846
Releases: master
Change-Id: Ica028f81aa377fd60e5159907c8c226fe0ebd34a
Reviewed-on: http://review.typo3.org/43352
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Georg Ringer <georg.ringer@gmail.com>
Tested-by: Georg Ringer <georg.ringer@gmail.com>
Reviewed-by: Mathias Schreiber <mathias.schreiber@wmdb.de>
Tested-by: Mathias Schreiber <mathias.schreiber@wmdb.de>
---
 .../backend/Classes/Http/RequestHandler.php   |  4 +-
 .../{Dispatcher.php => RouteDispatcher.php}   | 43 +---------
 .../Classes/Controller/FileDumpController.php | 13 +--
 .../core/Classes/Http/ControllerInterface.php | 37 ---------
 typo3/sysext/core/Classes/Http/Dispatcher.php | 82 +++++++++++++++++++
 ...IDsWithPSR-7WithoutControllerInterface.rst | 27 ++++++
 typo3/sysext/core/ext_localconf.php           |  2 +-
 .../Controller/ExtDirectEidController.php     |  6 +-
 .../Controller/ShowImageController.php        | 15 ++--
 .../Classes/Http/EidRequestHandler.php        | 20 +++--
 typo3/sysext/frontend/ext_localconf.php       |  4 +-
 .../RsaPublicKeyGenerationController.php      | 14 ++--
 typo3/sysext/rsaauth/ext_localconf.php        |  2 +-
 .../Controller/SpellCheckingController.php    | 14 ++--
 typo3/sysext/rtehtmlarea/ext_localconf.php    |  2 +-
 15 files changed, 159 insertions(+), 126 deletions(-)
 rename typo3/sysext/backend/Classes/Http/{Dispatcher.php => RouteDispatcher.php} (69%)
 delete mode 100644 typo3/sysext/core/Classes/Http/ControllerInterface.php
 create mode 100644 typo3/sysext/core/Classes/Http/Dispatcher.php
 create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Important-69846-HaveEIDsWithPSR-7WithoutControllerInterface.rst

diff --git a/typo3/sysext/backend/Classes/Http/RequestHandler.php b/typo3/sysext/backend/Classes/Http/RequestHandler.php
index c716f275847a..56f202aae55d 100644
--- a/typo3/sysext/backend/Classes/Http/RequestHandler.php
+++ b/typo3/sysext/backend/Classes/Http/RequestHandler.php
@@ -150,8 +150,8 @@ class RequestHandler implements RequestHandlerInterface {
 	protected function dispatch($request) {
 		/** @var Response $response */
 		$response = GeneralUtility::makeInstance(Response::class);
-		/** @var Dispatcher $dispatcher */
-		$dispatcher = GeneralUtility::makeInstance(Dispatcher::class);
+		/** @var RouteDispatcher $dispatcher */
+		$dispatcher = GeneralUtility::makeInstance(RouteDispatcher::class);
 		return $dispatcher->dispatch($request, $response);
 	}
 }
diff --git a/typo3/sysext/backend/Classes/Http/Dispatcher.php b/typo3/sysext/backend/Classes/Http/RouteDispatcher.php
similarity index 69%
rename from typo3/sysext/backend/Classes/Http/Dispatcher.php
rename to typo3/sysext/backend/Classes/Http/RouteDispatcher.php
index 4d54f1602645..98cf50e82b00 100644
--- a/typo3/sysext/backend/Classes/Http/Dispatcher.php
+++ b/typo3/sysext/backend/Classes/Http/RouteDispatcher.php
@@ -19,6 +19,7 @@ use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Routing\Router;
 use TYPO3\CMS\Backend\Routing\Route;
 use TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException;
+use TYPO3\CMS\Core\Http\Dispatcher;
 use TYPO3\CMS\Core\Http\DispatcherInterface;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
@@ -26,7 +27,7 @@ use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
 /**
  * Dispatcher which resolves a route to call a controller and method (but also a callable)
  */
-class Dispatcher implements DispatcherInterface {
+class RouteDispatcher extends Dispatcher implements DispatcherInterface {
 
 	/**
 	 * Main method to resolve the route and checks the target of the route, and tries to call it.
@@ -74,44 +75,4 @@ class Dispatcher implements DispatcherInterface {
 		$route = $request->getAttribute('route');
 		return ($route->getOption('access') === 'public' || $this->getFormProtection()->validateToken($token, 'route', $route->getOption('_identifier')));
 	}
-
-	/**
-	 * Creates a callable out of the given parameter, which can be a string, a callable / closure or an array
-	 * which can be handed to call_user_func_array()
-	 *
-	 * @param array|string|callable $target the target which is being resolved.
-	 * @return callable
-	 * @throws \InvalidArgumentException
-	 */
-	protected function getCallableFromTarget($target) {
-		if (is_array($target)) {
-			return $target;
-		}
-
-		if (is_object($target) && $target instanceof \Closure) {
-			return $target;
-		}
-
-		// Only a class name is given
-		if (is_string($target) && strpos($target, ':') === FALSE) {
-			$target = GeneralUtility::makeInstance($target);
-			if (method_exists($target, '__invoke')) {
-				return $target;
-			}
-		}
-
-		// Check if the target is a concatenated string of "className::actionMethod"
-		if (is_string($target) && strpos($target, '::') !== FALSE) {
-			list($className, $methodName) = explode('::', $target, 2);
-			$targetObject = GeneralUtility::makeInstance($className);
-			return [$targetObject, $methodName];
-		}
-
-		// This needs to be checked at last as a string with object::method is recognize as callable
-		if (is_callable($target)) {
-			return $target;
-		}
-
-		throw new \InvalidArgumentException('Invalid target for "' . $target. '", as it is not callable.', 1425381442);
-	}
 }
\ No newline at end of file
diff --git a/typo3/sysext/core/Classes/Controller/FileDumpController.php b/typo3/sysext/core/Classes/Controller/FileDumpController.php
index e5fc5bb03bdf..eea4e0b313b6 100644
--- a/typo3/sysext/core/Classes/Controller/FileDumpController.php
+++ b/typo3/sysext/core/Classes/Controller/FileDumpController.php
@@ -14,9 +14,8 @@ namespace TYPO3\CMS\Core\Controller;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
-use TYPO3\CMS\Core\Http\ControllerInterface;
-use TYPO3\CMS\Core\Http\Response;
 use TYPO3\CMS\Core\Resource\Hook\FileDumpEIDHookInterface;
 use TYPO3\CMS\Core\Resource\ProcessedFileRepository;
 use TYPO3\CMS\Core\Resource\ResourceFactory;
@@ -26,18 +25,21 @@ use TYPO3\CMS\Core\Utility\HttpUtility;
 /**
  * Class FileDumpController
  */
-class FileDumpController implements ControllerInterface {
+class FileDumpController {
 
 	/**
+	 * Main method to dump a file
+	 *
 	 * @param ServerRequestInterface $request
-	 * @return NULL|Response
+	 * @param ResponseInterface $response
+	 * @return NULL|ResponseInterface
 	 *
 	 * @throws \InvalidArgumentException
 	 * @throws \RuntimeException
 	 * @throws \TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException
 	 * @throws \UnexpectedValueException
 	 */
-	public function processRequest(ServerRequestInterface $request) {
+	public function dumpAction(ServerRequestInterface $request, ResponseInterface $response) {
 		$parameters = array('eID' => 'dumpFile');
 		$t = $this->getGetOrPost($request, 't');
 		if ($t) {
@@ -83,7 +85,6 @@ class FileDumpController implements ControllerInterface {
 			// @todo Refactor FAL to not echo directly, but to implement a stream for output here and use response
 			return NULL;
 		} else {
-			$response = GeneralUtility::makeInstance(Response::class);
 			return $response->withStatus(403);
 		}
 	}
diff --git a/typo3/sysext/core/Classes/Http/ControllerInterface.php b/typo3/sysext/core/Classes/Http/ControllerInterface.php
deleted file mode 100644
index 96564e42f4aa..000000000000
--- a/typo3/sysext/core/Classes/Http/ControllerInterface.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-namespace TYPO3\CMS\Core\Http;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
-
-/**
- * An interface every controller should implement
- * in order to deal with PSR-7 standard.
- *
- * @internal please note that this API will be extended until TYPO3 CMS 7 LTS and is not public yet.
- */
-interface ControllerInterface {
-
-	/**
-	 * Processes a typical request.
-	 *
-	 * @param ServerRequestInterface $request The request object
-	 * @return ResponseInterface The response, created by the controller
-	 * @api
-	 */
-	public function processRequest(ServerRequestInterface $request);
-
-}
diff --git a/typo3/sysext/core/Classes/Http/Dispatcher.php b/typo3/sysext/core/Classes/Http/Dispatcher.php
new file mode 100644
index 000000000000..c48072e249b6
--- /dev/null
+++ b/typo3/sysext/core/Classes/Http/Dispatcher.php
@@ -0,0 +1,82 @@
+<?php
+namespace TYPO3\CMS\Core\Http;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Dispatcher which resolves a target, which was given to the request to call a controller and method (but also a callable)
+ * where the request contains a "target" as attribute.
+ *
+ * Used in eID Frontend Requests, see EidRequestHandler
+ */
+class Dispatcher implements DispatcherInterface {
+
+	/**
+	 * Main method that fetches the target from the request and calls the target directly
+	 *
+	 * @param ServerRequestInterface $request the current server request
+	 * @param ResponseInterface $response the prepared response
+	 * @return ResponseInterface the filled response by the callable / controller/action
+	 * @throws \InvalidArgumentException if the defined target is invalid
+	 */
+	public function dispatch(ServerRequestInterface $request, ResponseInterface $response) {
+		$targetIdentifier = $request->getAttribute('target');
+		$target = $this->getCallableFromTarget($targetIdentifier);
+		return call_user_func_array($target, array($request, $response));
+	}
+
+	/**
+	 * Creates a callable out of the given parameter, which can be a string, a callable / closure or an array
+	 * which can be handed to call_user_func_array()
+	 *
+	 * @param array|string|callable $target the target which is being resolved.
+	 * @return callable
+	 * @throws \InvalidArgumentException
+	 */
+	protected function getCallableFromTarget($target) {
+		if (is_array($target)) {
+			return $target;
+		}
+
+		if (is_object($target) && $target instanceof \Closure) {
+			return $target;
+		}
+
+		// Only a class name is given
+		if (is_string($target) && strpos($target, ':') === FALSE) {
+			$target = GeneralUtility::makeInstance($target);
+			if (method_exists($target, '__invoke')) {
+				return $target;
+			}
+		}
+
+		// Check if the target is a concatenated string of "className::actionMethod"
+		if (is_string($target) && strpos($target, '::') !== FALSE) {
+			list($className, $methodName) = explode('::', $target, 2);
+			$targetObject = GeneralUtility::makeInstance($className);
+			return [$targetObject, $methodName];
+		}
+
+		// This needs to be checked at last as a string with object::method is recognize as callable
+		if (is_callable($target)) {
+			return $target;
+		}
+
+		throw new \InvalidArgumentException('Invalid target for "' . $target. '", as it is not callable.', 1425381442);
+	}
+}
\ No newline at end of file
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Important-69846-HaveEIDsWithPSR-7WithoutControllerInterface.rst b/typo3/sysext/core/Documentation/Changelog/master/Important-69846-HaveEIDsWithPSR-7WithoutControllerInterface.rst
new file mode 100644
index 000000000000..e101527b187c
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Important-69846-HaveEIDsWithPSR-7WithoutControllerInterface.rst
@@ -0,0 +1,27 @@
+====================================================================
+Important: #69846 - Have eIDs with PSR-7 without ControllerInterface
+====================================================================
+
+Description
+===========
+
+In order to allow the same logic as with the routing and the direct information which method to call, the
+ControllerInterface is not mandatory anymore.
+
+Remove the ``implements ControllerInterface`` instruction in the affected class. The former ``processRequest``
+method may be changed to:
+
+.. code-block:: php
+
+	public function anyMethodNameYouLike(ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response) {
+	}
+
+Please note that the ``$response`` object is now passed into the method directly, thus you must not create a new object
+by ``$response = GeneralUtility::makeInstance(Response::class);``
+
+The eID_include registration in :file:`ext_localconf.php` must be changed in such case to
+
+.. code-block:: php
+
+	$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['identifier'] = \Foo\Bar::class . '::anyMethodNameYouLike';
+
diff --git a/typo3/sysext/core/ext_localconf.php b/typo3/sysext/core/ext_localconf.php
index b128fa03bb97..f1354df7c8e7 100644
--- a/typo3/sysext/core/ext_localconf.php
+++ b/typo3/sysext/core/ext_localconf.php
@@ -71,7 +71,7 @@ $signalSlotDispatcher->connect(
 
 unset($signalSlotDispatcher);
 
-$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['dumpFile'] = \TYPO3\CMS\Core\Controller\FileDumpController::class;
+$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['dumpFile'] = \TYPO3\CMS\Core\Controller\FileDumpController::class . '::dumpAction';
 
 /** @var \TYPO3\CMS\Core\Resource\Rendering\RendererRegistry $rendererRegistry */
 $rendererRegistry = \TYPO3\CMS\Core\Resource\Rendering\RendererRegistry::getInstance();
diff --git a/typo3/sysext/frontend/Classes/Controller/ExtDirectEidController.php b/typo3/sysext/frontend/Classes/Controller/ExtDirectEidController.php
index a8badb581114..2b7036a7966c 100644
--- a/typo3/sysext/frontend/Classes/Controller/ExtDirectEidController.php
+++ b/typo3/sysext/frontend/Classes/Controller/ExtDirectEidController.php
@@ -16,7 +16,6 @@ namespace TYPO3\CMS\Frontend\Controller;
 
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
-use TYPO3\CMS\Core\Http\ControllerInterface;
 use TYPO3\CMS\Frontend\Utility\EidUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Http\AjaxRequestHandler;
@@ -24,7 +23,7 @@ use TYPO3\CMS\Core\Http\AjaxRequestHandler;
 /**
  * eID controller for ExtDirect
  */
-class ExtDirectEidController implements ControllerInterface {
+class ExtDirectEidController {
 
 	/**
 	 * Ajax Instance
@@ -52,10 +51,11 @@ class ExtDirectEidController implements ControllerInterface {
 	 * Renders/Echoes the ajax output
 	 *
 	 * @param ServerRequestInterface $request
+	 * @param ResponseInterface $response
 	 * @return ResponseInterface|NULL
 	 * @throws \InvalidArgumentException
 	 */
-	public function processRequest(ServerRequestInterface $request) {
+	public function processRequest(ServerRequestInterface $request, ResponseInterface $response) {
 		$action = isset($request->getParsedBody()['action'])
 			? $request->getParsedBody()['action']
 			: (isset($request->getQueryParams()['action']) ? $request->getQueryParams()['action'] : '');
diff --git a/typo3/sysext/frontend/Classes/Controller/ShowImageController.php b/typo3/sysext/frontend/Classes/Controller/ShowImageController.php
index 47e6afc97a13..7d5a3a9f50f6 100644
--- a/typo3/sysext/frontend/Classes/Controller/ShowImageController.php
+++ b/typo3/sysext/frontend/Classes/Controller/ShowImageController.php
@@ -15,9 +15,8 @@ namespace TYPO3\CMS\Frontend\Controller;
  */
 
 use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Message\ResponseInterface;
 use TYPO3\CMS\Core\Exception;
-use TYPO3\CMS\Core\Http\ControllerInterface;
-use TYPO3\CMS\Core\Http\Response;
 use TYPO3\CMS\Core\Resource\ResourceFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
@@ -35,7 +34,7 @@ use TYPO3\CMS\Core\Utility\MathUtility;
  *  - bodyTag
  *  - title
  */
-class ShowImageController implements ControllerInterface {
+class ShowImageController {
 
 	/**
 	 * @var \Psr\Http\Message\ServerRequestInterface
@@ -184,15 +183,13 @@ EOF;
 	/**
 	 * Fetches the content and builds a content file out of it
 	 *
-	 * @param \Psr\Http\Message\ServerRequestInterface $request
-	 * @return \Psr\Http\Message\ResponseInterface
+	 * @param ServerRequestInterface $request the current request object
+	 * @param ResponseInterface $response the available response
+	 * @return ResponseInterface the modified response
 	 */
-	public function processRequest(ServerRequestInterface $request) {
+	public function processRequest(ServerRequestInterface $request, ResponseInterface $response) {
 		$this->request = $request;
 
-		/** @var Response $response */
-		$response = GeneralUtility::makeInstance(Response::class);
-
 		try {
 			$this->initialize();
 			$this->main();
diff --git a/typo3/sysext/frontend/Classes/Http/EidRequestHandler.php b/typo3/sysext/frontend/Classes/Http/EidRequestHandler.php
index eb67627d839b..a0ec4ddbdd0a 100644
--- a/typo3/sysext/frontend/Classes/Http/EidRequestHandler.php
+++ b/typo3/sysext/frontend/Classes/Http/EidRequestHandler.php
@@ -16,7 +16,7 @@ namespace TYPO3\CMS\Frontend\Http;
 
 use TYPO3\CMS\Core\Core\Bootstrap;
 use TYPO3\CMS\Core\Exception;
-use TYPO3\CMS\Core\Http\ControllerInterface;
+use TYPO3\CMS\Core\Http\Dispatcher;
 use TYPO3\CMS\Core\Http\Response;
 use TYPO3\CMS\Core\TimeTracker\NullTimeTracker;
 use TYPO3\CMS\Core\TimeTracker\TimeTracker;
@@ -108,21 +108,25 @@ class EidRequestHandler implements RequestHandlerInterface {
 	 * @throws Exception
 	 */
 	protected function dispatch($request) {
+		/** @var Response $response */
+		$response = GeneralUtility::makeInstance(Response::class);
+
 		$eID = isset($request->getParsedBody()['eID'])
 			? $request->getParsedBody()['eID']
 			: (isset($request->getQueryParams()['eID']) ? $request->getQueryParams()['eID'] : '');
 
 		if (empty($eID) || !isset($GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include'][$eID])) {
-			return GeneralUtility::makeInstance(Response::class)->withStatus(404, 'eID not registered');
+			return $response->withStatus(404, 'eID not registered');
 		}
 
 		$configuration = $GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include'][$eID];
-		if (class_exists($configuration)) {
-			$controller = GeneralUtility::makeInstance($configuration);
-			if (!$controller instanceof ControllerInterface) {
-				throw new Exception('The provided eID class "' . $configuration . '" does not implement "ControllerInterface".', 1436909478);
-			}
-			return $controller->processRequest($request);
+
+		// Simple check to make sure that it's not an absolute file (to use the fallback)
+		if (strpos($configuration, '::') !== FALSE || is_callable($configuration)) {
+			/** @var Dispatcher $dispatcher */
+			$dispatcher = GeneralUtility::makeInstance(Dispatcher::class);
+			$request = $request->withAttribute('target', $configuration);
+			return $dispatcher->dispatch($request, $response);
 		}
 
 		$scriptPath = GeneralUtility::getFileAbsFileName($configuration);
diff --git a/typo3/sysext/frontend/ext_localconf.php b/typo3/sysext/frontend/ext_localconf.php
index c6ceb63ea6e0..e4e95b99c22d 100644
--- a/typo3/sysext/frontend/ext_localconf.php
+++ b/typo3/sysext/frontend/ext_localconf.php
@@ -36,9 +36,9 @@ $GLOBALS['TYPO3_CONF_VARS']['FE']['ContentObjects'] = array_merge($GLOBALS['TYPO
 if (TYPO3_MODE === 'FE') {
 
 	// Register eID provider for showpic
-	$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['tx_cms_showpic'] = \TYPO3\CMS\Frontend\Controller\ShowImageController::class;
+	$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['tx_cms_showpic'] = \TYPO3\CMS\Frontend\Controller\ShowImageController::class . '::processRequest';
 	// Register eID provider for ExtDirect for the frontend
-	$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['ExtDirect'] = \TYPO3\CMS\Frontend\Controller\ExtDirectEidController::class;
+	$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['ExtDirect'] = \TYPO3\CMS\Frontend\Controller\ExtDirectEidController::class . '::processRequest';
 
 }
 
diff --git a/typo3/sysext/rsaauth/Classes/Controller/RsaPublicKeyGenerationController.php b/typo3/sysext/rsaauth/Classes/Controller/RsaPublicKeyGenerationController.php
index 9818af1ff1d8..97c748d02395 100644
--- a/typo3/sysext/rsaauth/Classes/Controller/RsaPublicKeyGenerationController.php
+++ b/typo3/sysext/rsaauth/Classes/Controller/RsaPublicKeyGenerationController.php
@@ -14,25 +14,22 @@ namespace TYPO3\CMS\Rsaauth\Controller;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
-use TYPO3\CMS\Core\Http\ControllerInterface;
-use TYPO3\CMS\Core\Http\Response;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Rsaauth\Backend\BackendFactory;
 use TYPO3\CMS\Rsaauth\Storage\StorageFactory;
 
 /**
  * eID script "RsaPublicKeyGenerationController" to generate an rsa key
  */
-class RsaPublicKeyGenerationController implements ControllerInterface {
+class RsaPublicKeyGenerationController {
 
 	/**
 	 * @param ServerRequestInterface $request
-	 * @return Response
+	 * @param ResponseInterface $response
+	 * @return ResponseInterface
 	 */
-	public function processRequest(ServerRequestInterface $request) {
-		/** @var Response $response */
-		$response = GeneralUtility::makeInstance(Response::class);
+	public function processRequest(ServerRequestInterface $request, ResponseInterface $response) {
 		/** @var \TYPO3\CMS\Rsaauth\Backend\AbstractBackend $backend */
 		$backend = BackendFactory::getBackend();
 		if ($backend === NULL) {
@@ -46,7 +43,6 @@ class RsaPublicKeyGenerationController implements ControllerInterface {
 		session_commit();
 		$content = $keyPair->getPublicKeyModulus() . ':' . sprintf('%x', $keyPair->getExponent()) . ':';
 		$response->getBody()->write($content);
-
 		return $response;
 	}
 
diff --git a/typo3/sysext/rsaauth/ext_localconf.php b/typo3/sysext/rsaauth/ext_localconf.php
index 5539676f2201..ea7a75c4ea06 100644
--- a/typo3/sysext/rsaauth/ext_localconf.php
+++ b/typo3/sysext/rsaauth/ext_localconf.php
@@ -38,7 +38,7 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['displ
 );
 
 // eID for FrontendLoginRsaPublicKey
-$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['RsaPublicKeyGenerationController'] = \TYPO3\CMS\Rsaauth\Controller\RsaPublicKeyGenerationController::class;
+$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['RsaPublicKeyGenerationController'] = \TYPO3\CMS\Rsaauth\Controller\RsaPublicKeyGenerationController::class . '::processRequest';
 
 \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class)->connect(
 	\TYPO3\CMS\Backend\LoginProvider\UsernamePasswordLoginProvider::class,
diff --git a/typo3/sysext/rtehtmlarea/Classes/Controller/SpellCheckingController.php b/typo3/sysext/rtehtmlarea/Classes/Controller/SpellCheckingController.php
index dcf2789e26fb..107e7072d0f3 100644
--- a/typo3/sysext/rtehtmlarea/Classes/Controller/SpellCheckingController.php
+++ b/typo3/sysext/rtehtmlarea/Classes/Controller/SpellCheckingController.php
@@ -16,13 +16,13 @@ namespace TYPO3\CMS\Rtehtmlarea\Controller;
 
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
-use TYPO3\CMS\Core\Http\ControllerInterface;
+use TYPO3\CMS\Core\Http\Response;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * Spell checking plugin 'tx_rtehtmlarea_pi1' for the htmlArea RTE extension.
  */
-class SpellCheckingController implements ControllerInterface {
+class SpellCheckingController {
 
 	/**
 	 * @var \TYPO3\CMS\Core\Charset\CharsetConverter
@@ -153,20 +153,23 @@ class SpellCheckingController implements ControllerInterface {
 	 * @throws \UnexpectedValueException
 	 */
 	public function main(array $ajaxParams) {
-		$this->processRequest($ajaxParams['request']);
+		/** @var Response $response */
+		$response = GeneralUtility::makeInstance(Response::class);
+		$this->processRequest($ajaxParams['request'], $response);
 		header('Content-Type: text/html; charset=' . strtoupper($this->parserCharset));
 		echo $this->result;
 	}
 
 	/**
-	 * Main class of Spell Checker plugin for Typo3 CMS
+	 * Main class of Spell Checker plugin
 	 *
 	 * @param ServerRequestInterface $request
+	 * @param ResponseInterface $response
 	 * @return ResponseInterface
 	 * @throws \InvalidArgumentException
 	 * @throws \UnexpectedValueException
 	 */
-	public function processRequest(ServerRequestInterface $request) {
+	public function processRequest(ServerRequestInterface $request, ResponseInterface $response) {
 		$this->csConvObj = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Charset\CharsetConverter::class);
 		// Setting start time
 		$time_start = microtime(TRUE);
@@ -357,7 +360,6 @@ var selectedDictionary = "' . $this->dictionary . '";
 			$this->result .= '
 </body></html>';
 			// Outputting
-			$response = GeneralUtility::makeInstance(Response::class);
 			$response = $response->withHeader('Content-Type', 'text/html; charset=' . strtoupper($this->parserCharset));
 			$response->getBody()->write($this->result);
 			return $response;
diff --git a/typo3/sysext/rtehtmlarea/ext_localconf.php b/typo3/sysext/rtehtmlarea/ext_localconf.php
index af152fd720e9..0c15287cfb6f 100644
--- a/typo3/sysext/rtehtmlarea/ext_localconf.php
+++ b/typo3/sysext/rtehtmlarea/ext_localconf.php
@@ -157,7 +157,7 @@ $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rtehtmlarea']['plugins']['Language']['ob
 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rtehtmlarea']['plugins']['Language']['disableInFE'] = 0;
 
 // Spell checking configuration
-$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['rtehtmlarea_spellchecker'] = \TYPO3\CMS\Rtehtmlarea\Controller\SpellCheckingController::class;
+$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['rtehtmlarea_spellchecker'] = \TYPO3\CMS\Rtehtmlarea\Controller\SpellCheckingController::class . '::processRequest';
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::registerAjaxHandler('rtehtmlarea::spellchecker', \TYPO3\CMS\Rtehtmlarea\Controller\SpellCheckingController::class . '->main');
 
 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rtehtmlarea']['plugins']['SpellChecker'] = array();
-- 
GitLab