[TASK] Implement CompileableInterface for SwitchViewHelper 70/39170/4
authorChristian Müller <christian@kitsunet.de>
Fri, 1 May 2015 18:54:26 +0000 (20:54 +0200)
committerChristian Kuhn <lolli@schwarzbu.ch>
Sat, 2 May 2015 10:49:05 +0000 (12:49 +0200)
Allows the SwitchViewHelper to be compiled into cached templates.
Until now using the SwitchViewHelper would result in the template
not being compiled at all. With this change that is no longer the
case.

Releases: master
Resolves: #66718
Change-Id: I5c34c1f770ec73c0296054905b65301af9de7c1b
Reviewed-on: http://review.typo3.org/39170
Reviewed-by: Nicole Cordes <typo3@cordes.co>
Tested-by: Nicole Cordes <typo3@cordes.co>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
typo3/sysext/fluid/Classes/ViewHelpers/CaseViewHelper.php
typo3/sysext/fluid/Classes/ViewHelpers/SwitchViewHelper.php
typo3/sysext/fluid/Tests/Unit/ViewHelpers/CaseViewHelperTest.php
typo3/sysext/fluid/Tests/Unit/ViewHelpers/SwitchViewHelperTest.php

index ff8e465..08e9254 100644 (file)
@@ -55,19 +55,27 @@ class CaseViewHelper extends AbstractViewHelper implements CompilableInterface {
                $value = $arguments['value'];
                $default = $arguments['default'];
                $viewHelperVariableContainer = $renderingContext->getViewHelperVariableContainer();
-               if (!$viewHelperVariableContainer->exists(SwitchViewHelper::class, 'switchExpression')) {
+               if (!$viewHelperVariableContainer->exists(SwitchViewHelper::class, 'stateStack')) {
                        throw new Exception('The case View helper can only be used within a switch View helper', 1368112037);
                }
                if (is_null($value) && $default === FALSE) {
                        throw new Exception('The case View helper must have either value or default argument', 1382867521);
                }
-               $switchExpression = $viewHelperVariableContainer->get(SwitchViewHelper::class, 'switchExpression');
+               $stateStack = $viewHelperVariableContainer->get(SwitchViewHelper::class, 'stateStack');
+               $currentState = array_pop($stateStack);
+
+               if ($currentState['break'] === TRUE) {
+                       return '';
+               }
 
                // non-type-safe comparison by intention
-               if ($default === TRUE || $switchExpression == $value) {
-                       $viewHelperVariableContainer->addOrUpdate(SwitchViewHelper::class, 'break', TRUE);
+               if ($default === TRUE || $currentState['expression'] == $value) {
+                       $currentState['break'] = TRUE;
+                       $stateStack[] = $currentState;
+                       $viewHelperVariableContainer->addOrUpdate(SwitchViewHelper::class, 'stateStack', $stateStack);
                        return $renderChildrenClosure();
                }
+
                return '';
        }
 }
index 1557f16..7637299 100644 (file)
@@ -10,6 +10,12 @@ namespace TYPO3\CMS\Fluid\ViewHelpers;
  *                                                                        *
  * The TYPO3 project - inspiring people to share!                         *
  *                                                                        */
+use TYPO3\CMS\Fluid\Core\Compiler\TemplateCompiler;
+use TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\AbstractNode;
+use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
+use TYPO3\CMS\Fluid\Core\ViewHelper\Facets\ChildNodeAccessInterface;
+use TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface;
 
 /**
  * Switch view helper which can be used to render content depending on a value or expression.
@@ -36,7 +42,7 @@ namespace TYPO3\CMS\Fluid\ViewHelpers;
  *
  * @api
  */
-class SwitchViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper implements \TYPO3\CMS\Fluid\Core\ViewHelper\Facets\ChildNodeAccessInterface {
+class SwitchViewHelper extends AbstractViewHelper implements ChildNodeAccessInterface, CompilableInterface {
 
        /**
         * An array of \TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\AbstractNode
@@ -70,63 +76,47 @@ class SwitchViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelp
         * @api
         */
        public function render($expression) {
-               $content = '';
-               $this->backupSwitchState();
-               $templateVariableContainer = $this->renderingContext->getViewHelperVariableContainer();
-
-               $templateVariableContainer->addOrUpdate(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression', $expression);
-               $templateVariableContainer->addOrUpdate(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'break', FALSE);
-
-               foreach ($this->childNodes as $childNode) {
-                       if (
-                               !$childNode instanceof \TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ViewHelperNode
-                               || $childNode->getViewHelperClassName() !== \TYPO3\CMS\Fluid\ViewHelpers\CaseViewHelper::class
-                       ) {
-                               continue;
-                       }
-                       $content = $childNode->evaluate($this->renderingContext);
-                       if ($templateVariableContainer->get(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'break') === TRUE) {
-                               break;
-                       }
-               }
-
-               $templateVariableContainer->remove(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression');
-               $templateVariableContainer->remove(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'break');
-
-               $this->restoreSwitchState();
-               return $content;
+               return self::renderStatic(
+                       array(
+                               'expression' => $expression
+                       ),
+                       $this->buildRenderChildrenClosure(),
+                       $this->renderingContext
+               );
        }
 
        /**
-        * Backups "switch expression" and "break" state of a possible parent switch ViewHelper to support nesting
+        * Default implementation for CompilableInterface. See CompilableInterface
+        * for a detailed description of this method.
         *
-        * @return void
+        * @param array $arguments
+        * @param \Closure $renderChildrenClosure
+        * @param RenderingContextInterface $renderingContext
+        * @return mixed
+        * @see \TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface
         */
-       protected function backupSwitchState() {
-               if ($this->renderingContext->getViewHelperVariableContainer()->exists(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression')) {
-                       $this->backupSwitchExpression = $this->renderingContext->getViewHelperVariableContainer()->get(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression');
-               }
-               if ($this->renderingContext->getViewHelperVariableContainer()->exists(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'break')) {
-                       $this->backupBreakState = $this->renderingContext->getViewHelperVariableContainer()->get(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'break');
-               }
-       }
+       static public function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) {
+               $viewHelperVariableContainer = $renderingContext->getViewHelperVariableContainer();
 
-       /**
-        * Restores "switch expression" and "break" states that might have been backed up in backupSwitchState() before
-        *
-        * @return void
-        */
-       protected function restoreSwitchState() {
-               if ($this->backupSwitchExpression !== NULL) {
-                       $this->renderingContext->getViewHelperVariableContainer()->addOrUpdate(
-                               \TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class,
-                               'switchExpression',
-                               $this->backupSwitchExpression
-                       );
-               }
-               if ($this->backupBreakState !== FALSE) {
-                       $this->renderingContext->getViewHelperVariableContainer()->addOrUpdate(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'break', TRUE);
+               $stackValue = array(
+                       'expression' => $arguments['expression'],
+                       'break' => FALSE
+               );
+
+               if ($viewHelperVariableContainer->exists(SwitchViewHelper::class, 'stateStack')) {
+                       $stateStack = $viewHelperVariableContainer->get(SwitchViewHelper::class, 'stateStack');
+               } else {
+                       $stateStack = array();
                }
-       }
+               $stateStack[] = $stackValue;
+               $viewHelperVariableContainer->addOrUpdate(SwitchViewHelper::class, 'stateStack', $stateStack);
+
+               $result = $renderChildrenClosure();
 
+               $stateStack = $viewHelperVariableContainer->get(SwitchViewHelper::class, 'stateStack');
+               array_pop($stateStack);
+               $viewHelperVariableContainer->addOrUpdate(SwitchViewHelper::class, 'stateStack', $stateStack);
+
+               return $result;
+       }
 }
index 53e2629..a3c2aae 100644 (file)
@@ -23,7 +23,10 @@ class CaseViewHelperTest extends \TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers\ViewHel
 
        protected function setUp() {
                parent::setUp();
-               $this->viewHelper = $this->getMock(\TYPO3\CMS\Fluid\ViewHelpers\CaseViewHelper::class, array('renderChildren'));
+               $this->viewHelper = $this->getMock(\TYPO3\CMS\Fluid\ViewHelpers\CaseViewHelper::class, array('buildRenderChildrenClosure'));
+               $this->viewHelper->expects($this->any())->method('buildRenderChildrenClosure')->will($this->returnValue(function () {
+                       return 'ChildNodes';
+               }));
                $this->injectDependenciesIntoViewHelper($this->viewHelper);
                $this->viewHelper->initializeArguments();
        }
@@ -33,7 +36,7 @@ class CaseViewHelperTest extends \TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers\ViewHel
         * @expectedException \TYPO3\CMS\Fluid\Core\ViewHelper\Exception
         */
        public function renderThrowsExceptionIfSwitchExpressionIsNotSetInViewHelperVariableContainer() {
-               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('exists')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression')->will($this->returnValue(FALSE));
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('exists')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack')->will($this->returnValue(FALSE));
                $this->viewHelper->render('foo');
        }
 
@@ -41,11 +44,13 @@ class CaseViewHelperTest extends \TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers\ViewHel
         * @test
         */
        public function renderReturnsChildNodesIfTheSpecifiedValueIsEqualToTheSwitchExpression() {
-               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('exists')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression')->will($this->returnValue(TRUE));
-               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('get')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression')->will($this->returnValue('someValue'));
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('exists')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack')->will($this->returnValue(TRUE));
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('get')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack')->will($this->returnValue(array(array(
+                       'break' => FALSE,
+                       'expression' => 'someValue'
+               ))));
 
                $renderedChildNodes = 'ChildNodes';
-               $this->viewHelper->expects($this->once())->method('renderChildren')->will($this->returnValue($renderedChildNodes));
 
                $this->assertSame($renderedChildNodes, $this->viewHelper->render('someValue'));
        }
@@ -54,10 +59,16 @@ class CaseViewHelperTest extends \TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers\ViewHel
         * @test
         */
        public function renderSetsBreakStateInViewHelperVariableContainerIfTheSpecifiedValueIsEqualToTheSwitchExpression() {
-               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('exists')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression')->will($this->returnValue(TRUE));
-               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('get')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression')->will($this->returnValue('someValue'));
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('exists')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack')->will($this->returnValue(TRUE));
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('get')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack')->will($this->returnValue(array(array(
+                       'break' => FALSE,
+                       'expression' => 'someValue'
+               ))));
 
