[BUGFIX] Switch ViewHelper restored for safe deprecation 48/46548/5
authorClaus Due <claus@namelesscoder.net>
Tue, 9 Feb 2016 20:00:32 +0000 (21:00 +0100)
committerFrank Naegler <frank.naegler@typo3.org>
Mon, 22 Feb 2016 16:01:33 +0000 (17:01 +0100)
This change restores the previous f:switch and f:case
ViewHelpers. Once deprecation period for f:case argument
"default" is over both classes can be safely deleted.

Change-Id: Ie0d79ef69d145e851f4f27187696a5a5297b3a80
Resolves: #73197
Releases: master
Reviewed-on: https://review.typo3.org/46548
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Morton Jonuschat <m.jonuschat@mojocode.de>
Tested-by: Morton Jonuschat <m.jonuschat@mojocode.de>
Reviewed-by: Daniel Goerz <ervaude@gmail.com>
Tested-by: Daniel Goerz <ervaude@gmail.com>
Reviewed-by: Frank Naegler <frank.naegler@typo3.org>
Tested-by: Frank Naegler <frank.naegler@typo3.org>
typo3/sysext/fluid/Classes/ViewHelpers/CaseViewHelper.php
typo3/sysext/fluid/Classes/ViewHelpers/SwitchViewHelper.php [new file with mode: 0644]

index 44a2912..d9b7691 100644 (file)
@@ -1,66 +1,88 @@
 <?php
 namespace TYPO3\CMS\Fluid\ViewHelpers;
 
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
+/*                                                                        *
+ * 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!                         *
+ *                                                                        */
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
 use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
-use TYPO3Fluid\Fluid\ViewHelpers\DefaultCaseViewHelper;
+use TYPO3\CMS\Fluid\Core\ViewHelper\Exception;
+use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3Fluid\Fluid\ViewHelpers\SwitchViewHelper as OriginalSwitchViewHelper;
 
 /**
  * Case view helper that is only usable within the SwitchViewHelper.
- *
- * @see \TYPO3Fluid\Fluid\ViewHelpers\SwitchViewHelper
+ * @see \TYPO3\CMS\Fluid\ViewHelpers\SwitchViewHelper
  *
  * @api
  */
-class CaseViewHelper extends \TYPO3Fluid\Fluid\ViewHelpers\CaseViewHelper
+class CaseViewHelper extends AbstractViewHelper
 {
     /**
-     * Overrides the "value" argument definition, making it optional.
+     * @var bool
+     */
+    protected $escapeOutput = false;
+
+    /**
+     * @var bool
+     */
+    protected $escapeChildren = false;
+
+    /**
+     * @param mixed $value The switch value. If it matches, the child will be rendered
+     * @param bool $default If this is set, this child will be rendered, if none else matches
+     *
+     * @return string the contents of this view helper if $value equals the expression of the surrounding switch view helper, or $default is TRUE. otherwise an empty string
+     * @throws Exception
      *
-     * @return void
+     * @api
      */
-    public function initializeArguments() {
-        parent::initializeArguments();
-        $this->overrideArgument('value', 'mixed', 'Value to match in this case', false);
+    public function render($value = null, $default = false)
+    {
+        return static::renderStatic(
+            array(
+                'value' => $value,
+                'default' => $default
+            ),
+            $this->buildRenderChildrenClosure(),
+            $this->renderingContext
+        );
     }
 
     /**
      * @param array $arguments
-     * @return void
+     * @param callable $renderChildrenClosure
+     * @param RenderingContextInterface $renderingContext
+     *
+     * @return mixed|string
+     * @throws Exception
      */
-    public function handleAdditionalArguments(array $arguments) {
-        if (isset($arguments['default'])) {
+    public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
+    {
+        $value = $arguments['value'];
+        $default = $arguments['default'];
+        $viewHelperVariableContainer = $renderingContext->getViewHelperVariableContainer();
+        if ($default !== false) {
             GeneralUtility::deprecationLog('Argument "default" on f:case is deprecated - use f:defaultCase instead');
-            if ((bool)$arguments['default']) {
-                // Patch the ViewHelperNode (parse-time only) and change it's class name
-                $attribute = new \ReflectionProperty($this->viewHelperNode, 'viewHelperClassName');
-                $attribute->setAccessible(true);
-                $attribute->setValue($this->viewHelperNode, DefaultCaseViewHelper::class);
-            }
         }
-    }
+        if ($value === null && $default === false) {
+            throw new Exception('The case View helper must have either value or default argument', 1382867521);
+        }
+        $expression = $viewHelperVariableContainer->get(OriginalSwitchViewHelper::class, 'switchExpression');
 
-    /**
-     * @param array $arguments
-     * @return void
-     */
-    public function validateAdditionalArguments(array $arguments) {
-        // Unset the "default" argument and let everything else through to be validated
-        unset($arguments['default']);
-        parent::validateAdditionalArguments($arguments);
+        // non-type-safe comparison by intention
+        if ($default === true || $expression == $value) {
+            $viewHelperVariableContainer->addOrUpdate(OriginalSwitchViewHelper::class, 'break', true);
+            return $renderChildrenClosure();
+        }
+
+        return '';
     }
 }
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..a5c0d5e
--- /dev/null
@@ -0,0 +1,93 @@
+<?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!                         *
+ *                                                                        */
+
+use TYPO3Fluid\Fluid\Core\Compiler\StopCompilingException;
+use TYPO3Fluid\Fluid\Core\Compiler\TemplateCompiler;
+use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\NodeInterface;
+use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode;
+use TYPO3Fluid\Fluid\ViewHelpers\CaseViewHelper as OriginalCaseViewHelper;
+use TYPO3Fluid\Fluid\ViewHelpers\DefaultCaseViewHelper;
+
+/**
+ * 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:defaultCase>Mrs. or Mr.</f:defaultCase>
+ * </f:switch>
+ * </code>
+ * <output>
+ * Mr. / Mrs. (depending on the value of {person.gender}) or if no value evaluates to TRUE, defaultCase
+ * </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 \TYPO3Fluid\Fluid\ViewHelpers\SwitchViewHelper
+{
+    /**
+     * @param NodeInterface $node
+     * @return bool
+     */
+    protected function isDefaultCaseNode(NodeInterface $node)
+    {
+        if ($node instanceof ViewHelperNode) {
+            $viewHelperClassName = $node->getViewHelperClassName();
+            $arguments = $node->getArguments();
+            return (
+                $viewHelperClassName === DefaultCaseViewHelper::class ||
+                (
+                    $viewHelperClassName === CaseViewHelper::class && isset($arguments['default']) && $arguments['default']
+                )
+            );
+        }
+        return false;
+    }
+
+    /**
+     * @param NodeInterface $node
+     * @return bool
+     */
+    protected function isCaseNode(NodeInterface $node)
+    {
+        if ($node instanceof ViewHelperNode) {
+            $viewHelperClassName = $node->getViewHelperClassName();
+            return ($viewHelperClassName === CaseViewHelper::class || $viewHelperClassName === OriginalCaseViewHelper::class);
+        }
+        return false;
+    }
+
+    /**
+     * @param string $argumentsName
+     * @param string $closureName
+     * @param string $initializationPhpCode
+     * @param ViewHelperNode $node
+     * @param TemplateCompiler $compiler
+     */
+    public function compile($argumentsName, $closureName, &$initializationPhpCode, ViewHelperNode $node, TemplateCompiler $compiler)
+    {
+        if (count($node->getChildNodes())) {
+            throw new StopCompilingException();
+        }
+    }
+}