[TASK] Deprecate \TYPO3\CMS\Extbase\Mvc\Controller\AbstractController 62/62162/9
authorAlexander Schnitzler <git@alexanderschnitzler.de>
Wed, 30 Oct 2019 18:53:58 +0000 (19:53 +0100)
committerDaniel Goerz <daniel.goerz@posteo.de>
Sat, 9 Nov 2019 12:44:24 +0000 (13:44 +0100)
The AbstractController is an internal class which never
really had any functionality than to provide some basic
method for the ActionController.

If users implemented their own controllers and
extended the AbstractController directly, the further
execution led to an exception. Unless people used the
AbstractController and implemented the missing logic
of the ActionController themselves, they didn't have
a functional controller, therefore it's safe to assume
that nobody extends the AbstractController directly.

To be on the safe side however, the AbstractController
is properly deprecated and will not be removed until
TYPO3 11.0.

People are - and always have been - encouraged to
extend the ActionController.

Releases: master
Resolves: #89554
Change-Id: I86a45621f4d32249f94deec0d932a930d3a9824f
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/62162
Tested-by: Susanne Moog <look@susi.dev>
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Daniel Goerz <daniel.goerz@posteo.de>
Reviewed-by: Susanne Moog <look@susi.dev>
Reviewed-by: Daniel Goerz <daniel.goerz@posteo.de>
Build/Scripts/duplicateExceptionCodeCheck.sh
typo3/sysext/core/Documentation/Changelog/master/Deprecation-89554-DeprecateTYPO3CMSExtbaseMvcControllerAbstractController.rst [new file with mode: 0644]
typo3/sysext/extbase/Classes/Mvc/Controller/AbstractController.php
typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php
typo3/sysext/extbase/Configuration/Services.php
typo3/sysext/extbase/Tests/Unit/Mvc/Controller/AbstractControllerTest.php [deleted file]
typo3/sysext/extbase/Tests/UnitDeprecated/Mvc/Controller/AbstractControllerTest.php [new file with mode: 0644]
typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php
typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php

index c17536f..9fed53d 100755 (executable)
@@ -21,6 +21,10 @@ ignoreFiles+="sysext/form/Classes/Mvc/Property/Exception/TypeConverterException.
 ignoreFiles+="sysext/core/Classes/Database/Driver/PDOStatement.php"
 ignoreFiles+="sysext/core/Classes/Database/Driver/PDOConnection.php"
 
+# both ActionController and AbstractController throw the same exceptions
+# until AbstractController is removed
+ignoreFiles+="sysext/extbase/Classes/Mvc/Controller/AbstractController.php"
+
 foundNewFile=0
 oldFilename=""
 firstLineOfMatch=""
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-89554-DeprecateTYPO3CMSExtbaseMvcControllerAbstractController.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-89554-DeprecateTYPO3CMSExtbaseMvcControllerAbstractController.rst
new file mode 100644 (file)
index 0000000..c2a2157
--- /dev/null
@@ -0,0 +1,39 @@
+.. include:: ../../Includes.txt
+
+====================================================================================
+Deprecation: #89554 - Deprecate \TYPO3\CMS\Extbase\Mvc\Controller\AbstractController
+====================================================================================
+
+See :issue:`89554`
+
+Description
+===========
+
+The class :php:`\TYPO3\CMS\Extbase\Mvc\Controller\AbstractController` has been marked as deprecated.
+
+The :php:`AbstractController` is an internal class which never really had any functionality besides
+providing some basic methods for the :php:`\TYPO3\CMS\Extbase\Mvc\Controller\ActionController`. Therefore
+and in order to streamline the codebase of extbase, the :php:`AbstractController` will be removed
+with TYPO3 11.0.
+
+
+Impact
+======
+
+As all functionality of the :php:`AbstractController` has been moved to the :php:`ActionController` there is no impact
+for extbase extensions that used and extended the :php:`ActionController`.
+
+
+Affected Installations
+======================
+
+Installations that extended the :php:`AbstractController` directly.
+
+
+Migration
+=========
+
+Extend the :php:`ActionController`.
+
+
+.. index:: PHP-API, PartiallyScanned, ext:extbase
index cd4dbed..a0361f0 100644 (file)
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Extbase\Mvc\Controller;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait;
 use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
 use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