-               $this->viewHelperVariableContainer->expects($this->once())->method('addOrUpdate')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'break', TRUE);
+               $this->viewHelperVariableContainer->expects($this->once())->method('addOrUpdate')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack', array(array(
+                       'break' => TRUE,
+                       'expression' => 'someValue'
+               )));
 
                $this->viewHelper->render('someValue');
        }
@@ -69,10 +80,16 @@ class CaseViewHelperTest extends \TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers\ViewHel
                $numericValue = 123;
                $stringValue = '123';
 
-               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('exists')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression')->will($this->returnValue(TRUE));
-               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('get')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression')->will($this->returnValue($numericValue));
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('exists')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack')->will($this->returnValue(TRUE));
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('get')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack')->will($this->returnValue(array(array(
+                       'break' => FALSE,
+                       'expression' => $numericValue
+               ))));
 
-               $this->viewHelperVariableContainer->expects($this->once())->method('addOrUpdate')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'break', TRUE);
+               $this->viewHelperVariableContainer->expects($this->once())->method('addOrUpdate')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack', array(array(
+                       'break' => TRUE,
+                       'expression' => $numericValue
+               )));
 
                $this->viewHelper->render($stringValue);
        }
@@ -82,8 +99,12 @@ class CaseViewHelperTest extends \TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers\ViewHel
         * @test
         */
        public function renderReturnsAnEmptyStringIfTheSpecifiedValueIsNotEqualToTheSwitchExpression() {
-               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('exists')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression')->will($this->returnValue(TRUE));
-               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('get')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression')->will($this->returnValue('someValue'));
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('exists')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack')->will($this->returnValue(TRUE));
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('get')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack')->will($this->returnValue(array(array(
+                       'break' => FALSE,
+                       'expression' => 'someValue'
+               ))));
+
                $this->assertSame('', $this->viewHelper->render('someOtherValue'));
        }
 
