TYPO3 вер. 7.6.2 - Условие ViewHelpers оценивается только один раз

Проблема: я написал условный VH (расширение AbstractConditionViewHelper) и работает как обычно, во всяком случае я понял, что в не кешированной версии он оценивается только один раз. Изначально я думал, что это моя ошибка, но проверил общий <f:if> и проблема идентична:S

В общем, когда я впервые захожу на мою страницу, условие оценивается и выдается действительный результат, но когда я обновлю страницу, VH больше не вызывается (проверяется путем установки точки останова внутри VH), а VH всегда обрабатывается как ЛОЖНЫЙ. Только любое изменение в коде представления приведет к тому, что VH будет оцениваться один раз, и снова следующее обновление (я) больше не будет вызывать VH.

typo3conf / внутр / Инструментальный ящик / Классы / 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,

Какие-либо предложения? Я пропустил некоторые важные изменения в API ViewHelpers после 7.x-?

Конечно, если расширение кэшируется, оно не будет видно, так как первое попадание будет сохранено в кеше с правильным возвратом VH.

2 ответа

Решение

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() вызвать этот метод:

    Этот метод решает, является ли условие ИСТИНА или ЛОЖЬ. Он может быть переопределен в расширении помощников вида для настройки функциональности.

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

Самое быстрое решение состоит в том, чтобы переписать класс render и оценивать условие следующим образом:

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;
    }
Другие вопросы по тегам