PhpStorm 无法识别 TYPO3 Fluid 结束标签

PhpStorm not recognizing TYPO3 Fluid closing tags

我有一个 Fluid 模板,我将列表分成 4 组,例如:

<ul>
<f:for each="{items}" as="item" iteration="i">
    <li>(CONTENT HERE)</li>
    <f:if condition="{i.cycle} % 4">
</ul>
<ul>
    </f:if>
</f:for>
</ul>

我已将 Fluid XML 命名空间添加到我的项目 like this,但 PhpStorm 仍然通知我我的结束 </f:if> 标记 'matches nothing'.

有没有办法配置 PhpStorm 来识别这个结构?

我在 <f:if> 中包裹结束和开始标记是否违反了最佳实践?

PHP Storm 验证的第一件事是 XML/HTML 的正确嵌套 - 就像标签一样,在你的示例中你无情地破坏它(从 IDE 的角度来看,不是据我所知,需要在 Fluid 中使用模 break),添加有效的 XML 命名空间甚至禁用 [=41= 都没关系]检查员。

更重要的是 聪明 即使在 then 通知中也能识别标签(该死的!),这也将显示IDE级错误:

<ul>
    <f:for each="{items}" as="item" iteration="i">
        <li>Item {i.cycle}</li>
        {f:if(condition: '{i.cycle} % 4', then: '</ul><ul>')}
    </f:for>
</ul>

到目前为止,我发现并在许多项目中成功使用的唯一解决方案是自定义 ext 中的自定义 ViewHelper(对于 IDE,重要的是在 endTag 之前声明 startTage !):

<?php
namespace Vendor\Myext\ViewHelpers;
/**
 * {namespace myNs=Vendor\Myext\ViewHelpers}
 *
 * = Inline samples
 *
 * === Break the list:
 * {myNs:breakTagByModulo(iterator: i, modulo: 2)}
 * or...
 * {myNs:breakTagByModulo(iterator: i, modulo: 2, startTag: '<ul class="next-level">', endTag: '</ul>')}
 *
 *  result on valid modulo:
 *  </ul><ul class="next-level">
 *
 * === Break the Bootstrap row:
 * {myNs:breakTagByModulo(iterator: i, modulo: 2, startTag: '<div class="row">', endTag: '</div>')}
 * 
 *  result on valid modulo:
 *  </div><div class="row">
 *  
 * etc...
 */
class BreakTagByModuloViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper {

    /**
     * @param array   $iterator Iterator from `f:for` VH
     * @param integer $modulo   Modulo to check
     * @param boolean $skipLast If skipLast==true VH will return false even if condition is correct, needed for `not full` lists
     * @param string  $startTag Begin of the tag
     * @param string  $endTag   End of the tag
     *
     * @return bool|string
     */
    public function render($iterator, $modulo, $skipLast = true, $startTag = '<ul>', $endTag = '</ul>') {
        $i = $iterator['cycle'];
        $bool = ($i % $modulo == 0);
        if ($skipLast && $iterator['isLast']) {
            $bool = false;
        }

        return ($bool) ? $endTag . $startTag : null;
    }
}

?>

视图中的用法如上所示,仅对于您的示例,它类似于:

{namespace myNs=Vendor\Myext\ViewHelpers}

<ul>
    <f:for each="{items}" as="item" iteration="i">
        <li>(CONTENT HERE)</li>
        {myNs:breakTagByModulo(iterator: i, modulo: 4)}
    </f:for>
</ul>

(当然,您要用自己的值替换 myNsVendorMyext

我受到了 LazyOne 的评论和 Biesior 的回答的启发。采取以下措施:

<ul>
    <f:for each="{items}" as="item" iteration="i">
        <li>Item {i.cycle}</li>
        {f:if(condition: '{i.cycle} % 4', else: '</ul><ul>')}
    </f:for>
</ul>

我尝试用 HTML 实体和 Unicode 转义序列替换尖括号,两者都完整输出。然后我想到做字符替换。我找到了 v:format.replace viewhelper,并执行了以下操作:

<v:format.replace substring="(" replacement="<"><v:format.replace substring=")" replacement=">">{f:if(condition: '{iter.cycle} % 4', else: '(/ul)(ul)')}</v:format.replace></v:format.replace>

也就是说,我在我的代码中放入了括号,并将它们切换为尖括号以用于输出。

所以对于任何想使用它的人来说,都有一个冗长得可笑的选项。

我建议采用不同的方法来确保稳固的 html 结构。混合模板 HTML 和来自视图助手的 HTML 似乎是一个危险的想法,当开始标签来自一个而结束标签来自另一个时。

由于将列表拆分成块似乎是逻辑上的必要性而不是表象,因此其逻辑应该发生在控制器而不是视图中。如果出于某种原因,您无法更改控制器逻辑(第 3 方扩展?),您应该求助于小部件/视图助手。在那里,您可以使用纯 PHP 将列表拆分为 4 组,然后使用循环迭代模板中的集合。这样,HTML 将不易损坏,更易于维护且更易于理解(对您和 PHPSTORM)。