5

问题:我写了一个有条件的 VH(扩展AbstractConditionViewHelper)并且它像往常一样工作,无论如何我意识到在非缓存版本中它只被评估一次。最初我认为这是我的错误,但检查常见<f:if> 问题是相同的:S

一般来说,当我第一次访问我的页面时,会评估条件并给出有效结果,但是当我刷新页面时,不再调用 VH(通过在 VH 内设置断点进行检查)并且 VH 始终被视为错误的。只有视图代码中的任何更改都会导致 VH 将被评估一次,并且下一次刷新将不再调用 VH。

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();
    }
}

用法:

{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>

对于第一个打击我有TRUE但后来只有FALSE

有什么建议么?自 7.x- 以来,我是否错过了 ViewHelpers API 的一些重要变化?

当然,如果扩展被缓存,它将不可见,因为第一个命中将保存在缓存中并返回适当的 VH。

4

2 回答 2

10

AbstractConditionViewHelper实现TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface接口。这意味着它实现了一个compile实际返回 PHP 代码的方法,该代码将存储在已编译的 Fluid 视图中。

在源代码中查看此方法:

 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);
 }

编译后,render()将不再调用该方法(它将在第一次调用时,模板尚未编译时)。相反,renderStatic()将调用该方法。

解决方案:您可以

  1. 还覆盖该renderStatic()方法并在那里(再次)实现您的 ViewHelper 逻辑
  2. 不实现该render()方法并简单地覆盖静态evaluateCondition($arguments)方法。这个方法实际上被设计为被覆盖——两者的默认实现render()renderStatic()调用这个方法:

    此方法决定条件是 TRUE 还是 FALSE。它可以在扩展 viewhelpers 以调整功能时被覆盖。

    static protected function evaluateCondition($arguments = null)
    {
        $requiredArray = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $arguments['requiredFields'], true);
        return (in_array($arguments['fieldName'], $requiredArray));
    }
    
于 2016-01-12T12:16:58.683 回答
0

最快的解决方案是像这样覆盖类渲染和评估条件:

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;
    }
于 2018-07-13T09:40:18.937 回答