TYPO3 ver. 7.6.2 - Condition ViewHelpers evaluated only once

試著忘記壹切 提交于 2019-12-07 11:13:05

问题


Problem: I wrote a conditional VH (extending AbstractConditionViewHelper) and it works as usually, anyway I realized that in non-cached version it is evaluated only once. Initialy I thought that's my bug, but checked common <f:if> and the problem is identical :S

In general when I visit my page for the first time, condition is evaluated and valid result is given, but when I'll refresh the page VH isn't called anymore (checked by setting breakpoint inside the VH) and VH is always treated as FALSE. Only any change in view's code will cause that VH will be evaluated once, and again next refresh(es) won't call VH anymore.

typo3conf/ext/toolbox/Classes/ViewHelpers/IsFieldRequiredViewHelper.php:

<?php
namespace Vendor\Toolbox\ViewHelpers;

class IsFieldRequiredViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractConditionViewHelper {

    /**
     * @param string $fieldName      Current field name
     * @param string $requiredFields List of required names separated by commas
     *
     * @return string the rendered string
     */
    public function render($fieldName, $requiredFields) {

        $requiredArray = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $requiredFields, true);

        return (in_array($fieldName, $requiredArray))
            ? $this->renderThenChild()
            : $this->renderElseChild();
    }
}

Usage:

{namespace toolbox=Vendor\Toolbox\ViewHelpers}

<toolbox:isFieldRequired fieldName="foo" requiredFields="foo, bar, baz">
    <f:then>TRUE</f:then>
    <f:else>FALSE</f:else>
</toolbox:isFieldRequired>

For the first hit I have TRUE but later only FALSE.

Any suggestions? Did I missed some important change in ViewHelpers API since 7.x- ?

Of course if extension is cached it will be not visible, as the first hit will be saved in cache with proper VH return.


回答1:


The AbstractConditionViewHelper implements the TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface interface. This means that it implements a compile method that actually returns PHP code that will be stored in the compiled Fluid views.

Have a look at this method in the source code:

 public function compile($argumentsVariableName, $renderChildrenClosureVariableName, &$initializationPhpCode, \TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\AbstractNode $syntaxTreeNode, \TYPO3\CMS\Fluid\Core\Compiler\TemplateCompiler $templateCompiler)
 {
     foreach ($syntaxTreeNode->getChildNodes() as $childNode) {
         if ($childNode instanceof ViewHelperNode
             && $childNode->getViewHelperClassName() === ThenViewHelper::class) {
             $childNodesAsClosure = $templateCompiler->wrapChildNodesInClosure($childNode);
             $initializationPhpCode .= sprintf('%s[\'__thenClosure\'] = %s;', $argumentsVariableName, $childNodesAsClosure) . LF;
         }
         if ($childNode instanceof ViewHelperNode
             && $childNode->getViewHelperClassName() === ElseViewHelper::class) {
             $childNodesAsClosure = $templateCompiler->wrapChildNodesInClosure($childNode);
             $initializationPhpCode .= sprintf('%s[\'__elseClosure\'] = %s;', $argumentsVariableName, $childNodesAsClosure) . LF;
         }
     }

     return sprintf('%s::renderStatic(%s, %s, $renderingContext)',
         get_class($this), $argumentsVariableName, $renderChildrenClosureVariableName);
 }

Once compiled, the render() method will not be called anymore (it will on the first invocation, when the template is not yet compiled). Instead, the renderStatic() method will be called.

Solution: You can either

  1. also override the renderStatic() method and implement your ViewHelper logic there (again)
  2. not implement the render() method and simply overwrite the static evaluateCondition($arguments) method. This method is actually designed to be overwritten -- the default implementations of both render() and renderStatic() call this method:

    This method decides if the condition is TRUE or FALSE. It can be overriden in extending viewhelpers to adjust functionality.

    static protected function evaluateCondition($arguments = null)
    {
        $requiredArray = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $arguments['requiredFields'], true);
        return (in_array($arguments['fieldName'], $requiredArray));
    }
    



回答2:


The quickest solution is to overwrite the class render and evaluateCondition like this:

public function initializeArguments()
   {
        parent::initializeArguments();
        $this->registerArgument('yourArgument','array','',true);
   }

public function render() 
    {
        return self::evaluateCondition($this->arguments) ? $this->renderThenChild() : $this->renderElseChild();
    }

/**
 * @return bool
 */
protected static function evaluateCondition($arguments = null) 
    {
         //do your stuff
         return true;
    }


来源:https://stackoverflow.com/questions/34729014/typo3-ver-7-6-2-condition-viewhelpers-evaluated-only-once

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!