From c118510bd9ef75276d10e348b8fc944b6d612494 Mon Sep 17 00:00:00 2001 From: Christian Kuhn <lolli@schwarzbu.ch> Date: Thu, 26 Aug 2021 09:55:21 +0200 Subject: [PATCH] [TASK] Obsolete NotFoundView and deprecate canRender() Extbase ActionController has a view functionality to test if the target template files exist and to render an error message via NotFoundView if not. This is the only use of @internal marked NotFoundView and the only practical usage of extbase ViewInterface canRender(). This structure can be simplified significantly, without loosing functionality. The patch: * Removes @internal NotFoundView and its template * Drops canRender() from ViewInterface * Keeps canRender() in extbase ViewInterface implementations but marks them @deprecated and logs usages. * Changes extbase ActionController to not test canRender() but to let InvalidTemplateResourceException bubble up during $view->render(). This handling as a result - in case of missing templates - provides a full backtrace with a better error message than before, that of course still includes the controller and action name, plus the template location that has not been found. In the frontend, the exception is handled by the casual "plugin based exception handling" (TypoScript config.contentObjectExceptionHandler), a "template missing" programming error is now handled just like any other plugin exception. Resolves: #95003 Releases: master Change-Id: I5e55fdb2f1cfa66682b3b3a6ad0ebd21188dc10e Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/70762 Tested-by: core-ci <typo3@b13.com> Tested-by: Jochen <rothjochen@gmail.com> Tested-by: Wouter Wolters <typo3@wouterwolters.nl> Tested-by: Oliver Bartsch <bo@cedev.de> Tested-by: Christian Kuhn <lolli@schwarzbu.ch> Reviewed-by: Jochen <rothjochen@gmail.com> Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl> Reviewed-by: Oliver Bartsch <bo@cedev.de> Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch> --- .../Classes/View/BackendTemplateView.php | 7 +- ...on-95003-ExtbaseViewInterfaceCanRender.rst | 41 +++++ .../Mvc/Controller/ActionController.php | 9 - .../extbase/Classes/Mvc/View/AbstractView.php | 5 +- .../extbase/Classes/Mvc/View/EmptyView.php | 5 +- .../extbase/Classes/Mvc/View/JsonView.php | 5 +- .../extbase/Classes/Mvc/View/NotFoundView.php | 155 ------------------ .../Classes/Mvc/View/ViewInterface.php | 8 - .../Private/MVC/NotFoundView_Template.html | 2 - .../Mvc/Controller/ActionControllerTest.php | 6 +- .../Classes/View/AbstractTemplateView.php | 2 + .../fluid/Classes/View/TemplateView.php | 22 --- 12 files changed, 59 insertions(+), 208 deletions(-) create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Deprecation-95003-ExtbaseViewInterfaceCanRender.rst delete mode 100644 typo3/sysext/extbase/Classes/Mvc/View/NotFoundView.php delete mode 100644 typo3/sysext/extbase/Resources/Private/MVC/NotFoundView_Template.html diff --git a/typo3/sysext/backend/Classes/View/BackendTemplateView.php b/typo3/sysext/backend/Classes/View/BackendTemplateView.php index b97593a1169e..76831231c898 100644 --- a/typo3/sysext/backend/Classes/View/BackendTemplateView.php +++ b/typo3/sysext/backend/Classes/View/BackendTemplateView.php @@ -115,12 +115,13 @@ class BackendTemplateView implements ViewInterface /** * Checks whether a template can be resolved for the current request context. * - * @param ControllerContext $controllerContext Controller context which is available inside the view * @return bool + * @deprecated since TYPO3 v11, will be removed in v12. Legacy method, not part of ViewInterface anymore. */ - public function canRender(ControllerContext $controllerContext) + public function canRender() { - return $this->templateView->canRender($controllerContext); + // Deprecation logged by AbstractTemplateView + return $this->templateView->canRender(); } /** diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-95003-ExtbaseViewInterfaceCanRender.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-95003-ExtbaseViewInterfaceCanRender.rst new file mode 100644 index 000000000000..ef855c26b6db --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-95003-ExtbaseViewInterfaceCanRender.rst @@ -0,0 +1,41 @@ +.. include:: ../../Includes.txt + +======================================================= +Deprecation: #95003 - Extbase ViewInterface canRender() +======================================================= + +See :issue:`95003` + +Description +=========== + +To streamline and simplify fluid view related classes, the +extbase related :php:`TYPO3\CMS\Extbase\Mvc\View\ViewInterface` +method :php:`canRender()` has been dropped from the interface. + +Impact +====== + +The method should not be used anymore. Implementations in consuming +view classes are kept in v11 but have been marked as deprecated and +log a deprecation level error upon usage. + + +Affected Installations +====================== + +Method :php:`canRender()` had limited use within extbase, it is rather +unlikely many instances with extensions using the method exist. It's +purpose was to check for fluid template existence before calling +:php:`$view->render()`, but all existing view implementations throw an +exception during :php:`render()` if a template path can't be resolved. + + +Migration +========= + +Do not call :php:`canRender()` on template view instances, but let +:php:`render()` throw :php:`InvalidTemplateResourceException` on error +instead. + +.. index:: PHP-API, NotScanned, ext:extbase diff --git a/typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php b/typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php index 458e53945148..bb778448d7cf 100644 --- a/typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php +++ b/typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php @@ -42,7 +42,6 @@ use TYPO3\CMS\Extbase\Mvc\Request; use TYPO3\CMS\Extbase\Mvc\RequestInterface; use TYPO3\CMS\Extbase\Mvc\View\GenericViewResolver; use TYPO3\CMS\Extbase\Mvc\View\JsonView; -use TYPO3\CMS\Extbase\Mvc\View\NotFoundView; use TYPO3\CMS\Extbase\Mvc\View\ViewInterface; use TYPO3\CMS\Extbase\Mvc\View\ViewResolverInterface; use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder; @@ -621,14 +620,6 @@ abstract class ActionController implements ControllerInterface if ($view instanceof ViewInterface) { $this->setViewConfiguration($view); - if ($view->canRender($this->controllerContext) === false) { - $view = null; - } - } - if (!isset($view)) { - $view = GeneralUtility::makeInstance(NotFoundView::class); - $view->assign('errorMessage', 'No template was found. View could not be resolved for action "' - . $this->request->getControllerActionName() . '" in class "' . $this->request->getControllerObjectName() . '"'); } $view->setControllerContext($this->controllerContext); if (method_exists($view, 'injectSettings')) { diff --git a/typo3/sysext/extbase/Classes/Mvc/View/AbstractView.php b/typo3/sysext/extbase/Classes/Mvc/View/AbstractView.php index dc5819c9ad37..0df970c339e0 100644 --- a/typo3/sysext/extbase/Classes/Mvc/View/AbstractView.php +++ b/typo3/sysext/extbase/Classes/Mvc/View/AbstractView.php @@ -80,11 +80,12 @@ abstract class AbstractView implements ViewInterface * By default we assume that the view implementation can handle all kinds of * contexts. Override this method if that is not the case. * - * @param \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext $controllerContext * @return bool TRUE if the view has something useful to display, otherwise FALSE + * @deprecated since TYPO3 v11, will be removed in v12. Legacy method, not part of ViewInterface anymore. */ - public function canRender(ControllerContext $controllerContext) + public function canRender() { + trigger_error('Method ' . __METHOD__ . ' has been deprecated in v11 and will be removed with v12.', E_USER_DEPRECATED); return true; } diff --git a/typo3/sysext/extbase/Classes/Mvc/View/EmptyView.php b/typo3/sysext/extbase/Classes/Mvc/View/EmptyView.php index a980ecbe4334..87604ce20bd4 100644 --- a/typo3/sysext/extbase/Classes/Mvc/View/EmptyView.php +++ b/typo3/sysext/extbase/Classes/Mvc/View/EmptyView.php @@ -65,11 +65,12 @@ class EmptyView implements ViewInterface /** * This view can be used in any case. * - * @param \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext $controllerContext * @return bool TRUE + * @deprecated since TYPO3 v11, will be removed in v12. Legacy method, not part of ViewInterface anymore. */ - public function canRender(ControllerContext $controllerContext) + public function canRender() { + trigger_error('Method ' . __METHOD__ . ' has been deprecated in v11 and will be removed with v12.', E_USER_DEPRECATED); return true; } diff --git a/typo3/sysext/extbase/Classes/Mvc/View/JsonView.php b/typo3/sysext/extbase/Classes/Mvc/View/JsonView.php index 9408920d6f6a..46c64ca6c27f 100644 --- a/typo3/sysext/extbase/Classes/Mvc/View/JsonView.php +++ b/typo3/sysext/extbase/Classes/Mvc/View/JsonView.php @@ -225,11 +225,12 @@ class JsonView implements ViewInterface * By default we assume that the view implementation can handle all kinds of * contexts. Override this method if that is not the case. * - * @param ControllerContext $controllerContext * @return bool TRUE if the view has something useful to display, otherwise FALSE + * @deprecated since TYPO3 v11, will be removed in v12. Legacy method, not part of ViewInterface anymore. */ - public function canRender(ControllerContext $controllerContext) + public function canRender() { + trigger_error('Method ' . __METHOD__ . ' has been deprecated in v11 and will be removed with v12.', E_USER_DEPRECATED); return true; } diff --git a/typo3/sysext/extbase/Classes/Mvc/View/NotFoundView.php b/typo3/sysext/extbase/Classes/Mvc/View/NotFoundView.php deleted file mode 100644 index e29d0aab9476..000000000000 --- a/typo3/sysext/extbase/Classes/Mvc/View/NotFoundView.php +++ /dev/null @@ -1,155 +0,0 @@ -<?php - -/* - * 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! - */ - -namespace TYPO3\CMS\Extbase\Mvc\View; - -use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; -use TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext; -use TYPO3\CMS\Extbase\Mvc\Exception; -use TYPO3\CMS\Extbase\Mvc\Request; - -/** - * The not found view - a special case. - * @internal only to be used within Extbase, not part of TYPO3 Core API. - */ -class NotFoundView implements ViewInterface -{ - /** - * @var array - */ - protected $variablesMarker = ['errorMessage' => 'ERROR_MESSAGE']; - - /** - * @var ControllerContext - */ - protected $controllerContext; - - /** - * View variables and their values - * - * @var array - * @see assign() - */ - protected $variables = []; - - /** - * Renders the not found view - * - * @return string The rendered view - * @throws \TYPO3\CMS\Extbase\Mvc\Exception if no request has been set - */ - public function render() - { - if (!is_object($this->controllerContext->getRequest())) { - throw new Exception('Can\'t render view without request object.', 1192450280); - } - $template = file_get_contents($this->getTemplatePathAndFilename()); - $template = is_string($template) ? $template : ''; - if ($this->controllerContext->getRequest() instanceof Request) { - $template = str_replace('###BASEURI###', $this->controllerContext->getRequest()->getAttribute('normalizedParams')->getSiteUrl(), $template); - } - foreach ($this->variablesMarker as $variableName => $marker) { - $variableValue = $this->variables[$variableName] ?? ''; - $template = str_replace('###' . $marker . '###', $variableValue, $template); - } - return $template; - } - - /** - * Retrieves path and filename of the not-found-template - * - * @return string path and filename of the not-found-template - */ - protected function getTemplatePathAndFilename() - { - return ExtensionManagementUtility::extPath('extbase') . 'Resources/Private/MVC/NotFoundView_Template.html'; - } - - /** - * A magic call method. - * - * Because this not found view is used as a Special Case in situations when no matching - * view is available, it must be able to handle method calls which originally were - * directed to another type of view. This magic method should prevent PHP from issuing - * a fatal error. - * - * @param string $methodName - * @param array $arguments - */ - public function __call($methodName, array $arguments) - { - } - - /** - * Sets the current controller context - * - * @param ControllerContext $controllerContext - */ - public function setControllerContext(ControllerContext $controllerContext) - { - $this->controllerContext = $controllerContext; - } - - /** - * Add a variable to $this->viewData. - * Can be chained, so $this->view->assign(..., ...)->assign(..., ...); is possible - * - * @param string $key Key of variable - * @param mixed $value Value of object - * @return NotFoundView an instance of $this, to enable chaining - */ - public function assign($key, $value) - { - $this->variables[$key] = $value; - return $this; - } - - /** - * Add multiple variables to $this->viewData. - * - * @param array $values array in the format array(key1 => value1, key2 => value2). - * @return NotFoundView an instance of $this, to enable chaining - */ - public function assignMultiple(array $values) - { - foreach ($values as $key => $value) { - $this->assign($key, $value); - } - return $this; - } - - /** - * Tells if the view implementation can render the view for the given context. - * - * By default we assume that the view implementation can handle all kinds of - * contexts. Override this method if that is not the case. - * - * @param ControllerContext $controllerContext - * @return bool TRUE if the view has something useful to display, otherwise FALSE - */ - public function canRender(ControllerContext $controllerContext) - { - return true; - } - - /** - * Initializes this view. - * - * Override this method for initializing your concrete view implementation. - */ - public function initializeView() - { - } -} diff --git a/typo3/sysext/extbase/Classes/Mvc/View/ViewInterface.php b/typo3/sysext/extbase/Classes/Mvc/View/ViewInterface.php index 7abf65b11da8..7afa1b45c23b 100644 --- a/typo3/sysext/extbase/Classes/Mvc/View/ViewInterface.php +++ b/typo3/sysext/extbase/Classes/Mvc/View/ViewInterface.php @@ -48,14 +48,6 @@ interface ViewInterface */ public function assignMultiple(array $values); - /** - * Tells if the view implementation can render the view for the given context. - * - * @param ControllerContext $controllerContext - * @return bool TRUE if the view has something useful to display, otherwise FALSE - */ - public function canRender(ControllerContext $controllerContext); - /** * Renders the view * diff --git a/typo3/sysext/extbase/Resources/Private/MVC/NotFoundView_Template.html b/typo3/sysext/extbase/Resources/Private/MVC/NotFoundView_Template.html deleted file mode 100644 index dd2671a1f319..000000000000 --- a/typo3/sysext/extbase/Resources/Private/MVC/NotFoundView_Template.html +++ /dev/null @@ -1,2 +0,0 @@ -<p><strong>Sorry, the requested view was not found.</strong></p> -<p>The technical reason is: <em>###ERROR_MESSAGE###</em>.</p> diff --git a/typo3/sysext/extbase/Tests/Unit/Mvc/Controller/ActionControllerTest.php b/typo3/sysext/extbase/Tests/Unit/Mvc/Controller/ActionControllerTest.php index fc155eaa0a40..353760e9c2da 100644 --- a/typo3/sysext/extbase/Tests/Unit/Mvc/Controller/ActionControllerTest.php +++ b/typo3/sysext/extbase/Tests/Unit/Mvc/Controller/ActionControllerTest.php @@ -309,7 +309,7 @@ class ActionControllerTest extends UnitTestCase $mockController->injectConfigurationManager($mockConfigurationManager); $mockController->_set('request', $this->createMock(Request::class), ['getControllerExtensionKey']); $view = $this->getMockBuilder(ViewInterface::class) - ->onlyMethods(['setControllerContext', 'assign', 'assignMultiple', 'canRender', 'render', 'initializeView']) + ->onlyMethods(['setControllerContext', 'assign', 'assignMultiple', 'render', 'initializeView']) ->addMethods(['setTemplateRootPaths']) ->getMock(); $view->expects(self::once())->method('setTemplateRootPaths')->with($expected); @@ -388,7 +388,7 @@ class ActionControllerTest extends UnitTestCase $mockController->injectConfigurationManager($mockConfigurationManager); $mockController->_set('request', $this->createMock(Request::class), ['getControllerExtensionKey']); $view = $this->getMockBuilder(ViewInterface::class) - ->onlyMethods(['setControllerContext', 'assign', 'assignMultiple', 'canRender', 'render', 'initializeView']) + ->onlyMethods(['setControllerContext', 'assign', 'assignMultiple', 'render', 'initializeView']) ->addMethods(['setlayoutRootPaths']) ->getMock(); $view->expects(self::once())->method('setlayoutRootPaths')->with($expected); @@ -467,7 +467,7 @@ class ActionControllerTest extends UnitTestCase $mockController->injectConfigurationManager($mockConfigurationManager); $mockController->_set('request', $this->createMock(Request::class), ['getControllerExtensionKey']); $view = $this->getMockBuilder(ViewInterface::class) - ->onlyMethods(['setControllerContext', 'assign', 'assignMultiple', 'canRender', 'render', 'initializeView']) + ->onlyMethods(['setControllerContext', 'assign', 'assignMultiple', 'render', 'initializeView']) ->addMethods(['setpartialRootPaths']) ->getMock(); $view->expects(self::once())->method('setpartialRootPaths')->with($expected); diff --git a/typo3/sysext/fluid/Classes/View/AbstractTemplateView.php b/typo3/sysext/fluid/Classes/View/AbstractTemplateView.php index b34451946b11..95afa0c8b7fc 100644 --- a/typo3/sysext/fluid/Classes/View/AbstractTemplateView.php +++ b/typo3/sysext/fluid/Classes/View/AbstractTemplateView.php @@ -63,9 +63,11 @@ abstract class AbstractTemplateView extends Typo3FluidAbstractTemplateView imple * * @param \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext $controllerContext Controller context which is available inside the view * @return bool TRUE if the view has something useful to display, otherwise FALSE + * @deprecated since TYPO3 v11, will be removed in v12. Legacy method, not part of ViewInterface anymore. */ public function canRender(ControllerContext $controllerContext) { + trigger_error('Method ' . __METHOD__ . ' has been deprecated in v11 and will be removed with v12.', E_USER_DEPRECATED); return true; } diff --git a/typo3/sysext/fluid/Classes/View/TemplateView.php b/typo3/sysext/fluid/Classes/View/TemplateView.php index b2de145ba533..4f676e36293e 100644 --- a/typo3/sysext/fluid/Classes/View/TemplateView.php +++ b/typo3/sysext/fluid/Classes/View/TemplateView.php @@ -15,9 +15,6 @@ namespace TYPO3\CMS\Fluid\View; -use TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext; -use TYPO3Fluid\Fluid\View\Exception\InvalidTemplateResourceException; - /** * The main template view. Should be used as view if you want Fluid Templating */ @@ -32,23 +29,4 @@ class TemplateView extends AbstractTemplateView { $this->baseRenderingContext->getTemplatePaths()->setLayoutPathAndFilename($layoutPathAndFilename); } - - /** - * Checks whether a template can be resolved for the current request context. - * - * @param ControllerContext $controllerContext Controller context which is available inside the view - * @return bool - */ - public function canRender(ControllerContext $controllerContext) - { - try { - $request = $controllerContext->getRequest(); - $this->setControllerContext($controllerContext); - $this->baseRenderingContext->getTemplatePaths()->setFormat($request->getFormat()); - $this->baseRenderingContext->getTemplatePaths()->getTemplateSource($request->getControllerName(), $request->getControllerActionName()); - return true; - } catch (InvalidTemplateResourceException $e) { - return false; - } - } } -- GitLab