[FEATURE] Add templateRootPaths support to StandaloneView 60/39160/3
authorFrans Saris <franssaris@gmail.com>
Fri, 1 May 2015 15:30:29 +0000 (17:30 +0200)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Sun, 3 May 2015 11:02:57 +0000 (13:02 +0200)
StandaloneView is extended with setTemplateRootPaths() and
setTemplate() so it supports the same template path fallback
support like the extbase controllers do.

Resolves: #66709
Releases: master
Change-Id: I64a6e4a8e81936233e9efec85181ce3849771cdb
Reviewed-on: http://review.typo3.org/39160
Reviewed-by: Andreas Fernandez <typo3@scripting-base.de>
Tested-by: Andreas Fernandez <typo3@scripting-base.de>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
typo3/sysext/core/Documentation/Changelog/master/Feature-66709-AddTemplateRootPathsSupportToFluidViewStandaloneView.rst [new file with mode: 0644]
typo3/sysext/fluid/Classes/View/StandaloneView.php
typo3/sysext/fluid/Tests/Unit/View/StandaloneViewTest.php

diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-66709-AddTemplateRootPathsSupportToFluidViewStandaloneView.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-66709-AddTemplateRootPathsSupportToFluidViewStandaloneView.rst
new file mode 100644 (file)
index 0000000..d18077b
--- /dev/null
@@ -0,0 +1,49 @@
+============================================================================
+Feature: #66709 - Add TemplateRootPaths support to Fluid/View/StandaloneView
+============================================================================
+
+Description
+===========
+
+The StandaloneView is extended with ``setTemplateRootPaths($templatePaths)`` and ``setTemplate($templateName, $throwException = TRUE)``. Now you can set a template by name.
+
+When ``setTemplate($templateName)`` is called the ``$templateName`` is used to find the template in the given templateRootPaths with the same fallback logic as layoutRootPath and partialRootPath.
+
+
+Basic example:
+
+.. code-block:: php
+
+       $view = GeneralUtility::makeInstance(StandaloneView::class);
+       $view->setLayoutRootPaths($layoutPaths);
+       $view->setPartialRootPaths($partialPaths);
+       $view->setTemplateRootPaths($templatePaths);
+
+       try {
+               $view->setTemplate($templateName);
+       } catch (InvalidTemplateResourceException $e) {
+               // no template $templateName found in given $templatePaths
+               exit($e->getMessage());
+       }
+
+       $content = $view->render();
+
+
+
+Example of rendering a email template:
+
+.. code-block:: php
+
+       $view = GeneralUtility::makeInstance(StandaloneView::class);
+       $view->setLayoutRootPaths(array(GeneralUtility::getFileAbsFileName('EXT:my_extension/Resources/Private/Layouts')));
+       $view->setPartialRootPaths(array(GeneralUtility::getFileAbsFileName('EXT:my_extension/Resources/Private/Partials')));
+       $view->setTemplateRootPaths(array(GeneralUtility::getFileAbsFileName('EXT:my_extension/Resources/Private/Templates')));
+       $view->setTemplate('Email/Notification');
+
+       $emailBody = $view->render();
+
+
+Impact
+======
+
+The public API of ``TYPO3\CMS\Fluid\View\StandaloneView`` is enhanced with the methods ``setTemplateRootPaths($templatePaths)`` and ``setTemplate($templateName, $throwException = TRUE)``
\ No newline at end of file
index fa81773..d57ca42 100644 (file)
@@ -57,16 +57,23 @@ class StandaloneView extends AbstractTemplateView {
        protected $templatePathAndFilename = NULL;
 
        /**
+        * Path(s) to the template root
+        *
+        * @var string[]
+        */
+       protected $templateRootPaths = NULL;
+
+       /**
         * Path(s) to the partial root
         *
-        * @var array
+        * @var string[]
         */
        protected $partialRootPaths = NULL;
 
        /**
         * Path(s) to the layout root
         *
-        * @var array
+        * @var string[]
         */
        protected $layoutRootPaths = NULL;
 
@@ -169,6 +176,46 @@ class StandaloneView extends AbstractTemplateView {
        }
 
        /**
+        * Set the root path(s) to the templates.
+        *
+        * @param string[] $templateRootPaths Root paths to the templates.
+        * @return void
+        * @api
+        */
+       public function setTemplateRootPaths(array $templateRootPaths) {
+               $this->templateRootPaths = $templateRootPaths;
+       }
+
+       /**
+        * Set template by name
+        * All set templateRootPaths are checked to find template by given name
+        *
+        * @param string $templateName Name of the template
+        * @param bool $throwException
+        * @throws InvalidTemplateResourceException
+        * @api
+        */
+       public function setTemplate($templateName, $throwException = TRUE) {
+               if ($this->templateRootPaths === NULL) {
+                       throw new InvalidTemplateResourceException('No template root path has been specified. Use setTemplateRootPaths().', 1430635895);
+               }
+               $format = $this->getRequest()->getFormat();
+               $templatePathAndFilename = NULL;
+               $possibleTemplatePaths = $this->buildListOfTemplateCandidates($templateName, $this->templateRootPaths, $format);
+               foreach ($possibleTemplatePaths as $possibleTemplatePath) {
+                       if ($this->testFileExistence($possibleTemplatePath)) {
+                               $templatePathAndFilename = $possibleTemplatePath;
+                               break;
+                       }
+               }
+               if ($templatePathAndFilename !== NULL) {
+                       $this->setTemplatePathAndFilename($templatePathAndFilename);
+               } elseif ($throwException) {
+                       throw new InvalidTemplateResourceException('Could not load template file. Tried following paths: "' . implode('", "', $possibleTemplatePaths) . '".', 1430635896);
+               }
+       }
+
+       /**
         * Set the root path to the layouts.
         *
         * @param string $layoutRootPath Root path to the layouts.
@@ -185,7 +232,7 @@ class StandaloneView extends AbstractTemplateView {
        /**
         * Set the root path(s) to the layouts.
         *
-        * @param array $layoutRootPaths Root path to the layouts
+        * @param string[] $layoutRootPaths Root path to the layouts
         * @return void
         * @api
         */
@@ -257,7 +304,7 @@ class StandaloneView extends AbstractTemplateView {
         * Set the root path(s) to the partials.
         * If set, overrides the one determined from $this->partialRootPathPattern
         *
-        * @param array $partialRootPaths Root paths to the partials. If set, overrides the one determined from $this->partialRootPathPattern
+        * @param string[] $partialRootPaths Root paths to the partials. If set, overrides the one determined from $this->partialRootPathPattern
         * @return void
         * @api
         */
index 7c0573f..2973e90 100644 (file)
@@ -778,4 +778,161 @@ class StandaloneViewTest extends UnitTestCase {
                $this->assertEquals(PATH_site . 'some/Default/Directory/Default', $this->view->_call('getLayoutPathAndFilename'));
        }
 
+       /**
+        * @test
+        * @expectedException \TYPO3\CMS\Fluid\View\Exception\InvalidTemplateResourceException
+        */
+       public function setTemplateThrowsExceptionIfNoTemplateRootPathsAreSet() {
+               $this->view->setTemplate('TemplateName');
+       }
+
+       /**
+        * @test
+        * @expectedException \TYPO3\CMS\Fluid\View\Exception\InvalidTemplateResourceException
+        */
+       public function setTemplateThrowsExceptionIfSpecifiedTemplateNameDoesNotExist() {
+               $this->view->setTemplateRootPaths(array(
+                       'Some/Template/Path'
+               ));
+               $this->view->setTemplate('NonExistingTemplateName');
+       }
+
+       /**
+        * @test
+        */
+       public function setTemplateRespectsCasingOfTemplateName() {
+               $this->view->setTemplateRootPaths(array('some/Default/Directory'));
+               $this->mockRequest->expects($this->any())->method('getFormat')->will($this->returnValue('html'));
+               $this->view->expects($this->at(0))->method('testFileExistence')->with(PATH_site . 'some/Default/Directory/TemplateName.html')->willReturn(FALSE);
+               $this->view->expects($this->at(1))->method('testFileExistence')->with(PATH_site . 'some/Default/Directory/TemplateName')->willReturn(FALSE);
+               $this->view->expects($this->at(2))->method('testFileExistence')->with(PATH_site . 'some/Default/Directory/templateName.html')->willReturn(TRUE);
+               $this->view->setTemplate('templateName');
+
+               $this->assertSame(PATH_site . 'some/Default/Directory/templateName.html', $this->view->getTemplatePathAndFilename());
+       }
+
+       /**
+        * @test
+        */
+       public function setTemplateSetsUpperCasedTemplateName() {
+               $this->view->setTemplateRootPaths(array('some/Default/Directory'));
+               $this->mockRequest->expects($this->any())->method('getFormat')->will($this->returnValue('html'));
+               $this->view->expects($this->at(0))->method('testFileExistence')->with(PATH_site . 'some/Default/Directory/TemplateName.html')->willReturn(TRUE);
+               $this->view->setTemplate('templateName');
+               $this->assertSame(PATH_site . 'some/Default/Directory/TemplateName.html', $this->view->getTemplatePathAndFilename());
+       }
+
+       /**
+        * @test
+        */
+       public function setTemplateResolvesTheSpecificTemplateFile() {
+               $this->view->setTemplateRootPaths(array(
+                       'default' => 'some/Default/Directory',
+                       'specific' => 'specific/Templates',
+               ));
+               $this->mockRequest->expects($this->any())->method('getFormat')->will($this->returnValue('html'));
+               $this->view->expects($this->at(0))->method('testFileExistence')->with(PATH_site . 'specific/Templates/Template.html')->will($this->returnValue(TRUE));
+               $this->view->setTemplate('Template');
+               $this->assertEquals(PATH_site . 'specific/Templates/Template.html', $this->view->getTemplatePathAndFilename());
+       }
+
+       /**
+        * @test
+        */
+       public function setTemplateResolvesTheDefaultTemplateFile() {
+               $this->view->setTemplateRootPaths(array(
+                       'default' => 'some/Default/Directory',
+                       'specific' => 'specific/Templates',
+               ));
+               $this->mockRequest->expects($this->any())->method('getFormat')->will($this->returnValue('html'));
+               $this->view->expects($this->at(2))->method('testFileExistence')->with(PATH_site . 'some/Default/Directory/Template.html')->will($this->returnValue(TRUE));
+               $this->view->setTemplate('Template');
+
+               $this->assertEquals(PATH_site . 'some/Default/Directory/Template.html', $this->view->getTemplatePathAndFilename());
+       }
+
+       /**
+        * @test
+        */
+       public function setTemplateResolvesTemplateNameWithPath() {
+               $this->view->setTemplateRootPaths(array(
+                       'default' => 'some/Default/Directory',
+                       'specific' => 'specific/Templates',
+               ));
+               $this->mockRequest->expects($this->any())->method('getFormat')->will($this->returnValue('html'));
+               $this->view->expects($this->at(0))->method('testFileExistence')->with(PATH_site . 'specific/Templates/Email/Template.html')->will($this->returnValue(TRUE));
+               $this->view->setTemplate('Email/Template');
+               $this->assertEquals(PATH_site . 'specific/Templates/Email/Template.html', $this->view->getTemplatePathAndFilename());
+       }
+
+       /**
+        * @test
+        */
+       public function setTemplateResolvesTheSpecificFileWithNumericIndices() {
+               $this->view->setTemplateRootPaths(array(
+                       '10' => 'some/Default/Directory',
+                       '25' => 'evenMore/Specific/Templates',
+                       '17' => 'specific/Templates',
+               ));
+               $this->mockRequest->expects($this->any())->method('getFormat')->will($this->returnValue('html'));
+               $this->view->expects($this->at(2))->method('testFileExistence')->with(PATH_site . 'specific/Templates/Template.html')->will($this->returnValue(TRUE));
+               $this->view->setTemplate('Template');
+               $this->assertEquals(PATH_site . 'specific/Templates/Template.html', $this->view->getTemplatePathAndFilename());
+       }
+
+       /**
+        * @test
+        */
+       public function setTemplateResolvesTheDefaultFileWithNumericIndices() {
+               $this->view->setTemplateRootPaths(array(
+                       '10' => 'some/Default/Directory',
+                       '25' => 'evenMore/Specific/Templates',
+                       '17' => 'specific/Templates',
+               ));
+               $this->mockRequest->expects($this->any())->method('getFormat')->will($this->returnValue('html'));
+               $this->view->expects($this->at(4))->method('testFileExistence')->with(PATH_site . 'some/Default/Directory/Template.html')->will($this->returnValue(TRUE));
+               $this->view->setTemplate('Template');
+               $this->assertEquals(PATH_site . 'some/Default/Directory/Template.html', $this->view->getTemplatePathAndFilename());
+       }
+
+       /**
+        * @test
+        */
+       public function setTemplateWalksNumericalIndicesInDescendingOrder() {
+               $this->view->setTemplateRootPaths(array(
+                       '10' => 'some/Default/Directory',
+                       '25' => 'evenMore/Specific/Templates',
+                       '17' => 'specific/Templates',
+               ));
+               $this->mockRequest->expects($this->any())->method('getFormat')->will($this->returnValue('html'));
+               $this->view->expects($this->at(0))->method('testFileExistence')->with(PATH_site . 'evenMore/Specific/Templates/Template.html')->will($this->returnValue(FALSE));
+               $this->view->expects($this->at(1))->method('testFileExistence')->with(PATH_site . 'evenMore/Specific/Templates/Template')->will($this->returnValue(FALSE));
+               $this->view->expects($this->at(2))->method('testFileExistence')->with(PATH_site . 'specific/Templates/Template.html')->will($this->returnValue(FALSE));
+               $this->view->expects($this->at(3))->method('testFileExistence')->with(PATH_site . 'specific/Templates/Template')->will($this->returnValue(FALSE));
+               $this->view->expects($this->at(4))->method('testFileExistence')->with(PATH_site . 'some/Default/Directory/Template.html')->will($this->returnValue(FALSE));
+               $this->view->expects($this->at(5))->method('testFileExistence')->with(PATH_site . 'some/Default/Directory/Template')->will($this->returnValue(TRUE));
+               $this->view->setTemplate('Template');
+               $this->assertEquals(PATH_site . 'some/Default/Directory/Template', $this->view->getTemplatePathAndFilename());
+       }
+
+       /**
+        * @test
+        */
+       public function setTemplateWalksStringKeysInReversedOrder() {
+               $this->view->setTemplateRootPaths(array(
+                       'default' => 'some/Default/Directory',
+                       'specific' => 'specific/Templates',
+                       'verySpecific' => 'evenMore/Specific/Templates',
+               ));
+               $this->mockRequest->expects($this->any())->method('getFormat')->will($this->returnValue('html'));
+               $this->view->expects($this->at(0))->method('testFileExistence')->with(PATH_site . 'evenMore/Specific/Templates/Template.html')->will($this->returnValue(FALSE));
+               $this->view->expects($this->at(1))->method('testFileExistence')->with(PATH_site . 'evenMore/Specific/Templates/Template')->will($this->returnValue(FALSE));
+               $this->view->expects($this->at(2))->method('testFileExistence')->with(PATH_site . 'specific/Templates/Template.html')->will($this->returnValue(FALSE));
+               $this->view->expects($this->at(3))->method('testFileExistence')->with(PATH_site . 'specific/Templates/Template')->will($this->returnValue(FALSE));
+               $this->view->expects($this->at(4))->method('testFileExistence')->with(PATH_site . 'some/Default/Directory/Template.html')->will($this->returnValue(FALSE));
+               $this->view->expects($this->at(5))->method('testFileExistence')->with(PATH_site . 'some/Default/Directory/Template')->will($this->returnValue(TRUE));
+               $this->view->setTemplate('Template');
+               $this->assertEquals(PATH_site . 'some/Default/Directory/Template', $this->view->getTemplatePathAndFilename());
+       }
+
 }