Пользовательская TYPO3Fluid inArray viewhelper не работает должным образом при первой загрузке страницы - PullRequest
0 голосов
/ 16 октября 2019

Я использую TYPO3Fluid для своего пользовательского (автономного) приложения (без TYPO3 CMS).

Мой пользовательский inArray-ViewHelper не работает должным образом.

При первом вызове страницы онкажется, игнорируется (никакой код не выполняется внутри viewhelper). Но при втором вызове страницы viewhelper выполняется и работает (надеюсь) как и ожидалось.

Кроме того, viewhelper работает, только если включено кэширование, если отключено, он просто возвращает else-часть.

<?php
namespace TYPO3Fluid\Fluid\ViewHelpers;

use TYPO3Fluid\Fluid\Core\Compiler\TemplateCompiler;
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;

class InArrayViewHelper extends \TYPO3Fluid\Fluid\Core\ViewHelper\AbstractConditionViewHelper {

    /**
     * We accept value and children interchangeably, thus we must disable children escaping.
     *
     * @var bool
     */
    protected $escapeChildren = false;

    /**
     * If we decode, we must not encode again after that.
     *
     * @var bool
     */
    protected $escapeOutput = false;

    public function initializeArguments() {
        parent::initializeArguments();
        $this->registerArgument('haystack', 'mixed', 'View helper haystack ', TRUE);
        $this->registerArgument('needle', 'string', 'View helper needle', TRUE);
    }

    /**
     * @param array $arguments
     * @param \Closure $renderChildrenClosure
     * @param RenderingContextInterface $renderingContext
     * @return mixed
     */
    public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext){
        $needle = $arguments['needle'];
        $haystack = $arguments['haystack'];

        if(!is_array($haystack)) {
            return $this->renderElseChild();
        }else {
            if (in_array($needle, $haystack)) {
                if (isset($arguments['then'])) {
                    return $arguments['then'];
                }
                if (isset($arguments['__thenClosure'])) {
                    return $arguments['__thenClosure']();
                }
            }  elseif (!empty($arguments['__elseClosures'])) {
                $elseIfClosures = isset($arguments['__elseifClosures']) ? $arguments['__elseifClosures'] : [];
                return static::evaluateElseClosures($arguments['__elseClosures'], $elseIfClosures, $renderingContext);
            } elseif (array_key_exists('else', $arguments)){
                return $arguments['else'];
            }
            return '';
        }
    }

    /**
     * @param array $closures
     * @param array $conditionClosures
     * @param RenderingContextInterface $renderingContext
     * @return string
     */
    private static function evaluateElseClosures(array $closures, array $conditionClosures, RenderingContextInterface $renderingContext)
    {
        foreach ($closures as $elseNodeIndex => $elseNodeClosure) {
            if (!isset($conditionClosures[$elseNodeIndex])) {
                return $elseNodeClosure();
            } else {
                if ($conditionClosures[$elseNodeIndex]()) {
                    return $elseNodeClosure();
                }
            }
        }
        return '';
    }
}

У кого-нибудь есть идея, чтобы это исправить? Или кто-нибудь знает лучшее решение для inArray?

EDIT:

Хорошо, как сказано в документации, renderStatic () нельзя использовать для viewhelper, которому нужен доступ к своим потомкам. Так что я не могу использовать renderStatic () здесь. Я попытался использовать render (), который доставил мне больше проблем, потому что тогда первая загрузка страницы дала 500! Поэтому я перешел на compile () как метод рендеринга. Теперь я могу использовать мой viewhelper в качестве аргумента внутри условия if. Это нормально и работает.

Новые проблемы:

  • Песчаный Я не могу использовать его внутри условия inline-if-условие! Грустно!
  • Приходится использовать -Tag вокруг моего состояния, в других случаях результат будет ложным каждый раз.

Теперь окно справки выглядит так

<?php
namespace TYPO3Fluid\Fluid\ViewHelpers;

use TYPO3Fluid\Fluid\Core\Compiler\TemplateCompiler;
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;

class InArrayViewHelper extends \TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper {

    use CompileWithRenderStatic;

    public function initializeArguments() {
        parent::initializeArguments();
        $this->registerArgument('haystack', 'mixed', 'View helper haystack ', TRUE);
        $this->registerArgument('needle', 'string', 'View helper needle', TRUE);
    }

    public static function renderStatic(
        array $arguments,
        \Closure $renderChildrenClosure,
        RenderingContextInterface $renderingContext
    ) {
        return in_array($arguments['needle'], $arguments['haystack']);
    }

    public function compile(
        $argumentsName,
        $closureName,
        &$initializationPhpCode,
        ViewHelperNode $node,
        TemplateCompiler $compiler
    ) {
        return 'in_array('.$argumentsName.'[\'needle\'],'. $argumentsName.'[\'haystack\'])';
    }
}

РЕДАКТИРОВАТЬ2:

Я сделал некоторые изменения в compile () - возможно, это сработает.

EDIT 3:

Я попытался переписать класс IfViewHelper. Но это, к сожалению, не работает. Значения и результат in_array такие же, как ожидалось, но отображаемое значение всегда ложно.

<?php
namespace TYPO3Fluid\Fluid\ViewHelpers;

use TYPO3Fluid\Fluid\Core\Compiler\TemplateCompiler;
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;

class InArrayViewHelper extends \TYPO3Fluid\Fluid\ViewHelpers\IfViewHelper {

    use CompileWithRenderStatic;

    public function initializeArguments() {
        parent::initializeArguments();
        $this->registerArgument('haystack', 'mixed', 'View helper haystack ', TRUE);
        $this->registerArgument('needle', 'string', 'View helper needle', TRUE);
    }

    /**
     * @param array $arguments
     * @param RenderingContextInterface $renderingContext
     * @return bool
     */
    public static function verdict(array $arguments, RenderingContextInterface $renderingContext)
    {
        return in_array($arguments['needle'], $arguments['haystack']);
    }
}

Поэтому я использую второй код и отключаю кеш вокруг условия. Работает, но без возможности использовать его в inline-if-условии.

1 Ответ

0 голосов
/ 16 октября 2019

Метод компиляции предназначен для генерации кода PHP и в большинстве случаев не должен переопределяться, если вы не знаете, что делаете:

/**
 * You only should override this method *when you absolutely know what you
 * are doing*, and really want to influence the generated PHP code during
 * template compilation directly.
 * ...

Код, который вы разместили выше в своем методе компиляциитак или иначе не работает ($ аргументов в этом методе не существует).

Вместо того, чтобы переопределять условие if, я бы порекомендовал создать простой InArrayViewHelper, который просто возвращает true или false, а затем использовать его как:

<f:if condition="{x:inArray(haystack: haystack, needle: needle)}"> ... </f:if>

Но если это должен быть пользовательский if-подобный ViewHelper, возможно, вы захотите взглянуть на расширение класса \TYPO3Fluid\Fluid\Core\ViewHelper\AbstractConditionViewHelper вместо стандартного AbstractViewHelper.

Как я вижудля этого достаточно просто расширить этот класс и только переопределить initializeArguments для регистрации аргумента и метод verdict, который будет содержать ваш вызов in_array и вернуть bool.

Также взгляните на: \TYPO3Fluid\Fluid\ViewHelpers\IfViewHelper

...