[FEATURE] Switch View Helper 55/21155/6
authorWouter Wolters <typo3@wouterwolters.nl>
Wed, 29 May 2013 17:06:33 +0000 (19:06 +0200)
committerFelix Kopp <felix-source@phorax.com>
Tue, 4 Jun 2013 21:17:08 +0000 (23:17 +0200)
Simple view helper that allows you to render content depending
on a given value or expression.
It bahaves similar to a basic switch statement in PHP.

Usage:

<f:switch expression="{person.gender}">
  <f:case value="male">Mr.</f:case>
  <f:case value="female">Mrs.</f:case>
</f:switch>

Change-Id: I44a7066dfa86785f795069e0f06391cb45fa373c
Resolves: #48653
Releases: 6.2
Reviewed-on: https://review.typo3.org/21155
Reviewed-by: Alexander Schnitzler
Tested-by: Alexander Schnitzler
Reviewed-by: Jigal van Hemert
Tested-by: Jigal van Hemert
Reviewed-by: Felix Kopp
Tested-by: Felix Kopp
typo3/sysext/fluid/Classes/ViewHelpers/CaseViewHelper.php [new file with mode: 0644]
typo3/sysext/fluid/Classes/ViewHelpers/SwitchViewHelper.php [new file with mode: 0644]
typo3/sysext/fluid/Tests/Unit/ViewHelpers/CaseViewHelperTest.php [new file with mode: 0644]
typo3/sysext/fluid/Tests/Unit/ViewHelpers/SwitchViewHelperTest.php [new file with mode: 0644]

