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()
метод будет вызван.
Решение: Вы можете либо
- также переопределить
renderStatic()
метод и реализовать свою логику ViewHelper там (снова) не реализовать
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;
}