@@ -94,17 +115,22 @@ class CaseViewHelperTest extends \TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers\ViewHel
                $this->viewHelperVariableContainer->expects(
                        $this->atLeastOnce())
                        ->method('exists')
-                       ->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression')
+                       ->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack')
                        ->will($this->returnValue(TRUE)
                        );
                $this->viewHelperVariableContainer->expects(
                        $this->atLeastOnce())->method('get')
-                       ->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression')
-                       ->will($this->returnValue(NULL)
+                       ->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack')
+                       ->will($this->returnValue(array(array(
+                               'break' => FALSE,
+                               'expression' => 'someExpression'
+                       )))
                        );
 
                $renderedChildNodes = 'ChildNodes';
-               $this->viewHelper->expects($this->once())->method('renderChildren')->will($this->returnValue($renderedChildNodes));
+               $this->viewHelper->expects($this->once())->method('buildRenderChildrenClosure')->will($this->returnValue(function() {
+                       return 'ChildNodes';
+               }));
 
                $this->assertSame($renderedChildNodes, $this->viewHelper->render(NULL, TRUE));
        }
@@ -117,7 +143,7 @@ class CaseViewHelperTest extends \TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers\ViewHel
                $this->viewHelperVariableContainer->expects(
                        $this->atLeastOnce())
                        ->method('exists')