diff --git a/typo3/sysext/fluid/Classes/ViewHelpers/CaseViewHelper.php b/typo3/sysext/fluid/Classes/ViewHelpers/CaseViewHelper.php
new file mode 100644 (file)
index 0000000..a38f259
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+namespace TYPO3\CMS\Fluid\ViewHelpers;
+
+/*                                                                        *
+ * This script is backported from the TYPO3 Flow package "TYPO3.Fluid".   *
+ *                                                                        *
+ * It is free software; you can redistribute it and/or modify it under    *
+ * the terms of the GNU Lesser General Public License, either version 3   *
+ *  of the License, or (at your option) any later version.                *
+ *                                                                        *
+ * The TYPO3 project - inspiring people to share!                         *
+ *                                                                        */
+
+/**
+ * Case view helper that is only usable within the SwitchViewHelper.
+ * @see \TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper
+ *
+ * @api
+ */
+class CaseViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper {
+
+       /**
+        * @param mixed $value
+        * @return string the contents of this view helper if $value equals the expression of the surrounding switch view helper, otherwise an empty string
+        * @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception
+        * @api
+        */
+       public function render($value) {
+               $viewHelperVariableContainer = $this->renderingContext->getViewHelperVariableContainer();
+               if (!$viewHelperVariableContainer->exists('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'switchExpression')) {
+                       throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('The case View helper can only be used within a switch View helper', 1368112037);
+               }
+               $switchExpression = $viewHelperVariableContainer->get('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'switchExpression');
+
+               // non-type-safe comparison by intention
+               if ($switchExpression == $value) {
+                       $viewHelperVariableContainer->addOrUpdate('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'break', TRUE);
+                       return $this->renderChildren();
+               }
+               return '';
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/fluid/Classes/ViewHelpers/SwitchViewHelper.php b/typo3/sysext/fluid/Classes/ViewHelpers/SwitchViewHelper.php
new file mode 100644 (file)
index 0000000..f672b96
--- /dev/null
@@ -0,0 +1,131 @@
+<?php
+namespace TYPO3\CMS\Fluid\ViewHelpers;
+
+/*                                                                        *
+ * This script is backported from the TYPO3 Flow package "TYPO3.Fluid".   *
+ *                                                                        *
+ * It is free software; you can redistribute it and/or modify it under    *
+ * the terms of the GNU Lesser General Public License, either version 3   *
+ *  of the License, or (at your option) any later version.                *
+ *                                                                        *
+ * The TYPO3 project - inspiring people to share!                         *
+ *                                                                        */
+
+/**
+ * Switch view helper which can be used to render content depending on a value or expression.
+ * Implements what a basic switch()-PHP-method does.
+ *
+ * = Examples =
+ *
+ * <code title="Simple Switch statement">
+ * <f:switch expression="{person.gender}">
+ *   <f:case value="male">Mr.</f:case>
+ *   <f:case value="female">Mrs.</f:case>
+ * </f:switch>
+ * </code>
+ * <output>
+ * Mr. / Mrs. (depending on the value of {person.gender})
+ * </output>
+ *
+ * Note: Using this view helper can be a sign of weak architecture. If you end up using it extensively
+ * you might want to consider restructuring your controllers/actions and/or use partials and sections.
+ * E.g. the above example could be achieved with <f:render partial="title.{person.gender}" /> and the partials
+ * "title.male.html", "title.female.html", ...
+ * Depending on the scenario this can be easier to extend and possibly contains less duplication.
+ *
+ * @api
+ */
+class SwitchViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper implements \TYPO3\CMS\Fluid\Core\ViewHelper\Facets\ChildNodeAccessInterface {
+
+       /**
+        * An array of \TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\AbstractNode
+        * @var array
+        */
+       private $childNodes = array();
+
+       /**
+        * @var mixed
+        */
+       protected $backupSwitchExpression = NULL;
+
+       /**
+        * @var boolean
+        */
+       protected $backupBreakState = FALSE;
+
+       /**
+        * Setter for ChildNodes - as defined in ChildNodeAccessInterface
+        *
+        * @param array $childNodes Child nodes of this syntax tree node
+        * @return void
+        */
+       public function setChildNodes(array $childNodes) {
+               $this->childNodes = $childNodes;
+       }
+
+       /**
+        * @param mixed $expression
+        * @return string the rendered string
+        * @api
+        */
+       public function render($expression) {
+               $content = '';
+               $this->backupSwitchState();
+               $templateVariableContainer = $this->renderingContext->getViewHelperVariableContainer();
+
+               $templateVariableContainer->addOrUpdate('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'switchExpression', $expression);
+               $templateVariableContainer->addOrUpdate('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'break', FALSE);
+
+               foreach ($this->childNodes as $childNode) {
+                       if (
+                               !$childNode instanceof \TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ViewHelperNode
+                               || $childNode->getViewHelperClassName() !== 'TYPO3\CMS\Fluid\ViewHelpers\CaseViewHelper'
+                       ) {
+                               continue;
+                       }
+                       $content = $childNode->evaluate($this->renderingContext);
+                       if ($templateVariableContainer->get('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'break') === TRUE) {
+                               break;
+                       }
+               }
+
+               $templateVariableContainer->remove('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'switchExpression');
+               $templateVariableContainer->remove('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'break');
+
+               $this->restoreSwitchState();
+               return $content;
+       }
+
+       /**
+        * Backups "switch expression" and "break" state of a possible parent switch ViewHelper to support nesting
+        *
+        * @return void
+        */
+       protected function backupSwitchState() {
+               if ($this->renderingContext->getViewHelperVariableContainer()->exists('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'switchExpression')) {
+                       $this->backupSwitchExpression = $this->renderingContext->getViewHelperVariableContainer()->get('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'switchExpression');
+               }
+               if ($this->renderingContext->getViewHelperVariableContainer()->exists('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'break')) {
+                       $this->backupBreakState = $this->renderingContext->getViewHelperVariableContainer()->get('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'break');
+               }
+       }
+
+       /**
+        * 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',
+                               'switchExpression',
+                               $this->backupSwitchExpression
+                       );
+               }
+               if ($this->backupBreakState !== FALSE) {
+                       $this->renderingContext->getViewHelperVariableContainer()->addOrUpdate('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'break', TRUE);
+               }
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/fluid/Tests/Unit/ViewHelpers/CaseViewHelperTest.php b/typo3/sysext/fluid/Tests/Unit/ViewHelpers/CaseViewHelperTest.php
new file mode 100644 (file)
index 0000000..ce08996
--- /dev/null
@@ -0,0 +1,94 @@
+<?php
+namespace TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers;
+
+/*                                                                        *
+ * This script is backported from the TYPO3 Flow package "TYPO3.Fluid".   *
+ *                                                                        *
+ * It is free software; you can redistribute it and/or modify it under    *
+ * the terms of the GNU General Public License, either version 3 of the   *
+ * License, or (at your option) any later version.                        *
+ *                                                                        *
+ * The TYPO3 project - inspiring people to share!                         *
+ *                                                                        */
+
+require_once(__DIR__ . '/ViewHelperBaseTestcase.php');
+
+/**
+ * Testcase for CaseViewHelper
+ */
+class CaseViewHelperTest extends \TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers\ViewHelperBaseTestcase {
+
+       /**
+        * @var \TYPO3\CMS\Fluid\ViewHelpers\CaseViewHelper
+        */
+       protected $viewHelper;
+
+       public function setUp() {
+               parent::setUp();
+               $this->viewHelper = $this->getMock('TYPO3\CMS\Fluid\ViewHelpers\CaseViewHelper', array('renderChildren'));
+               $this->injectDependenciesIntoViewHelper($this->viewHelper);
+               $this->viewHelper->initializeArguments();
+       }
+
+       /**
+        * @test
+        * @expectedException \TYPO3\CMS\Fluid\Core\ViewHelper\Exception
+        */
+       public function renderThrowsExceptionIfSwitchExpressionIsNotSetInViewHelperVariableContainer() {
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('exists')->with('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'switchExpression')->will($this->returnValue(FALSE));
+               $this->viewHelper->render('foo');
+       }
+
+       /**
+        * @test
+        */
+       public function renderReturnsChildNodesIfTheSpecifiedValueIsEqualToTheSwitchExpression() {
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('exists')->with('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'switchExpression')->will($this->returnValue(TRUE));
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('get')->with('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'switchExpression')->will($this->returnValue('someValue'));
+
+               $renderedChildNodes = 'ChildNodes';
+               $this->viewHelper->expects($this->once())->method('renderChildren')->will($this->returnValue($renderedChildNodes));
+
+               $this->assertSame($renderedChildNodes, $this->viewHelper->render('someValue'));
+       }
+
+       /**
+        * @test
+        */
+       public function renderSetsBreakStateInViewHelperVariableContainerIfTheSpecifiedValueIsEqualToTheSwitchExpression() {
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('exists')->with('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'switchExpression')->will($this->returnValue(TRUE));
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('get')->with('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'switchExpression')->will($this->returnValue('someValue'));
+
+               $this->viewHelperVariableContainer->expects($this->once())->method('addOrUpdate')->with('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'break', TRUE);
+
+               $this->viewHelper->render('someValue');
+       }
+
+       /**
+        * @test
+        */
+       public function renderWeaklyComparesSpecifiedValueWithSwitchExpression() {
+               $numericValue = 123;
+               $stringValue = '123';
+
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('exists')->with('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'switchExpression')->will($this->returnValue(TRUE));
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('get')->with('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'switchExpression')->will($this->returnValue($numericValue));
+
+               $this->viewHelperVariableContainer->expects($this->once())->method('addOrUpdate')->with('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'break', TRUE);
+
+               $this->viewHelper->render($stringValue);
+       }
+
+
+       /**
+        * @test
+        */
+       public function renderReturnsAnEmptyStringIfTheSpecifiedValueIsNotEqualToTheSwitchExpression() {
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('exists')->with('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'switchExpression')->will($this->returnValue(TRUE));
+               $this->viewHelperVariableContainer->expects($this->atLeastOnce())->method('get')->with('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'switchExpression')->will($this->returnValue('someValue'));
+               $this->assertSame('', $this->viewHelper->render('someOtherValue'));
+       }
+
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/fluid/Tests/Unit/ViewHelpers/SwitchViewHelperTest.php b/typo3/sysext/fluid/Tests/Unit/ViewHelpers/SwitchViewHelperTest.php
new file mode 100644 (file)
index 0000000..e873556
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+namespace TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers;
+
+/*                                                                        *
+ * This script is backported from the TYPO3 Flow package "TYPO3.Fluid".   *
+ *                                                                        *
+ * It is free software; you can redistribute it and/or modify it under    *
+ * the terms of the GNU General Public License, either version 3 of the   *
+ * License, or (at your option) any later version.                        *
+ *                                                                        *
+ * The TYPO3 project - inspiring people to share!                         *
+ *                                                                        */
+
+require_once(__DIR__ . '/ViewHelperBaseTestcase.php');
+
+/**
+ * Testcase for SwitchViewHelper
+ */
+class SwitchViewHelperTest extends \TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers\ViewHelperBaseTestcase {
+
+       /**
+        * @var \TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper
+        */
+       protected $viewHelper;
+
+       public function setUp() {
+               parent::setUp();
+               $this->viewHelper = $this->getMock('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', array('renderChildren'));
+               $this->injectDependenciesIntoViewHelper($this->viewHelper);
+               $this->viewHelper->initializeArguments();
+       }
+
+       /**
+        * @test
+        */
+       public function renderSetsSwitchExpressionInViewHelperVariableContainer() {
+               $switchExpression = new \stdClass();
+               $this->viewHelperVariableContainer->expects($this->at(2))->method('addOrUpdate')->with('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'switchExpression', $switchExpression);
+               $this->viewHelper->render($switchExpression);
+       }
+
+       /**
+        * @test
+        */
+       public function renderRemovesSwitchExpressionFromViewHelperVariableContainerAfterInvocation() {
+               $this->viewHelperVariableContainer->expects($this->at(4))->method('remove')->with('TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper', 'switchExpression');
+               $this->viewHelper->render('switchExpression');
+       }
+}
+
+?>
\ No newline at end of file