@@ -22,54 +23,74 @@ use TYPO3\CMS\Extbase\Mvc\Web\Request as WebRequest;
 
 /**
  * An abstract base class for Controllers
+ * @deprecated since TYPO3 10.2, will be removed in version 11.0
  */
 abstract class AbstractController implements ControllerInterface
 {
+    use PublicPropertyDeprecationTrait;
+
+    /**
+     * @var array
+     */
+    private $deprecatedPublicProperties = [
+        'signalSlotDispatcher' => 'Property ' . self::class . '::$signalSlotDispatcher is deprecated since TYPO3 10.2 and will be removed in TYPO3 11.0',
+        'objectManager' => 'Property ' . self::class . '::$objectManager is deprecated since TYPO3 10.2 and will be removed in TYPO3 11.0',
+        'uriBuilder' => 'Property ' . self::class . '::$uriBuilder is deprecated since TYPO3 10.2 and will be removed in TYPO3 11.0',
+        'settings' => 'Property ' . self::class . '::$settings is deprecated since TYPO3 10.2 and will be removed in TYPO3 11.0',
+        'request' => 'Property ' . self::class . '::$request is deprecated since TYPO3 10.2 and will be removed in TYPO3 11.0',
+        'response' => 'Property ' . self::class . '::$response is deprecated since TYPO3 10.2 and will be removed in TYPO3 11.0',
+        'arguments' => 'Property ' . self::class . '::$arguments is deprecated since TYPO3 10.2 and will be removed in TYPO3 11.0',
+        'validatorResolver' => 'Property ' . self::class . '::$validatorResolver is deprecated since TYPO3 10.2 and will be removed in TYPO3 11.0',
+        'supportedRequestTypes' => 'Property ' . self::class . '::$supportedRequestTypes is deprecated since TYPO3 10.2 and will be removed in TYPO3 11.0',
+        'controllerContext' => 'Property ' . self::class . '::$controllerContext is deprecated since TYPO3 10.2 and will be removed in TYPO3 11.0',
+        'configurationManager' => 'Property ' . self::class . '::$configurationManager is deprecated since TYPO3 10.2 and will be removed in TYPO3 11.0',
+    ];
+
     /**
      * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
      */
-    protected $signalSlotDispatcher;
+    private $signalSlotDispatcher;
 
     /**
      * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
      */
-    protected $objectManager;
+    private $objectManager;
 
     /**
      * @var \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder
      */
-    protected $uriBuilder;
+    private $uriBuilder;
 
     /**
      * Contains the settings of the current extension
      *
      * @var array
      */
-    protected $settings;
+    private $settings;
 
     /**
      * The current request.
      *
      * @var \TYPO3\CMS\Extbase\Mvc\RequestInterface
      */
-    protected $request;
+    private $request;
 
     /**
      * The response which will be returned by this action controller
      *
      * @var \TYPO3\CMS\Extbase\Mvc\ResponseInterface
      */
-    protected $response;
+    private $response;
 
     /**
      * @var \TYPO3\CMS\Extbase\Validation\ValidatorResolver
      */
-    protected $validatorResolver;
+    private $validatorResolver;
 
     /**
      * @var \TYPO3\CMS\Extbase\Mvc\Controller\Arguments Arguments passed to the controller
      */
-    protected $arguments;
+    private $arguments;
 
     /**
      * @param \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher
@@ -94,25 +115,30 @@ abstract class AbstractController implements ControllerInterface
      *
      * @var array
      */
-    protected $supportedRequestTypes = [\TYPO3\CMS\Extbase\Mvc\Request::class];
+    private $supportedRequestTypes = [\TYPO3\CMS\Extbase\Mvc\Request::class];
 
     /**
      * @var \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext
      */
-    protected $controllerContext;
+    private $controllerContext;
 
     /**
      * @return ControllerContext
      */
     public function getControllerContext()
     {
+        trigger_error(
+            __METHOD__ . ' is deprecated since TYPO3 10.2 and will be removed in version 11.0',
+            E_USER_DEPRECATED
+        );
+
         return $this->controllerContext;
     }
 
     /**
      * @var ConfigurationManagerInterface
      */
-    protected $configurationManager;
+    private $configurationManager;
 
     /**
      * @param ConfigurationManagerInterface $configurationManager
@@ -143,9 +169,15 @@ abstract class AbstractController implements ControllerInterface
      * @param bool $storeInSession Optional, defines whether the message should be stored in the session (default) or not
      * @throws \InvalidArgumentException if the message body is no string
      * @see \TYPO3\CMS\Core\Messaging\FlashMessage
+     * @deprecated since TYPO3 10.2 and will be removed in version 11.0
      */
     public function addFlashMessage($messageBody, $messageTitle = '', $severity = \TYPO3\CMS\Core\Messaging\AbstractMessage::OK, $storeInSession = true)
     {
+        trigger_error(
+            __METHOD__ . ' is deprecated since TYPO3 10.2 and will be removed in version 11.0',
+            E_USER_DEPRECATED
+        );
+
         if (!is_string($messageBody)) {
             throw new \InvalidArgumentException('The message body must be of type string, "' . gettype($messageBody) . '" given.', 1243258395);
         }
@@ -169,9 +201,15 @@ abstract class AbstractController implements ControllerInterface
      *
      * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The current request
      * @return bool TRUE if this request type is supported, otherwise FALSE
+     * @deprecated since TYPO3 10.2 and will be removed in version 11.0
      */
     public function canProcessRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request)
     {
+        trigger_error(
+            __METHOD__ . ' is deprecated since TYPO3 10.2 and will be removed in version 11.0',
+            E_USER_DEPRECATED
+        );
+
         foreach ($this->supportedRequestTypes as $supportedRequestType) {
             if ($request instanceof $supportedRequestType) {
                 return true;
@@ -186,9 +224,15 @@ abstract class AbstractController implements ControllerInterface
      * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The request object
      * @param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response The response, modified by this handler
      * @throws UnsupportedRequestTypeException if the controller doesn't support the current request type
+     * @deprecated since TYPO3 10.2 and will be removed in version 11.0
      */
     public function processRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response)
     {
+        trigger_error(
+            __METHOD__ . ' is deprecated since TYPO3 10.2 and will be removed in version 11.0',
+            E_USER_DEPRECATED
+        );
+
         if (!$this->canProcessRequest($request)) {
             throw new UnsupportedRequestTypeException(static::class . ' does not support requests of type "' . get_class($request) . '". Supported types are: ' . implode(' ', $this->supportedRequestTypes), 1187701132);
         }
@@ -209,9 +253,15 @@ abstract class AbstractController implements ControllerInterface
      * Initialize the controller context
      *
      * @return \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext ControllerContext to be passed to the view
+     * @deprecated since TYPO3 10.2 and will be removed in version 11.0
      */
     protected function buildControllerContext()
     {
+        trigger_error(
+            __METHOD__ . ' is deprecated since TYPO3 10.2 and will be removed in version 11.0',
+            E_USER_DEPRECATED
+        );
+
         /** @var \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext $controllerContext */
         $controllerContext = $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext::class);
         $controllerContext->setRequest($this->request);
@@ -236,9 +286,15 @@ abstract class AbstractController implements ControllerInterface
      * @param array|null $arguments Arguments to pass to the target action
      * @throws StopActionException
      * @see redirect()
+     * @deprecated since TYPO3 10.2 and will be removed in version 11.0
      */
     public function forward($actionName, $controllerName = null, $extensionName = null, array $arguments = null)
     {
+        trigger_error(
+            __METHOD__ . ' is deprecated since TYPO3 10.2 and will be removed in version 11.0',
+            E_USER_DEPRECATED
+        );
+
         $this->request->setDispatched(false);
         if ($this->request instanceof WebRequest) {
             $this->request->setControllerActionName($actionName);
@@ -273,9 +329,15 @@ abstract class AbstractController implements ControllerInterface
      * @throws UnsupportedRequestTypeException If the request is not a web request
      * @throws StopActionException
      * @see forward()
+     * @deprecated since TYPO3 10.2 and will be removed in version 11.0
      */
     protected function redirect($actionName, $controllerName = null, $extensionName = null, array $arguments = null, $pageUid = null, $delay = 0, $statusCode = 303)
     {
+        trigger_error(
+            __METHOD__ . ' is deprecated since TYPO3 10.2 and will be removed in version 11.0',
+            E_USER_DEPRECATED
+        );
+
         if (!$this->request instanceof WebRequest) {
             throw new UnsupportedRequestTypeException('redirect() only supports web requests.', 1220539734);
         }
@@ -303,9 +365,15 @@ abstract class AbstractController implements ControllerInterface
      * @param int $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other
      * @throws UnsupportedRequestTypeException If the request is not a web request
      * @throws StopActionException
+     * @deprecated since TYPO3 10.2 and will be removed in version 11.0
      */
     protected function redirectToUri($uri, $delay = 0, $statusCode = 303)
     {
+        trigger_error(
+            __METHOD__ . ' is deprecated since TYPO3 10.2 and will be removed in version 11.0',
+            E_USER_DEPRECATED
+        );
+
         if (!$this->request instanceof WebRequest) {
             throw new UnsupportedRequestTypeException('redirect() only supports web requests.', 1220539735);
         }
@@ -335,9 +403,15 @@ abstract class AbstractController implements ControllerInterface
      *
      * @param string $uri The URI
      * @return string
+     * @deprecated since TYPO3 10.2 and will be removed in version 11.0
      */
     protected function addBaseUriIfNecessary($uri)
     {
+        trigger_error(
+            __METHOD__ . ' is deprecated since TYPO3 10.2 and will be removed in version 11.0',
+            E_USER_DEPRECATED
+        );
+
         return \TYPO3\CMS\Core\Utility\GeneralUtility::locationHeaderUrl((string)$uri);
     }
 
@@ -351,9 +425,15 @@ abstract class AbstractController implements ControllerInterface
      * @param string $content Body content which further explains the status
      * @throws UnsupportedRequestTypeException If the request is not a web request
      * @throws StopActionException
+     * @deprecated since TYPO3 10.2 and will be removed in version 11.0
      */
     public function throwStatus($statusCode, $statusMessage = null, $content = null)
     {
+        trigger_error(
+            __METHOD__ . ' is deprecated since TYPO3 10.2 and will be removed in version 11.0',
+            E_USER_DEPRECATED
+        );
+
         if (!$this->request instanceof WebRequest) {
             throw new UnsupportedRequestTypeException('throwStatus() only supports web requests.', 1220539739);
         }
@@ -370,9 +450,15 @@ abstract class AbstractController implements ControllerInterface
     /**
      * Collects the base validators which were defined for the data type of each
      * controller argument and adds them to the argument's validator chain.
+     * @deprecated since TYPO3 10.2 and will be removed in version 11.0
      */
     public function initializeControllerArgumentsBaseValidators()
     {
+        trigger_error(
+            __METHOD__ . ' is deprecated since TYPO3 10.2 and will be removed in version 11.0',
+            E_USER_DEPRECATED
+        );
+
         /** @var \TYPO3\CMS\Extbase\Mvc\Controller\Argument $argument */
         foreach ($this->arguments as $argument) {
             $validator = $this->validatorResolver->getBaseValidatorConjunction($argument->getDataType());
@@ -386,9 +472,15 @@ abstract class AbstractController implements ControllerInterface
      * Maps arguments delivered by the request object to the local controller arguments.
      *
      * @throws Exception\RequiredArgumentMissingException
+     * @deprecated since TYPO3 10.2 and will be removed in version 11.0
      */
     protected function mapRequestArgumentsToControllerArguments()
     {
+        trigger_error(
+            __METHOD__ . ' is deprecated since TYPO3 10.2 and will be removed in version 11.0',
+            E_USER_DEPRECATED
+        );
+
         /** @var \TYPO3\CMS\Extbase\Mvc\Controller\Argument $argument */
         foreach ($this->arguments as $argument) {
             $argumentName = $argument->getName();
index dc45aef..20acfbf 100644 (file)
@@ -17,8 +17,10 @@ namespace TYPO3\CMS\Extbase\Mvc\Controller;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
 use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
+use TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException;
 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
 use TYPO3\CMS\Extbase\Mvc\Web\ReferringRequest;
 use TYPO3\CMS\Extbase\Mvc\Web\Request as WebRequest;
@@ -30,7 +32,7 @@ use TYPO3Fluid\Fluid\View\TemplateView;
 /**
  * A multi action controller. This is by far the most common base class for Controllers.
  */
-class ActionController extends AbstractController
+class ActionController implements ControllerInterface
 {
     /**
      * @var \TYPO3\CMS\Extbase\Reflection\ReflectionService
@@ -572,4 +574,340 @@ class ActionController extends AbstractController
         $outputMessage = 'Validation failed while trying to call ' . static::class . '->' . $this->actionMethodName . '().' . PHP_EOL;
         return $outputMessage;
     }
+
+    /**
+     * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
+     */
+    protected $signalSlotDispatcher;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
+     */
+    protected $objectManager;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder
+     */
+    protected $uriBuilder;
+
+    /**
+     * Contains the settings of the current extension
+     *
+     * @var array
+     */
+    protected $settings;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Validation\ValidatorResolver
+     */
+    protected $validatorResolver;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Mvc\Controller\Arguments Arguments passed to the controller
+     */
+    protected $arguments;
+
+    /**
+     * @param \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher
+     */
+    public function injectSignalSlotDispatcher(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher)
+    {
+        $this->signalSlotDispatcher = $signalSlotDispatcher;
+    }
+
+    /**
+     * @param \TYPO3\CMS\Extbase\Validation\ValidatorResolver $validatorResolver
+     */
+    public function injectValidatorResolver(\TYPO3\CMS\Extbase\Validation\ValidatorResolver $validatorResolver)
+    {
+        $this->validatorResolver = $validatorResolver;
+    }
+
+    /**
+     * An array of supported request types. By default only web requests are supported.
+     * Modify or replace this array if your specific controller supports certain
+     * (additional) request types.
+     *
+     * @var array
+     */
+    protected $supportedRequestTypes = [\TYPO3\CMS\Extbase\Mvc\Request::class];
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext
+     */
+    protected $controllerContext;
+
+    /**
+     * @return ControllerContext
+     */
+    public function getControllerContext()
+    {
+        return $this->controllerContext;
+    }
+
+    /**
+     * @var ConfigurationManagerInterface
+     */
+    protected $configurationManager;
+
+    /**
+     * @param ConfigurationManagerInterface $configurationManager
+     */
+    public function injectConfigurationManager(ConfigurationManagerInterface $configurationManager)
+    {
+        $this->configurationManager = $configurationManager;
+        $this->settings = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS);
+    }
+
+    /**
+     * Injects the object manager
+     *
+     * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
+     */
+    public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
+    {
+        $this->objectManager = $objectManager;
+        $this->arguments = $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Controller\Arguments::class);
+    }
+
+    /**
+     * Creates a Message object and adds it to the FlashMessageQueue.
+     *
+     * @param string $messageBody The message
+     * @param string $messageTitle Optional message title
+     * @param int $severity Optional severity, must be one of \TYPO3\CMS\Core\Messaging\FlashMessage constants
+     * @param bool $storeInSession Optional, defines whether the message should be stored in the session (default) or not
+     * @throws \InvalidArgumentException if the message body is no string
+     * @see \TYPO3\CMS\Core\Messaging\FlashMessage
+     */
+    public function addFlashMessage($messageBody, $messageTitle = '', $severity = \TYPO3\CMS\Core\Messaging\AbstractMessage::OK, $storeInSession = true)
+    {
+        if (!is_string($messageBody)) {
+            throw new \InvalidArgumentException('The message body must be of type string, "' . gettype($messageBody) . '" given.', 1243258395);
+        }
+        /* @var \TYPO3\CMS\Core\Messaging\FlashMessage $flashMessage */
+        $flashMessage = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
+            \TYPO3\CMS\Core\Messaging\FlashMessage::class,
+            (string)$messageBody,
+            (string)$messageTitle,
+            $severity,
+            $storeInSession
+        );
+        $this->controllerContext->getFlashMessageQueue()->enqueue($flashMessage);
+    }
+
+    /**
+     * Checks if the current request type is supported by the controller.
+     *
+     * If your controller only supports certain request types, either
+     * replace / modify the supportedRequestTypes property or override this
+     * method.
+     *
+     * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The current request
+     * @return bool TRUE if this request type is supported, otherwise FALSE
+     */
+    public function canProcessRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request)
+    {
+        foreach ($this->supportedRequestTypes as $supportedRequestType) {
+            if ($request instanceof $supportedRequestType) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Initialize the controller context
+     *
+     * @return \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext ControllerContext to be passed to the view
+     */
+    protected function buildControllerContext()
+    {
+        /** @var \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext $controllerContext */
+        $controllerContext = $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext::class);
+        $controllerContext->setRequest($this->request);
+        $controllerContext->setResponse($this->response);
+        if ($this->arguments !== null) {
+            $controllerContext->setArguments($this->arguments);
+        }
+        $controllerContext->setUriBuilder($this->uriBuilder);
+
+        return $controllerContext;
+    }
+
+    /**
+     * Forwards the request to another action and / or controller.
+     *
+     * Request is directly transferred to the other action / controller
+     * without the need for a new request.
+     *
+     * @param string $actionName Name of the action to forward to
+     * @param string|null $controllerName Unqualified object name of the controller to forward to. If not specified, the current controller is used.
+     * @param string|null $extensionName Name of the extension containing the controller to forward to. If not specified, the current extension is assumed.
+     * @param array|null $arguments Arguments to pass to the target action
+     * @throws StopActionException
+     * @see redirect()
+     */
+    public function forward($actionName, $controllerName = null, $extensionName = null, array $arguments = null)
+    {
+        $this->request->setDispatched(false);
+        if ($this->request instanceof WebRequest) {
+            $this->request->setControllerActionName($actionName);
+            if ($controllerName !== null) {
+                $this->request->setControllerName($controllerName);
+            }
+            if ($extensionName !== null) {
+                $this->request->setControllerExtensionName($extensionName);
+            }
+        }
+        if ($arguments !== null) {
+            $this->request->setArguments($arguments);
+        }
+        throw new StopActionException('forward', 1476045801);
+    }
+
+    /**
+     * Redirects the request to another action and / or controller.
+     *
+     * Redirect will be sent to the client which then performs another request to the new URI.
+     *
+     * NOTE: This method only supports web requests and will thrown an exception
+     * if used with other request types.
+     *
+     * @param string $actionName Name of the action to forward to
+     * @param string|null $controllerName Unqualified object name of the controller to forward to. If not specified, the current controller is used.
+     * @param string|null $extensionName Name of the extension containing the controller to forward to. If not specified, the current extension is assumed.
+     * @param array|null $arguments Arguments to pass to the target action
+     * @param int|null $pageUid Target page uid. If NULL, the current page uid is used
+     * @param int $delay (optional) The delay in seconds. Default is no delay.
+     * @param int $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other
+     * @throws UnsupportedRequestTypeException If the request is not a web request
+     * @throws StopActionException
+     * @see forward()
+     */
+    protected function redirect($actionName, $controllerName = null, $extensionName = null, array $arguments = null, $pageUid = null, $delay = 0, $statusCode = 303)
+    {
+        if (!$this->request instanceof WebRequest) {
+            throw new UnsupportedRequestTypeException('redirect() only supports web requests.', 1220539734);
+        }
+        if ($controllerName === null) {
+            $controllerName = $this->request->getControllerName();
+        }
+        $this->uriBuilder->reset()->setCreateAbsoluteUri(true);
+        if (MathUtility::canBeInterpretedAsInteger($pageUid)) {
+            $this->uriBuilder->setTargetPageUid((int)$pageUid);
+        }
+        if (\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_SSL')) {
+            $this->uriBuilder->setAbsoluteUriScheme('https');
+        }
+        $uri = $this->uriBuilder->uriFor($actionName, $arguments, $controllerName, $extensionName);
+        $this->redirectToUri($uri, $delay, $statusCode);
+    }
+
+    /**
+     * Redirects the web request to another uri.
+     *
+     * NOTE: This method only supports web requests and will thrown an exception if used with other request types.
+     *
+     * @param mixed $uri A string representation of a URI
+     * @param int $delay (optional) The delay in seconds. Default is no delay.
+     * @param int $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other
+     * @throws UnsupportedRequestTypeException If the request is not a web request
+     * @throws StopActionException
+     */
+    protected function redirectToUri($uri, $delay = 0, $statusCode = 303)
+    {
+        if (!$this->request instanceof WebRequest) {
+            throw new UnsupportedRequestTypeException('redirect() only supports web requests.', 1220539735);
+        }
+
+        $this->objectManager->get(\TYPO3\CMS\Extbase\Service\CacheService::class)->clearCachesOfRegisteredPageIds();
+
+        $uri = $this->addBaseUriIfNecessary($uri);
+        $escapedUri = htmlentities($uri, ENT_QUOTES, 'utf-8');
+        $this->response->setContent('<html><head><meta http-equiv="refresh" content="' . (int)$delay . ';url=' . $escapedUri . '"/></head></html>');
+        if ($this->response instanceof \TYPO3\CMS\Extbase\Mvc\Web\Response) {
+            $this->response->setStatus($statusCode);
+            $this->response->setHeader('Location', (string)$uri);
+        }
+        // Avoid caching the plugin when we issue a redirect response
+        // This means that even when an action is configured as cachable
+        // we avoid the plugin to be cached, but keep the page cache untouched
+        $contentObject = $this->configurationManager->getContentObject();
+        if ($contentObject->getUserObjectType() === \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::OBJECTTYPE_USER) {
+            $contentObject->convertToUserIntObject();
+        }
+
+        throw new StopActionException('redirectToUri', 1476045828);
+    }
+
+    /**
+     * Adds the base uri if not already in place.
+     *
+     * @param string $uri The URI
+     * @return string
+     */
+    protected function addBaseUriIfNecessary($uri)
+    {
+        return \TYPO3\CMS\Core\Utility\GeneralUtility::locationHeaderUrl((string)$uri);
+    }
+
+    /**
+     * Sends the specified HTTP status immediately.
+     *
+     * NOTE: This method only supports web requests and will thrown an exception if used with other request types.
+     *
+     * @param int $statusCode The HTTP status code
+     * @param string $statusMessage A custom HTTP status message
+     * @param string $content Body content which further explains the status
+     * @throws UnsupportedRequestTypeException If the request is not a web request
+     * @throws StopActionException
+     */
+    public function throwStatus($statusCode, $statusMessage = null, $content = null)
+    {
+        if (!$this->request instanceof WebRequest) {
+            throw new UnsupportedRequestTypeException('throwStatus() only supports web requests.', 1220539739);
+        }
+        if ($this->response instanceof \TYPO3\CMS\Extbase\Mvc\Web\Response) {
+            $this->response->setStatus($statusCode, $statusMessage);
+            if ($content === null) {
+                $content = $this->response->getStatus();
+            }
+        }
+        $this->response->setContent($content);
+        throw new StopActionException('throwStatus', 1476045871);
+    }
+
+    /**
+     * Collects the base validators which were defined for the data type of each
+     * controller argument and adds them to the argument's validator chain.
+     */
+    public function initializeControllerArgumentsBaseValidators()
+    {
+        /** @var \TYPO3\CMS\Extbase\Mvc\Controller\Argument $argument */
+        foreach ($this->arguments as $argument) {
+            $validator = $this->validatorResolver->getBaseValidatorConjunction($argument->getDataType());
+            if ($validator !== null) {
+                $argument->setValidator($validator);
+            }
+        }
+    }
+
+    /**
+     * Maps arguments delivered by the request object to the local controller arguments.
+     *
+     * @throws Exception\RequiredArgumentMissingException
+     */
+    protected function mapRequestArgumentsToControllerArguments()
+    {
+        /** @var \TYPO3\CMS\Extbase\Mvc\Controller\Argument $argument */
+        foreach ($this->arguments as $argument) {
+            $argumentName = $argument->getName();
+            if ($this->request->hasArgument($argumentName)) {
+                $argument->setValue($this->request->getArgument($argumentName));
+            } elseif ($argument->isRequired()) {
+                throw new \TYPO3\CMS\Extbase\Mvc\Controller\Exception\RequiredArgumentMissingException('Required argument "' . $argumentName . '" is not set for ' . $this->request->getControllerObjectName() . '->' . $this->request->getControllerActionName() . '.', 1298012500);
+            }
+        }
+    }
 }
index e35268c..79c9134 100644 (file)
@@ -10,6 +10,7 @@ return function (ContainerConfigurator $containerConfigurator, ContainerBuilder
     $container->registerForAutoconfiguration(Mvc\RequestHandlerInterface::class)->addTag('extbase.request_handler');
     $container->registerForAutoconfiguration(Mvc\Controller\ControllerInterface::class)->addTag('extbase.controller');
     $container->registerForAutoconfiguration(Mvc\Controller\AbstractController::class)->addTag('extbase.prototype_controller');
+    $container->registerForAutoconfiguration(Mvc\Controller\ActionController::class)->addTag('extbase.action_controller');
     $container->registerForAutoconfiguration(Mvc\View\ViewInterface::class)->addTag('extbase.view');
 
     $container->addCompilerPass(new class implements CompilerPassInterface {
@@ -24,6 +25,9 @@ return function (ContainerConfigurator $containerConfigurator, ContainerBuilder
             foreach ($container->findTaggedServiceIds('extbase.prototype_controller') as $id => $tags) {
                 $container->findDefinition($id)->setShared(false);
             }
+            foreach ($container->findTaggedServiceIds('extbase.action_controller') as $id => $tags) {
+                $container->findDefinition($id)->setShared(false);
+            }
             foreach ($container->findTaggedServiceIds('extbase.view') as $id => $tags) {
                 $container->findDefinition($id)->setShared(false)->setPublic(true);
             }
diff --git a/typo3/sysext/extbase/Tests/Unit/Mvc/Controller/AbstractControllerTest.php b/typo3/sysext/extbase/Tests/Unit/Mvc/Controller/AbstractControllerTest.php
deleted file mode 100644 (file)
index ec87946..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-<?php
-namespace TYPO3\CMS\Extbase\Tests\Unit\Mvc\Controller;
-
-/*
- * 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 TYPO3\TestingFramework\Core\Unit\UnitTestCase;
-
-/**
- * Test case
- */
-class AbstractControllerTest extends UnitTestCase
-{
-    /**
-     * @return array
-     */
-    public function addFlashMessageDataProvider()
-    {
-        return [
-            [
-                new \TYPO3\CMS\Core\Messaging\FlashMessage('Simple Message'),
-                'Simple Message',
-                '',
-                \TYPO3\CMS\Core\Messaging\FlashMessage::OK,
-                false
-            ],
-            [
-                new \TYPO3\CMS\Core\Messaging\FlashMessage('Some OK', 'Message Title', \TYPO3\CMS\Core\Messaging\FlashMessage::OK, true),
-                'Some OK',
-                'Message Title',
-                \TYPO3\CMS\Core\Messaging\FlashMessage::OK,
-                true
-            ],
-            [
-                new \TYPO3\CMS\Core\Messaging\FlashMessage('Some Info', 'Message Title', \TYPO3\CMS\Core\Messaging\FlashMessage::INFO, true),
-                'Some Info',
-                'Message Title',
-                \TYPO3\CMS\Core\Messaging\FlashMessage::INFO,
-                true
-            ],
-            [
-                new \TYPO3\CMS\Core\Messaging\FlashMessage('Some Notice', 'Message Title', \TYPO3\CMS\Core\Messaging\FlashMessage::NOTICE, true),
-                'Some Notice',
-                'Message Title',
-                \TYPO3\CMS\Core\Messaging\FlashMessage::NOTICE,
-                true
-            ],
-
-            [
-                new \TYPO3\CMS\Core\Messaging\FlashMessage('Some Warning', 'Message Title', \TYPO3\CMS\Core\Messaging\FlashMessage::WARNING, true),
-                'Some Warning',
-                'Message Title',
-                \TYPO3\CMS\Core\Messaging\FlashMessage::WARNING,
-                true
-            ],
-            [
-                new \TYPO3\CMS\Core\Messaging\FlashMessage('Some Error', 'Message Title', \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR, true),
-                'Some Error',
-                'Message Title',
-                \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR,
-                true
-            ]
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider addFlashMessageDataProvider
-     */
-    public function addFlashMessageAddsFlashMessageObjectToFlashMessageQueue($expectedMessage, $messageBody, $messageTitle = '', $severity = \TYPO3\CMS\Core\Messaging\FlashMessage::OK, $storeInSession = true)
-    {
-        $flashMessageQueue = $this->getMockBuilder(\TYPO3\CMS\Core\Messaging\FlashMessageQueue::class)
-            ->setMethods(['enqueue'])
-            ->setConstructorArgs([$this->getUniqueId('identifier_')])
-            ->getMock();
-
-        $flashMessageQueue->expects(self::once())->method('enqueue')->with(self::equalTo($expectedMessage));
-
-        $controllerContext = $this->getMockBuilder(\TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext::class)
-            ->setMethods(['getFlashMessageQueue'])
-            ->getMock();
-        $controllerContext->expects(self::once())->method('getFlashMessageQueue')->willReturn($flashMessageQueue);
-
-        $controller = $this->getMockForAbstractClass(
-            \TYPO3\CMS\Extbase\Mvc\Controller\AbstractController::class,
-            [],
-            '',
-            false,
-            true,
-            true,
-            ['dummy']
-        );
-        $this->inject($controller, 'controllerContext', $controllerContext);
-
-        $controller->addFlashMessage($messageBody, $messageTitle, $severity, $storeInSession);
-    }
-
-    /**
-     * @test
-     */
-    public function addFlashMessageThrowsExceptionOnInvalidMessageBody()
-    {
-        $this->expectException(\InvalidArgumentException::class);
-        $this->expectExceptionCode(1243258395);
-        $controller = $this->getMockForAbstractClass(
-            \TYPO3\CMS\Extbase\Mvc\Controller\AbstractController::class,
-            [],
-            '',
-            false,
-            true,
-            true,
-            ['dummy']
-        );
-
-        $controller->addFlashMessage(new \stdClass());
-    }
-}
diff --git a/typo3/sysext/extbase/Tests/UnitDeprecated/Mvc/Controller/AbstractControllerTest.php b/typo3/sysext/extbase/Tests/UnitDeprecated/Mvc/Controller/AbstractControllerTest.php
new file mode 100644 (file)
index 0000000..5036dc9
--- /dev/null
@@ -0,0 +1,127 @@
+<?php
+namespace TYPO3\CMS\Extbase\Tests\UnitDeprecated\Mvc\Controller;
+
+/*
+ * 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 TYPO3\TestingFramework\Core\Unit\UnitTestCase;
+
+/**
+ * Test case
+ */
+class AbstractControllerTest extends UnitTestCase
+{
+    /**
+     * @return array
+     */
+    public function addFlashMessageDataProvider()
+    {
+        return [
+            [
+                new \TYPO3\CMS\Core\Messaging\FlashMessage('Simple Message'),
+                'Simple Message',
+                '',
+                \TYPO3\CMS\Core\Messaging\FlashMessage::OK,
+                false
+            ],
+            [
+                new \TYPO3\CMS\Core\Messaging\FlashMessage('Some OK', 'Message Title', \TYPO3\CMS\Core\Messaging\FlashMessage::OK, true),
+                'Some OK',
+                'Message Title',
+                \TYPO3\CMS\Core\Messaging\FlashMessage::OK,
+                true
+            ],
+            [
+                new \TYPO3\CMS\Core\Messaging\FlashMessage('Some Info', 'Message Title', \TYPO3\CMS\Core\Messaging\FlashMessage::INFO, true),
+                'Some Info',
+                'Message Title',
+                \TYPO3\CMS\Core\Messaging\FlashMessage::INFO,
+                true
+            ],
+            [
+                new \TYPO3\CMS\Core\Messaging\FlashMessage('Some Notice', 'Message Title', \TYPO3\CMS\Core\Messaging\FlashMessage::NOTICE, true),
+                'Some Notice',
+                'Message Title',
+                \TYPO3\CMS\Core\Messaging\FlashMessage::NOTICE,
+                true
+            ],
+
+            [
+                new \TYPO3\CMS\Core\Messaging\FlashMessage('Some Warning', 'Message Title', \TYPO3\CMS\Core\Messaging\FlashMessage::WARNING, true),
+                'Some Warning',
+                'Message Title',
+                \TYPO3\CMS\Core\Messaging\FlashMessage::WARNING,
+                true
+            ],
+            [
+                new \TYPO3\CMS\Core\Messaging\FlashMessage('Some Error', 'Message Title', \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR, true),
+                'Some Error',
+                'Message Title',
+                \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR,
+                true
+            ]
+        ];
+    }
+
+    /**
+     * @test
+     * @dataProvider addFlashMessageDataProvider
+     */
+    public function addFlashMessageAddsFlashMessageObjectToFlashMessageQueue($expectedMessage, $messageBody, $messageTitle = '', $severity = \TYPO3\CMS\Core\Messaging\FlashMessage::OK, $storeInSession = true)
+    {
+        $flashMessageQueue = $this->getMockBuilder(\TYPO3\CMS\Core\Messaging\FlashMessageQueue::class)
+            ->setMethods(['enqueue'])
+            ->setConstructorArgs([$this->getUniqueId('identifier_')])
+            ->getMock();
+
+        $flashMessageQueue->expects(self::once())->method('enqueue')->with(self::equalTo($expectedMessage));
+
+        $controllerContext = $this->getMockBuilder(\TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext::class)
+            ->setMethods(['getFlashMessageQueue'])
+            ->getMock();
+        $controllerContext->expects(self::once())->method('getFlashMessageQueue')->willReturn($flashMessageQueue);
+
+        $controller = $this->getAccessibleMockForAbstractClass(
+            \TYPO3\CMS\Extbase\Mvc\Controller\AbstractController::class,
+            [],
+            '',
+            false,
+            true,
+            true,
+            ['dummy']
+        );
+        $controller->_set('controllerContext', $controllerContext);
+
+        $controller->addFlashMessage($messageBody, $messageTitle, $severity, $storeInSession);
+    }
+
+    /**
+     * @test
+     */
+    public function addFlashMessageThrowsExceptionOnInvalidMessageBody()
+    {
+        $this->expectException(\InvalidArgumentException::class);
+        $this->expectExceptionCode(1243258395);
+        $controller = $this->getMockForAbstractClass(
+            \TYPO3\CMS\Extbase\Mvc\Controller\AbstractController::class,
+            [],
+            '',
+            false,
+            true,
+            true,
+            ['dummy']
+        );
+
+        $controller->addFlashMessage(new \stdClass());
+    }
+}
index 264f0e4..b202bf7 100644 (file)
@@ -1332,4 +1332,9 @@ return [
             'Deprecation-89037-DeprecatedLocallangXmlParser.rst',
         ],
     ],
+    'TYPO3\CMS\Extbase\Mvc\Controller\AbstractController' => [
+        'restFiles' => [
+            'Deprecation-89554-DeprecateTYPO3CMSExtbaseMvcControllerAbstractController.rst',
+        ],
+    ]
 ];
index 1a2fefd..9c75c9d 100644 (file)
@@ -4287,4 +4287,88 @@ return [
             'Deprecation-89127-CleanupRecordHistoryHandling.rst',
         ],
     ],
+    'TYPO3\CMS\Extbase\Mvc\Controller\AbstractController->getControllerContext' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-89554-DeprecateTYPO3CMSExtbaseMvcControllerAbstractController.rst',
+        ],
+    ],
+    'TYPO3\CMS\Extbase\Mvc\Controller\AbstractController->addFlashMessage' => [
+        'numberOfMandatoryArguments' => 1,
+        'maximumNumberOfArguments' => 4,
+        'restFiles' => [
+            'Deprecation-89554-DeprecateTYPO3CMSExtbaseMvcControllerAbstractController.rst',
+        ],
+    ],
+    'TYPO3\CMS\Extbase\Mvc\Controller\AbstractController->canProcessRequest' => [
+        'numberOfMandatoryArguments' => 1,
+        'maximumNumberOfArguments' => 1,
+        'restFiles' => [
+            'Deprecation-89554-DeprecateTYPO3CMSExtbaseMvcControllerAbstractController.rst',
+        ],
+    ],
+    'TYPO3\CMS\Extbase\Mvc\Controller\AbstractController->processRequest' => [
+        'numberOfMandatoryArguments' => 2,
+        'maximumNumberOfArguments' => 2,
+        'restFiles' => [
+            'Deprecation-89554-DeprecateTYPO3CMSExtbaseMvcControllerAbstractController.rst',
+        ],
+    ],
+    'TYPO3\CMS\Extbase\Mvc\Controller\AbstractController->buildControllerContext' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-89554-DeprecateTYPO3CMSExtbaseMvcControllerAbstractController.rst',
+        ],
+    ],
+    'TYPO3\CMS\Extbase\Mvc\Controller\AbstractController->forward' => [
+        'numberOfMandatoryArguments' => 1,
+        'maximumNumberOfArguments' => 4,
+        'restFiles' => [
+            'Deprecation-89554-DeprecateTYPO3CMSExtbaseMvcControllerAbstractController.rst',
+        ],
+    ],
+    'TYPO3\CMS\Extbase\Mvc\Controller\AbstractController->redirect' => [
+        'numberOfMandatoryArguments' => 1,
+        'maximumNumberOfArguments' => 7,
+        'restFiles' => [
+            'Deprecation-89554-DeprecateTYPO3CMSExtbaseMvcControllerAbstractController.rst',
+        ],
+    ],
+    'TYPO3\CMS\Extbase\Mvc\Controller\AbstractController->redirectToUri' => [
+        'numberOfMandatoryArguments' => 1,
+        'maximumNumberOfArguments' => 3,
+        'restFiles' => [
+            'Deprecation-89554-DeprecateTYPO3CMSExtbaseMvcControllerAbstractController.rst',
+        ],
+    ],
+    'TYPO3\CMS\Extbase\Mvc\Controller\AbstractController->addBaseUriIfNecessary' => [
+        'numberOfMandatoryArguments' => 1,
+        'maximumNumberOfArguments' => 1,
+        'restFiles' => [
+            'Deprecation-89554-DeprecateTYPO3CMSExtbaseMvcControllerAbstractController.rst',
+        ],
+    ],
+    'TYPO3\CMS\Extbase\Mvc\Controller\AbstractController->throwStatus' => [
+        'numberOfMandatoryArguments' => 1,
+        'maximumNumberOfArguments' => 3,
+        'restFiles' => [
+            'Deprecation-89554-DeprecateTYPO3CMSExtbaseMvcControllerAbstractController.rst',
+        ],
+    ],
+    'TYPO3\CMS\Extbase\Mvc\Controller\AbstractController->initializeControllerArgumentsBaseValidators' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-89554-DeprecateTYPO3CMSExtbaseMvcControllerAbstractController.rst',
+        ],
+    ],
+    'TYPO3\CMS\Extbase\Mvc\Controller\AbstractController->mapRequestArgumentsToControllerArguments' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-89554-DeprecateTYPO3CMSExtbaseMvcControllerAbstractController.rst',
+        ],
+    ],
 ];