Skip to content

Commit

Permalink
[TASK] Deprecate extbase ViewInterface
Browse files Browse the repository at this point in the history
The extbase ViewInterface fits little purpose: Most
methods are part of the fluid based class and interface
chain, with the exception of setControllerContext(),
which is deprecated, and initializeView(), which is
always only implemented as empty method.

The patch deprecates the interface keeping its usage
in API classes to prevent compatibility issues and
prepares the interface removal for v12.

Change-Id: I012ad0307f7a40923a793f55b596a27e8b770bf4
Resolves: #95222
Releases: master
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/71089
Tested-by: Jochen <rothjochen@gmail.com>
Tested-by: Oliver Bartsch <bo@cedev.de>
Tested-by: core-ci <typo3@b13.com>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Jochen <rothjochen@gmail.com>
Reviewed-by: Oliver Bartsch <bo@cedev.de>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
  • Loading branch information
lolli42 committed Sep 16, 2021
1 parent 41c2801 commit f0f4604
Show file tree
Hide file tree
Showing 18 changed files with 147 additions and 75 deletions.
Expand Up @@ -35,7 +35,6 @@
use TYPO3\CMS\Core\Messaging\FlashMessageService;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
use TYPO3\CMS\Fluid\View\StandaloneView;

/**
Expand Down Expand Up @@ -122,7 +121,7 @@ public function handleRequest(ServerRequestInterface $request): ResponseInterfac
/**
* Setup the overview with all available MFA providers
*/
public function overviewAction(ServerRequestInterface $request, ViewInterface $view): ResponseInterface
public function overviewAction(ServerRequestInterface $request, StandaloneView $view): ResponseInterface
{
$this->addOverviewButtons($request);
$view->assignMultiple([
Expand All @@ -138,7 +137,7 @@ public function overviewAction(ServerRequestInterface $request, ViewInterface $v
/**
* Render form to setup a provider by using provider specific content
*/
public function setupAction(ServerRequestInterface $request, MfaProviderManifestInterface $mfaProvider, ViewInterface $view): ResponseInterface
public function setupAction(ServerRequestInterface $request, MfaProviderManifestInterface $mfaProvider, StandaloneView $view): ResponseInterface
{
$this->addFormButtons();
$propertyManager = MfaProviderPropertyManager::create($mfaProvider, $this->getBackendUser());
Expand Down Expand Up @@ -227,7 +226,7 @@ public function unlockAction(ServerRequestInterface $request, MfaProviderManifes
/**
* Render form to edit a provider by using provider specific content
*/
public function editAction(ServerRequestInterface $request, MfaProviderManifestInterface $mfaProvider, ViewInterface $view): ResponseInterface
public function editAction(ServerRequestInterface $request, MfaProviderManifestInterface $mfaProvider, StandaloneView $view): ResponseInterface
{
$propertyManager = MfaProviderPropertyManager::create($mfaProvider, $this->getBackendUser());
if ($mfaProvider->isLocked($propertyManager)) {
Expand Down Expand Up @@ -273,7 +272,7 @@ public function saveAction(ServerRequestInterface $request, MfaProviderManifestI
/**
* Initialize the standalone view and set the template name
*/
protected function initializeView(string $templateName): ViewInterface
protected function initializeView(string $templateName): StandaloneView
{
$view = GeneralUtility::makeInstance(StandaloneView::class);
$view->setTemplateRootPaths(['EXT:backend/Resources/Private/Templates/Mfa']);
Expand Down
Expand Up @@ -34,7 +34,7 @@
use TYPO3\CMS\Core\Localization\Locales;
use TYPO3\CMS\Core\Page\PageRenderer;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
use TYPO3\CMS\Fluid\View\StandaloneView;

/**
* Controller responsible for rendering and processing password reset requests
Expand All @@ -44,7 +44,7 @@
class ResetPasswordController
{
protected string $loginProvider = '';
protected ?ViewInterface $view = null;
protected ?StandaloneView $view = null;
protected ?ModuleTemplate $moduleTemplate = null;

protected Context $context;
Expand Down
4 changes: 3 additions & 1 deletion typo3/sysext/backend/Classes/View/BackendTemplateView.php
Expand Up @@ -132,7 +132,9 @@ public function canRender()
*/
public function initializeView()
{
$this->templateView->initializeView();
if (method_exists($this->templateView, 'initializeView')) {
$this->templateView->initializeView();
}
}

/**
Expand Down
Expand Up @@ -124,6 +124,7 @@ public function initializeAction(): void
/**
* Assign default variables to view
* @param ViewInterface $view
* @todo v12: Change signature to TYPO3Fluid\Fluid\View\ViewInterface when extbase ViewInterface is dropped.
*/
protected function initializeView(ViewInterface $view): void
{
Expand Down
Expand Up @@ -29,7 +29,6 @@
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Http\HtmlResponse;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
use TYPO3\CMS\Fluid\View\StandaloneView;

/**
Expand Down Expand Up @@ -258,11 +257,8 @@ public function handleRequest(
* Generate a new shared secret, generate the otpauth URL and create a qr-code
* for improved usability. Set template and assign necessary variables for the
* setup view.
*
* @param ViewInterface $view
* @param MfaProviderPropertyManager $propertyManager
*/
protected function prepareSetupView(ViewInterface $view, MfaProviderPropertyManager $propertyManager): void
protected function prepareSetupView(StandaloneView $view, MfaProviderPropertyManager $propertyManager): void
{
$userData = $propertyManager->getUser()->user ?? [];
$secret = Totp::generateEncodedSecret([(string)($userData['uid'] ?? ''), (string)($userData['username'] ?? '')]);
Expand All @@ -283,11 +279,8 @@ protected function prepareSetupView(ViewInterface $view, MfaProviderPropertyMana

/**
* Set the template and assign necessary variables for the edit view
*
* @param ViewInterface $view
* @param MfaProviderPropertyManager $propertyManager
*/
protected function prepareEditView(ViewInterface $view, MfaProviderPropertyManager $propertyManager): void
protected function prepareEditView(StandaloneView $view, MfaProviderPropertyManager $propertyManager): void
{
$view->setTemplate('Edit');
$view->assignMultiple([
Expand All @@ -299,11 +292,8 @@ protected function prepareEditView(ViewInterface $view, MfaProviderPropertyManag

/**
* Set the template for the auth view where the user has to provide the TOTP
*
* @param ViewInterface $view
* @param MfaProviderPropertyManager $propertyManager
*/
protected function prepareAuthView(ViewInterface $view, MfaProviderPropertyManager $propertyManager): void
protected function prepareAuthView(StandaloneView $view, MfaProviderPropertyManager $propertyManager): void
{
$view->setTemplate('Auth');
$view->assign('isLocked', $this->isLocked($propertyManager));
Expand Down
@@ -0,0 +1,56 @@
.. include:: ../../Includes.txt

===========================================
Deprecation: #95222 - Extbase ViewInterface
===========================================

See :issue:`95222`

Description
===========

To further streamline Fluid view related class inheritance and dependencies,
the interface :php:`TYPO3\CMS\Extbase\Mvc\View\ViewInterface` has been marked
as deprecated and will be removed in v12.


Impact
======

This deprecation has little impact on TYPO3 v11: The interface is kept and still
carried around in the core, no deprecation level log entry is raised.

The interface itself deviates from the casual view related classes only by requiring
an implementation of method :php:`initializeView()` which was never actively used,
calling that method will vanish in v12. The second deviation is method
:php:`setControllerContext()`, and class :php:`ControllerContext` is deprecated, too.


Affected Installations
======================

The extension scanner will find usages of extbase :php:`ViewInterface` as a strong match.


Migration
=========

Some instances may rely on extensions that type hint :php:`TYPO3\CMS\Extbase\Mvc\View\ViewInterface`,
especially in the extbase action controller method :php:`initializeView()`. The default
implementation of that method in :php:`TYPO3\CMS\Extbase\Mvc\Controller\ActionController` is
empty. To simplify compatibility for extensions supporting both v11 and v12,
that empty method will be removed in v12, but will still be called if it exists in classes
extending :php:`ActionController`.
Extension authors should thus avoid calling :php:`parent::initializeView($view)` in their
implementation of :php:`initializeView()` to prepare towards v12.

Apart from that, usages of :php:`TYPO3\CMS\Extbase\Mvc\View\ViewInterface` should be changed
to the more specific :php:`TYPO3\CMS\Fluid\View\StandaloneView` - usually in non-extbase
related classes, or to the less specific :php:`TYPO3Fluid\Fluid\View\ViewInterface`.

If using a custom view implementing :php:`TYPO3\CMS\Extbase\Mvc\View\ViewInterface`,
keep in mind that auto configuration based on the interface will be dropped in v12, you
may have to configure the service in :file:`Services.yaml` manually.


.. index:: Fluid, PHP-API, FullyScanned, ext:fluid
18 changes: 5 additions & 13 deletions typo3/sysext/dashboard/Classes/Controller/DashboardController.php
Expand Up @@ -35,24 +35,13 @@
use TYPO3\CMS\Dashboard\DashboardRepository;
use TYPO3\CMS\Dashboard\WidgetGroupInitializationService;
use TYPO3\CMS\Extbase\Mvc\Controller\Exception\RequiredArgumentMissingException;
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
use TYPO3\CMS\Fluid\View\StandaloneView;

/**
* @internal
*/
class DashboardController extends AbstractController
{
/**
* @var ModuleTemplate
*/
private $moduleTemplate;

/**
* @var ViewInterface
*/
protected $view;

protected PageRenderer $pageRenderer;
protected UriBuilder $uriBuilder;
protected Dashboard $currentDashboard;
Expand All @@ -62,6 +51,9 @@ class DashboardController extends AbstractController
protected WidgetGroupInitializationService $widgetGroupInitializationService;
protected ModuleTemplateFactory $moduleTemplateFactory;

private ?ModuleTemplate $moduleTemplate = null;
protected StandaloneView $view;

public function __construct(
PageRenderer $pageRenderer,
UriBuilder $uriBuilder,
Expand All @@ -82,6 +74,8 @@ public function __construct(
$this->widgetGroupInitializationService = $widgetGroupInitializationService;

$this->moduleTemplateFactory = $moduleTemplateFactory;

$this->view = GeneralUtility::makeInstance(StandaloneView::class);
}

/**
Expand Down Expand Up @@ -241,9 +235,7 @@ public function removeWidgetAction(ServerRequestInterface $request): ResponseInt
*/
protected function initializeView(string $templateName): void
{
$this->view = GeneralUtility::makeInstance(StandaloneView::class);
$this->view->setTemplate($templateName);

$this->view->getRenderingContext()->getTemplatePaths()->fillDefaultsByPackageName('dashboard');
$this->moduleTemplate->getDocHeaderComponent()->disable();
}
Expand Down
33 changes: 16 additions & 17 deletions typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php
Expand Up @@ -96,6 +96,7 @@ abstract class ActionController implements ControllerInterface
* The current view, as resolved by resolveView()
*
* @var ViewInterface
* @todo v12: Change signature to TYPO3Fluid\Fluid\View\ViewInterface when extbase ViewInterface is dropped.
*/
protected $view;

Expand Down Expand Up @@ -330,6 +331,7 @@ final public function injectInternalExtensionService(ExtensionService $extension
* or prepare the view in another way before the action is called.
*
* @param ViewInterface $view The view to be initialized
* @deprecated since v11, will be removed in v12: Drop method along with extbase ViewInterface.
*/
protected function initializeView(ViewInterface $view)
{
Expand Down Expand Up @@ -482,7 +484,7 @@ public function processRequest(RequestInterface $request): ResponseInterface
// @deprecated since v11, will be removed with v12.
$this->controllerContext = $this->buildControllerContext();
$this->view = $this->resolveView();
if ($this->view !== null) {
if ($this->view !== null && method_exists($this, 'initializeView')) {
$this->initializeView($this->view);
}
$response = $this->callActionMethod($request);
Expand Down Expand Up @@ -611,6 +613,7 @@ protected function callActionMethod(RequestInterface $request): ResponseInterfac
* By default, this method tries to locate a view with a name matching the current action.
*
* @return ViewInterface
* @todo v12: Change signature to TYPO3Fluid\Fluid\View\ViewInterface when extbase ViewInterface is dropped.
*
* @internal only to be used within Extbase, not part of TYPO3 Core API.
*/
Expand All @@ -631,15 +634,16 @@ protected function resolveView()
$this->request->getFormat()
);

if ($view instanceof ViewInterface) {
$this->setViewConfiguration($view);
}
$this->setViewConfiguration($view);
// @deprecated since v11, will be removed with v12.
$view->setControllerContext($this->controllerContext);
if (method_exists($view, 'injectSettings')) {
$view->injectSettings($this->settings);
}
$view->initializeView();
if (method_exists($view, 'initializeView')) {
// @deprecated since v11, will be removed with v12. Drop together with removal of extbase ViewInterface.
$view->initializeView();
}
// In TYPO3.Flow, solved through Object Lifecycle methods, we need to call it explicitly
$view->assign('settings', $this->settings);
// same with settings injection.
Expand All @@ -650,6 +654,7 @@ protected function resolveView()
* @param ViewInterface $view
*
* @internal only to be used within Extbase, not part of TYPO3 Core API.
* @todo v12: Change signature to TYPO3Fluid\Fluid\View\ViewInterface when extbase ViewInterface is dropped.
*/
protected function setViewConfiguration(ViewInterface $view)
{
Expand All @@ -658,36 +663,30 @@ protected function setViewConfiguration(ViewInterface $view)
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK
);

// set TemplateRootPaths
$viewFunctionName = 'setTemplateRootPaths';
if (method_exists($view, $viewFunctionName)) {
if (method_exists($view, 'setTemplateRootPaths')) {
$setting = 'templateRootPaths';
$parameter = $this->getViewProperty($extbaseFrameworkConfiguration, $setting);
// no need to bother if there is nothing to set
if ($parameter) {
$view->$viewFunctionName($parameter);
$view->setTemplateRootPaths($parameter);
}
}

// set LayoutRootPaths
$viewFunctionName = 'setLayoutRootPaths';
if (method_exists($view, $viewFunctionName)) {
if (method_exists($view, 'setLayoutRootPaths')) {
$setting = 'layoutRootPaths';
$parameter = $this->getViewProperty($extbaseFrameworkConfiguration, $setting);
// no need to bother if there is nothing to set
if ($parameter) {
$view->$viewFunctionName($parameter);
$view->setLayoutRootPaths($parameter);
}
}

// set PartialRootPaths
$viewFunctionName = 'setPartialRootPaths';
if (method_exists($view, $viewFunctionName)) {
if (method_exists($view, 'setPartialRootPaths')) {
$setting = 'partialRootPaths';
$parameter = $this->getViewProperty($extbaseFrameworkConfiguration, $setting);
// no need to bother if there is nothing to set
if ($parameter) {
$view->$viewFunctionName($parameter);
$view->setPartialRootPaths($parameter);
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions typo3/sysext/extbase/Classes/Mvc/View/GenericViewResolver.php
Expand Up @@ -47,6 +47,9 @@ public function setDefaultViewClass(string $defaultViewClass): void
$this->defaultViewClass = $defaultViewClass;
}

/**
* @todo v12: Change signature to TYPO3Fluid\Fluid\View\ViewInterface when extbase ViewInterface is dropped.
*/
public function resolve(string $controllerObjectName, string $actionName, string $format): ViewInterface
{
if ($this->container->has($this->defaultViewClass)) {
Expand Down

0 comments on commit f0f4604

Please sign in to comment.