-                       ->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression')
+                       ->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack')
                        ->will($this->returnValue(TRUE)
                        );
                $this->viewHelperVariableContainer->expects($this->never())->method('get');
@@ -132,17 +158,19 @@ class CaseViewHelperTest extends \TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers\ViewHel
                $this->viewHelperVariableContainer->expects(
                        $this->atLeastOnce())
                        ->method('exists')
-                       ->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression')
+                       ->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack')
                        ->will($this->returnValue(TRUE)
                        );
                $this->viewHelperVariableContainer->expects(
                        $this->atLeastOnce())->method('get')
-                       ->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression')
-                       ->will($this->returnValue('someValue')
+                       ->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack')
+                       ->will($this->returnValue(array(array(
+                               'break' => FALSE,
+                               'expression' => 'someValue'
+                       )))
                        );
 
                $renderedChildNodes = 'ChildNodes';
-               $this->viewHelper->expects($this->once())->method('renderChildren')->will($this->returnValue($renderedChildNodes));
 
                $this->assertSame($renderedChildNodes, $this->viewHelper->render('someOtherValue', TRUE));
        }
index 6cbe526..baef625 100644 (file)
@@ -33,7 +33,14 @@ class SwitchViewHelperTest extends \TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers\ViewH
         */
        public function renderSetsSwitchExpressionInViewHelperVariableContainer() {
                $switchExpression = new \stdClass();
-               $this->viewHelperVariableContainer->expects($this->at(2))->method('addOrUpdate')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression', $switchExpression);
+               $this->viewHelperVariableContainer->expects($this->at(1))->method('addOrUpdate')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack', array(array(
+                       'break' => FALSE,
+                       'expression' => $switchExpression
+               )));
+               $this->viewHelperVariableContainer->expects($this->at(2))->method('get')->will($this->returnValue(array(array(
+                       'break' => TRUE,
+                       'expression' => $switchExpression
+               ))));
                $this->viewHelper->render($switchExpression);
        }
 
@@ -41,7 +48,15 @@ class SwitchViewHelperTest extends \TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers\ViewH
         * @test
         */
        public function renderRemovesSwitchExpressionFromViewHelperVariableContainerAfterInvocation() {
-               $this->viewHelperVariableContainer->expects($this->at(4))->method('remove')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'switchExpression');
+               $this->viewHelperVariableContainer->expects($this->at(1))->method('addOrUpdate')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack', array(array(
+                       'break' => FALSE,
+                       'expression' => 'switchExpression'
+               )));
+               $this->viewHelperVariableContainer->expects($this->at(2))->method('get')->will($this->returnValue(array(array(
+                       'break' => TRUE,
+                       'expression' => 'switchExpression'
+               ))));
+               $this->viewHelperVariableContainer->expects($this->at(3))->method('addOrUpdate')->with(\TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper::class, 'stateStack', array());
                $this->viewHelper->render('switchExpression');
        }