From b343492ed0e599a542686f9cd32af320b6719b03 Mon Sep 17 00:00:00 2001 From: Claus Due Date: Mon, 27 Jan 2025 00:07:02 +0100 Subject: [PATCH] [BUGFIX] Use ViewBuilder's TemplatePaths to gain fallback ability (#2224) --- Classes/Builder/RenderingContextBuilder.php | 10 +---- Classes/Builder/ViewBuilder.php | 18 +++++++-- Classes/Controller/AbstractFluxController.php | 10 +++-- Classes/Provider/AbstractProvider.php | 1 - Classes/Service/PageService.php | 26 ++++--------- .../Fixtures/Classes/DummyPageController.php | 5 ++- Tests/Fixtures/Classes/DummyPageService.php | 7 ++++ Tests/Unit/Builder/ViewBuilderTest.php | 15 +++++++- .../AbstractFluxControllerTestCase.php | 9 +++++ .../NormalizedData/DataAccessTraitTest.php | 5 +++ Tests/Unit/Service/PageServiceTest.php | 38 +++++++++++++------ 11 files changed, 94 insertions(+), 50 deletions(-) diff --git a/Classes/Builder/RenderingContextBuilder.php b/Classes/Builder/RenderingContextBuilder.php index f2384d6a9..840f98682 100644 --- a/Classes/Builder/RenderingContextBuilder.php +++ b/Classes/Builder/RenderingContextBuilder.php @@ -33,8 +33,7 @@ public function buildRenderingContextFor( string $extensionIdentity, string $controllerName, string $controllerActionName, - string $pluginName, - ?string $templatePathAndFilename = null + string $pluginName ): RenderingContextInterface { $extensionKey = ExtensionNamingUtility::getExtensionKey($extensionIdentity); @@ -71,13 +70,6 @@ public function buildRenderingContextFor( $renderingContext->setControllerName($controllerName); } - $templatePaths = $renderingContext->getTemplatePaths(); - $templatePaths->fillDefaultsByPackageName($extensionKey); - - if ($templatePathAndFilename) { - $templatePaths->setTemplatePathAndFilename($templatePathAndFilename); - } - return $renderingContext; } diff --git a/Classes/Builder/ViewBuilder.php b/Classes/Builder/ViewBuilder.php index c0d80ebe4..6d1a3344c 100644 --- a/Classes/Builder/ViewBuilder.php +++ b/Classes/Builder/ViewBuilder.php @@ -39,10 +39,15 @@ public function buildPreviewView( $extensionIdentity, $controllerName, $controllerAction, - $pluginName, - $templatePathAndFilename + $pluginName ); + $templatePaths = $this->buildTemplatePaths($extensionIdentity); + if ($templatePathAndFilename) { + $templatePaths->setTemplatePathAndFilename($templatePathAndFilename); + } + $renderingContext->setTemplatePaths($templatePaths); + /** @var PreviewView $view */ $view = GeneralUtility::makeInstance($viewClassName); $view->setRenderingContext($renderingContext); @@ -63,10 +68,15 @@ public function buildTemplateView( $extensionIdentity, $controllerName, $controllerAction, - $pluginName, - $templatePathAndFilename + $pluginName ); + $templatePaths = $this->buildTemplatePaths($extensionIdentity); + if ($templatePathAndFilename) { + $templatePaths->setTemplatePathAndFilename($templatePathAndFilename); + } + $renderingContext->setTemplatePaths($templatePaths); + /** @var TemplateView $view */ $view = GeneralUtility::makeInstance($viewClassName); $view->setRenderingContext($renderingContext); diff --git a/Classes/Controller/AbstractFluxController.php b/Classes/Controller/AbstractFluxController.php index 9f9c59028..608bb6a8a 100644 --- a/Classes/Controller/AbstractFluxController.php +++ b/Classes/Controller/AbstractFluxController.php @@ -11,6 +11,7 @@ use FluidTYPO3\Flux\Builder\RenderingContextBuilder; use FluidTYPO3\Flux\Builder\RequestBuilder; +use FluidTYPO3\Flux\Builder\ViewBuilder; use FluidTYPO3\Flux\Hooks\HookHandler; use FluidTYPO3\Flux\Integration\NormalizedData\DataAccessTrait; use FluidTYPO3\Flux\Integration\Resolver; @@ -36,7 +37,6 @@ use TYPO3\CMS\Extbase\Mvc\Request; use TYPO3\CMS\Extbase\Mvc\Response; use TYPO3\CMS\Extbase\Mvc\ResponseInterface; -use TYPO3\CMS\Fluid\View\TemplatePaths; use TYPO3\CMS\Fluid\View\TemplateView; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; @@ -67,6 +67,7 @@ abstract class AbstractFluxController extends ActionController protected TypoScriptService $typoScriptService; protected ProviderResolver $providerResolver; protected Resolver $resolver; + protected ViewBuilder $viewBuilder; protected ?ControllerProviderInterface $provider = null; public function __construct( @@ -75,7 +76,8 @@ public function __construct( WorkspacesAwareRecordService $recordService, TypoScriptService $typoScriptService, ProviderResolver $providerResolver, - Resolver $resolver + Resolver $resolver, + ViewBuilder $viewBuilder ) { $this->renderingContextBuilder = $renderingContextBuilder; $this->requestBuilder = $requestBuilder; @@ -83,6 +85,7 @@ public function __construct( $this->typoScriptService = $typoScriptService; $this->providerResolver = $providerResolver; $this->resolver = $resolver; + $this->viewBuilder = $viewBuilder; /** @var Arguments $arguments */ $arguments = GeneralUtility::makeInstance(Arguments::class); @@ -251,8 +254,7 @@ protected function resolveView(): ViewInterface $extensionName = ExtensionNamingUtility::getExtensionName($extensionKey); $controllerActionName = $this->provider->getControllerActionFromRecord($record); - /** @var TemplatePaths $templatePaths */ - $templatePaths = GeneralUtility::makeInstance(TemplatePaths::class, $extensionKey); + $templatePaths = $this->viewBuilder->buildTemplatePaths($extensionKey); /** @var RenderingContextInterface $renderingContext */ $renderingContext = $view->getRenderingContext(); diff --git a/Classes/Provider/AbstractProvider.php b/Classes/Provider/AbstractProvider.php index a72e97d78..0f79c2838 100644 --- a/Classes/Provider/AbstractProvider.php +++ b/Classes/Provider/AbstractProvider.php @@ -31,7 +31,6 @@ use TYPO3\CMS\Core\Utility\PathUtility; use TYPO3\CMS\Core\Utility\VersionNumberUtility; use TYPO3\CMS\Extbase\Reflection\ObjectAccess; -use TYPO3\CMS\Fluid\View\TemplatePaths; use TYPO3Fluid\Fluid\View\Exception\InvalidTemplateResourceException; use TYPO3Fluid\Fluid\View\ViewInterface; diff --git a/Classes/Service/PageService.php b/Classes/Service/PageService.php index 97545a743..dcbe88800 100755 --- a/Classes/Service/PageService.php +++ b/Classes/Service/PageService.php @@ -8,6 +8,7 @@ * LICENSE.md file that was distributed with this source code. */ +use FluidTYPO3\Flux\Builder\ViewBuilder; use FluidTYPO3\Flux\Content\TypeDefinition\FluidFileBased\DropInContentTypeDefinition; use FluidTYPO3\Flux\Core; use FluidTYPO3\Flux\Enum\ExtensionOption; @@ -16,7 +17,6 @@ use FluidTYPO3\Flux\Provider\PageProvider; use FluidTYPO3\Flux\Proxy\TemplatePathsProxy; use FluidTYPO3\Flux\Utility\ExtensionConfigurationUtility; -use FluidTYPO3\Flux\Utility\ExtensionNamingUtility; use FluidTYPO3\Flux\ViewHelpers\FormViewHelper; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareTrait; @@ -45,13 +45,16 @@ class PageService implements SingletonInterface, LoggerAwareInterface protected WorkspacesAwareRecordService $workspacesAwareRecordService; protected FrontendInterface $runtimeCache; + protected ViewBuilder $viewBuilder; public function __construct( WorkspacesAwareRecordService $recordService, - CacheManager $cacheManager + CacheManager $cacheManager, + ViewBuilder $viewBuilder ) { $this->workspacesAwareRecordService = $recordService; $this->runtimeCache = $cacheManager->getCache('runtime'); + $this->viewBuilder = $viewBuilder; } /** @@ -183,13 +186,13 @@ public function getPageConfiguration(?string $extensionName = null): array ]; } if (null !== $extensionName) { - $templatePaths = $this->createTemplatePaths($extensionName); + $templatePaths = $this->viewBuilder->buildTemplatePaths($extensionName); return TemplatePathsProxy::toArray($templatePaths); } $configurations = []; $registeredExtensionKeys = Core::getRegisteredProviderExtensionKeys('Page'); foreach ($registeredExtensionKeys as $registeredExtensionKey) { - $templatePaths = $this->createTemplatePaths($registeredExtensionKey); + $templatePaths = $this->viewBuilder->buildTemplatePaths($registeredExtensionKey); $configurations[$registeredExtensionKey] = TemplatePathsProxy::toArray($templatePaths); } if ($plugAndPlayEnabled) { @@ -236,7 +239,7 @@ public function getAvailablePageTemplateFiles(): array continue; } $output[$extensionName] = []; - $templatePaths = $this->createTemplatePaths($extensionName); + $templatePaths = $this->viewBuilder->buildTemplatePaths($extensionName); $finder = Finder::create()->in($templatePaths->getTemplateRootPaths())->name('*.html')->sortByName(); foreach ($finder->files() as $file) { /** @var \SplFileInfo $file */ @@ -290,19 +293,6 @@ public function getAvailablePageTemplateFiles(): array return $output; } - /** - * @codeCoverageIgnore - */ - protected function createTemplatePaths(string $registeredExtensionKey): TemplatePaths - { - /** @var TemplatePaths $templatePaths */ - $templatePaths = GeneralUtility::makeInstance( - TemplatePaths::class, - ExtensionNamingUtility::getExtensionKey($registeredExtensionKey) - ); - return $templatePaths; - } - /** * @codeCoverageIgnore */ diff --git a/Tests/Fixtures/Classes/DummyPageController.php b/Tests/Fixtures/Classes/DummyPageController.php index c8062602e..03dcb5f1b 100644 --- a/Tests/Fixtures/Classes/DummyPageController.php +++ b/Tests/Fixtures/Classes/DummyPageController.php @@ -10,6 +10,7 @@ use FluidTYPO3\Flux\Builder\RenderingContextBuilder; use FluidTYPO3\Flux\Builder\RequestBuilder; +use FluidTYPO3\Flux\Builder\ViewBuilder; use FluidTYPO3\Flux\Controller\PageController; use FluidTYPO3\Flux\Integration\Resolver; use FluidTYPO3\Flux\Provider\Interfaces\ControllerProviderInterface; @@ -32,6 +33,7 @@ public function __construct() $typoScriptService = $this->createMock(TypoScriptService::class); $providerResolver = $this->createMock(ProviderResolver::class); $resolver = $this->createMock(Resolver::class); + $viewBuilder = $this->createMock(ViewBuilder::class); parent::__construct( $renderingContextBuilder, @@ -39,7 +41,8 @@ public function __construct() $recordService, $typoScriptService, $providerResolver, - $resolver + $resolver, + $viewBuilder ); } diff --git a/Tests/Fixtures/Classes/DummyPageService.php b/Tests/Fixtures/Classes/DummyPageService.php index 2f93af757..5bcc115c6 100644 --- a/Tests/Fixtures/Classes/DummyPageService.php +++ b/Tests/Fixtures/Classes/DummyPageService.php @@ -1,6 +1,7 @@ workspacesAwareRecordService = $this->createMock(WorkspacesAwareRecordService::class); $this->runtimeCache = $this->createMock(FrontendInterface::class); + $this->viewBuilder = $this->createMock(ViewBuilder::class); } public function setWorkspacesAwareRecordService(WorkspacesAwareRecordService $workspacesAwareRecordService): void @@ -24,6 +26,11 @@ public function setRuntimeCache(FrontendInterface $runtimeCache): void $this->runtimeCache = $runtimeCache; } + public function setViewBuilder(ViewBuilder $viewBuilder): void + { + $this->viewBuilder = $viewBuilder; + } + private function createMock(string $className): object { return (new Generator())->getMock($className, [], [], '', false); diff --git a/Tests/Unit/Builder/ViewBuilderTest.php b/Tests/Unit/Builder/ViewBuilderTest.php index eaf6589ff..783ca61cf 100644 --- a/Tests/Unit/Builder/ViewBuilderTest.php +++ b/Tests/Unit/Builder/ViewBuilderTest.php @@ -13,6 +13,7 @@ use FluidTYPO3\Flux\Integration\PreviewView; use FluidTYPO3\Flux\Tests\Unit\AbstractTestCase; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Fluid\View\TemplatePaths; use TYPO3\CMS\Fluid\View\TemplateView; use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface; @@ -37,7 +38,12 @@ public function testBuildTemplateView(): void $view = $this->getMockBuilder(TemplateView::class)->disableOriginalConstructor()->getMock(); GeneralUtility::addInstance(TemplateView::class, $view); - $subject = new ViewBuilder($this->renderingContextBuilder); + $subject = $this->getMockBuilder(ViewBuilder::class) + ->onlyMethods(['buildTemplatePaths']) + ->setConstructorArgs([$this->renderingContextBuilder]) + ->getMock(); + $subject->method('buildTemplatePaths')->willReturn(new TemplatePaths()); + $view = $subject->buildTemplateView('FluidTYPO3.Flux', 'Default', 'default', 'defaut'); self::assertInstanceOf(TemplateView::class, $view); } @@ -47,7 +53,12 @@ public function testBuildPreviewView(): void $view = $this->getMockBuilder(PreviewView::class)->disableOriginalConstructor()->getMock(); GeneralUtility::addInstance(PreviewView::class, $view); - $subject = new ViewBuilder($this->renderingContextBuilder); + $subject = $this->getMockBuilder(ViewBuilder::class) + ->onlyMethods(['buildTemplatePaths']) + ->setConstructorArgs([$this->renderingContextBuilder]) + ->getMock(); + $subject->method('buildTemplatePaths')->willReturn(new TemplatePaths()); + $view = $subject->buildPreviewView('FluidTYPO3.Flux', 'Default', 'default', 'default'); self::assertInstanceOf(PreviewView::class, $view); } diff --git a/Tests/Unit/Controller/AbstractFluxControllerTestCase.php b/Tests/Unit/Controller/AbstractFluxControllerTestCase.php index 2e7876d7c..b4727dde3 100644 --- a/Tests/Unit/Controller/AbstractFluxControllerTestCase.php +++ b/Tests/Unit/Controller/AbstractFluxControllerTestCase.php @@ -10,6 +10,7 @@ use FluidTYPO3\Flux\Builder\RenderingContextBuilder; use FluidTYPO3\Flux\Builder\RequestBuilder; +use FluidTYPO3\Flux\Builder\ViewBuilder; use FluidTYPO3\Flux\Controller\AbstractFluxController; use FluidTYPO3\Flux\Controller\ContentController; use FluidTYPO3\Flux\Core; @@ -71,6 +72,8 @@ abstract class AbstractFluxControllerTestCase extends AbstractTestCase protected Resolver $resolver; + protected ViewBuilder $viewBuilder; + protected function setUp(): void { $renderingContext = new RenderingContext(); @@ -102,6 +105,11 @@ protected function setUp(): void $this->resolver = new Resolver(); + $this->viewBuilder = $this->getMockBuilder(ViewBuilder::class) + ->onlyMethods(['buildTemplatePaths']) + ->disableOriginalConstructor() + ->getMock(); + parent::setUp(); } @@ -114,6 +122,7 @@ protected function getConstructorArguments(): array $this->typoScriptService, $this->providerResolver, $this->resolver, + $this->viewBuilder, ]; } diff --git a/Tests/Unit/Integration/NormalizedData/DataAccessTraitTest.php b/Tests/Unit/Integration/NormalizedData/DataAccessTraitTest.php index ce538b316..522a20938 100644 --- a/Tests/Unit/Integration/NormalizedData/DataAccessTraitTest.php +++ b/Tests/Unit/Integration/NormalizedData/DataAccessTraitTest.php @@ -10,6 +10,7 @@ use FluidTYPO3\Flux\Builder\RenderingContextBuilder; use FluidTYPO3\Flux\Builder\RequestBuilder; +use FluidTYPO3\Flux\Builder\ViewBuilder; use FluidTYPO3\Flux\Form; use FluidTYPO3\Flux\Form\Transformation\FormDataTransformer; use FluidTYPO3\Flux\Integration\NormalizedData\Converter\InlineRecordDataConverter; @@ -51,6 +52,7 @@ class DataAccessTraitTest extends AbstractTestCase protected TypoScriptService $typoScriptService; protected ProviderResolver $providerResolver; protected Resolver $resolver; + protected ViewBuilder $viewBuilder; protected function setUp(): void { @@ -84,6 +86,8 @@ protected function setUp(): void $this->resolver = new Resolver(); + $this->viewBuilder = $this->getMockBuilder(ViewBuilder::class)->disableOriginalConstructor()->getMock(); + $GLOBALS['TYPO3_REQUEST'] = $this->getMockBuilder(ServerRequestInterface::class)->getMockForAbstractClass(); parent::setUp(); @@ -104,6 +108,7 @@ protected function getControllerConstructorArguments(): array $this->typoScriptService, $this->providerResolver, $this->resolver, + $this->viewBuilder, ]; } diff --git a/Tests/Unit/Service/PageServiceTest.php b/Tests/Unit/Service/PageServiceTest.php index 7f173b6da..62840de57 100644 --- a/Tests/Unit/Service/PageServiceTest.php +++ b/Tests/Unit/Service/PageServiceTest.php @@ -8,6 +8,7 @@ * LICENSE.md file that was distributed with this source code. */ +use FluidTYPO3\Flux\Builder\ViewBuilder; use FluidTYPO3\Flux\Core; use FluidTYPO3\Flux\Enum\ExtensionOption; use FluidTYPO3\Flux\Service\PageService; @@ -115,11 +116,17 @@ public function testGetAvailablePageTemplateFiles($typoScript, $expected): void $templatePaths->method('getTemplateRootPaths')->willReturn([__DIR__ . '/../../Fixtures/Templates']); $templatePaths->method('ensureAbsolutePath')->willReturnArgument(0); + $viewBuilder = $this->getMockBuilder(ViewBuilder::class) + ->onlyMethods(['buildTemplatePaths']) + ->disableOriginalConstructor() + ->getMock(); + $viewBuilder->method('buildTemplatePaths')->willReturn($templatePaths); + $instance = $this->getMockBuilder(DummyPageService::class) - ->onlyMethods(['createTemplatePaths', 'getPageConfiguration', 'createViewInstance']) + ->onlyMethods(['getPageConfiguration', 'createViewInstance']) ->getMock(); + $instance->setViewBuilder($viewBuilder); $instance->setLogger($this->getMockBuilder(LoggerInterface::class)->getMockForAbstractClass()); - $instance->method('createTemplatePaths')->willReturn($templatePaths); $instance->method('getPageConfiguration')->willReturn($typoScript); $instance->method('createViewInstance')->willReturn($templateView); @@ -229,11 +236,14 @@ public function testGetPageConfigurationReturnsExpectedArrayOnPlugAndPlayDirecto ); } - $instance = $this->getMockBuilder(PageService::class) - ->onlyMethods(['createTemplatePaths']) + $viewBuilder = $this->getMockBuilder(ViewBuilder::class) + ->onlyMethods(['buildTemplatePaths']) ->disableOriginalConstructor() ->getMock(); - $instance->method('createTemplatePaths')->willReturn($templatePaths); + $viewBuilder->method('buildTemplatePaths')->willReturn($templatePaths); + + $instance = new DummyPageService(); + $instance->setViewBuilder($viewBuilder); Core::registerProviderExtensionKey('FluidTYPO3.Testing', 'Page'); $result = $instance->getPageConfiguration(null); @@ -277,11 +287,14 @@ public function testGetPageConfigurationReturnsDefaultTemplatePaths(): void ); } - $instance = $this->getMockBuilder(PageService::class) - ->onlyMethods(['createTemplatePaths']) + $viewBuilder = $this->getMockBuilder(ViewBuilder::class) + ->onlyMethods(['buildTemplatePaths']) ->disableOriginalConstructor() ->getMock(); - $instance->method('createTemplatePaths')->willReturn($templatePaths); + $viewBuilder->method('buildTemplatePaths')->willReturn($templatePaths); + + $instance = new DummyPageService(); + $instance->setViewBuilder($viewBuilder); $result = $instance->getPageConfiguration('Flux'); @@ -298,11 +311,14 @@ public function testGetPageConfigurationReturnsDefaultTemplatePaths(): void public function testGetPageConfigurationWithoutExtensionNameReadsRegisteredProviders(): void { $templatePaths = new TemplatePaths(); - $instance = $this->getMockBuilder(PageService::class) - ->onlyMethods(['createTemplatePaths']) + $viewBuilder = $this->getMockBuilder(ViewBuilder::class) + ->onlyMethods(['buildTemplatePaths']) ->disableOriginalConstructor() ->getMock(); - $instance->method('createTemplatePaths')->willReturn($templatePaths); + $viewBuilder->method('buildTemplatePaths')->willReturn($templatePaths); + $instance = new DummyPageService(); + $instance->setViewBuilder($viewBuilder); + Core::registerProviderExtensionKey('foo', 'Page'); Core::registerProviderExtensionKey('bar', 'Page'); $result = $instance->getPageConfiguration();