15

我正在尝试在流体中编写以下 if 条件,但它没有像我希望的那样工作。

条件 作为 for 循环的一部分,我想检查项目是第一个还是第 4 个、第 8 个等

我原以为以下内容会起作用,但它会显示每次迭代的代码。

<f:if condition="{logoIterator.isFirst} || {logoIterator.cycle % 4} == 0">

我已经设法让它与嵌套的 if 一起工作,但是两次使用相同的代码部分并且还让循环检查使用 a<f:else>而不是 == 0感觉不对

<f:if condition="{logoIterator.isFirst}">
    <f:then>
        Do Something
    </f:then>
    <f:else>
        <f:if condition="{logoIterator.cycle} % 4">
            <f:else>
                Do Something
            </f:else>
        </f:if>
    </f:else>
</f:if>
4

11 回答 11

25

TYPO3 v8

更新了 TYPO3 v8 的答案。这引自克劳斯的回答如下:

根据当前情况更新此信息:

在 TYPO3v8 及更高版本上,支持以下语法,非常适合您的用例:

<f:if condition="{logoIterator.isFirst}">
    <f:then>First</f:then>
    <f:else if="{logoIterator.cycle % 4}">n4th</f:else>
    <f:else if="{logoIterator.cycle % 8}">n8th</f:else>
    <f:else>Not first, not n4th, not n8th - fallback/normal</f:else>
</f:if>

此外,还支持这样的语法:

<f:if condition="{logoIterator.isFirst} || {logoIterator.cycle} % 4">
    Is first or n4th
</f:if>

这对于某些情况可能更合适(特别是在使用内联语法中的条件时,您无法扩展为标记模式以便使用新的 if 参数访问 f:else)。

TYPO3 6.2 LTS 和 7 LTS

对于更复杂的 if 条件(如几个或/和组合),您可以在your_extension/Classes/ViewHelpers/. 你只需要扩展 Fluids AbstractConditionViewHelper。Fluid 附带的简单 if-ViewHelper 如下所示:

class IfViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractConditionViewHelper {

    /**
     * renders <f:then> child if $condition is true, otherwise renders <f:else> child.
     *
     * @param boolean $condition View helper condition
     * @return string the rendered string
     * @api
     */
    public function render($condition) {
        if ($condition) {
            return $this->renderThenChild();
        } else {
            return $this->renderElseChild();
        }
    }
}

您在自己的 ViewHelper 中所要做的就是添加比$condition, like $or,$and等更多的参数$not。然后您只需在 php 中编写 if-Conditions 并呈现 then 或 else 子项。对于您的示例,您可以使用以下内容:

class ExtendedIfViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractConditionViewHelper {

    /**
     * renders <f:then> child if $condition or $or is true, otherwise renders <f:else> child.
     *
     * @param boolean $condition View helper condition
     * @param boolean $or View helper condition
     * @return string the rendered string
     */
    public function render($condition, $or) {
        if ($condition || $or) {
            return $this->renderThenChild();
        } else {
            return $this->renderElseChild();
        }
    }
}

该文件将位于 your_extension/Classes/ViewHelpers/ExtendedIfViewHelper.php 然后您必须像这样在 Fluid-Template 中添加您的命名空间(这将启用模板中 your_extension/Classes/ViewHelpers/ 中的所有您自己编写的 ViewHelpers:

{namespace vh=Vendor\YourExtension\ViewHelpers}

并像这样在您的模板中调用它:

<vh:extendedIf condition="{logoIterator.isFirst}" or="{logoIterator.cycle} % 4">
  <f:then>Do something</f:then>
  <f:else>Do something else</f:else>
</vh:extendedIf>

编辑:更新。

于 2013-11-02T10:29:55.207 回答
13

根据当前情况更新此信息:

在 TYPO3v8 及更高版本上,支持以下语法,非常适合您的用例:

<f:if condition="{logoIterator.isFirst}">
    <f:then>First</f:then>
    <f:else if="{logoIterator.cycle % 4}">n4th</f:else>
    <f:else if="{logoIterator.cycle % 8}">n8th</f:else>
    <f:else>Not first, not n4th, not n8th - fallback/normal</f:else>
</f:if>

此外,还支持这样的语法:

<f:if condition="{logoIterator.isFirst} || {logoIterator.cycle} % 4">
    Is first or n4th
</f:if>

这可能更适合某些情况(特别是在使用内联语法中的条件时,您无法扩展为标记模式以便f:else使用新if参数访问 )。

于 2016-05-23T13:31:01.347 回答
6

v:if.condition 将在 vhs V2.0 中弃用,使用 v:if 堆栈代替: https ://github.com/FluidTYPO3/vhs/issues/493

于 2014-03-12T08:57:16.763 回答
4

您还可以使用VHS 扩展提供的If Condition Extend ViewHelper

<v:if.condition>
    <v:if.condition.extend>
        {logoIterator.isFirst} || {logoIterator.cycle % 4} == 0
    </v:if.condition.extend>
    <f:then>Output if TRUE</f:then>
    <f:else>Output if FALSE</f:else>
</v:if.condition>

附带说明:VHS 扩展提供了许多有用的 ViewHelper。我觉得很多应该包含在 TYPO3 Fluid 中。

于 2013-11-18T14:40:55.400 回答
4

在许多情况下,使用数组比较就足够了——因此您不必创建自定义视图助手。

<f:if condition="{0:user.number,1:user.zip}=={0:123,1:01234}">

或者

<f:if condition="{0:user.number,1:user.zip}!={0:false,1:false}">

可悲的是,这仅用于检查是否设置了变量而不是针对值。但对于许多情况,这已经足够了。

PS:(通过这个数组比较你也可以比较字符串)

于 2016-06-13T12:17:27.280 回答
1

除了 Daniels 的回答之外,我还制作了一个 ViewHelper,它接受多个条件,使用“and”模式(默认)或“or”模式:

<?php
namespace TLID\Contentelements\ViewHelpers;

class IfViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper {
  /**
   * Checks conditions
   *
   * @param mixed $checks
   * @param string $type
   *
   * @return boolean whether is array or not
   */
  public function render($checks, $type = "and") {
    $success = $type === "and" ? true : false;
    $doc = new \DOMDocument();
    $doc->loadHTML($this->renderChildren());
    $xpath = new \DOMXpath($doc);

    // get store values
    $storeNodes = $xpath->query("//body/store");
    $store = "";
    foreach ($storeNodes as $storeNode) {
      foreach ($storeNode->childNodes as $childNode) {
        $store .= $doc->saveHTML($childNode);
      }
    }

    // do the actual check
    foreach ($checks as $check) {
      if (
        ($type === "and" && (is_array($check) && count($check) === 0 || is_object($check) && get_object_vars($check) === 0 || empty($check))) ||
        (is_array($check) && count($check) !== 0 || is_object($check) && get_object_vars($check) !== 0 || !empty($check))
      ) {
        $success = $type === 'and' ? false : true;
        break;
      }
    }

    // render content
    $renderQueryElement = $success ? "success" : "failure";
    $renderNodes = $xpath->query("//body/" . $renderQueryElement);
    $content = "";
    foreach ($renderNodes as $renderNode) {
      foreach ($renderNode->childNodes as $childNode) {
        $content .= $doc->saveHTML($childNode);
      }
    }

    //insert contents
    $matches;
    $content = preg_replace("/<use[^>]*><\/use>/", $store, $content);

    //return rendered content
    return $content;
  }
}
?>

虽然它可以写得更好,但它确实有效。这是我如何使用它:

{namespace vhs=TLID\contentelements\ViewHelpers}

<vhs:if checks="{0: settings.link}">
  <f:comment><!-- store the content --></f:comment>
  <store>
    <f:if condition="{images}">
      <f:for each="{images}" as="image">
        <f:image image="{image}" alt="{image.description}" title="{image.title}" />
      </f:for>
    </f:if>

    <vhs:if checks="{0: settings.headline, 1: settings.text}" type="or">
      <success>
        <div>
          <f:if condition="{settings.headline}"><h2><f:format.nl2br><vhs:shy>{settings.headline}</vhs:shy></f:format.nl2br></h2></f:if>
          <f:if condition="{settings.text}"><p><f:format.nl2br><vhs:shy>{settings.text}</vhs:shy></f:format.nl2br></p></f:if>
        </div>        
      </success>
    </vhs:if>
  </store>

  <f:comment><!-- use the content of this container on success --></f:comment>
  <success>
    <vhs:link href="{settings.link}" target="{settings.target}" class="box">
      <use />
    </vhs:link>
  </success>

  <f:comment><!-- use the content of this container on failure --></f:comment>
  <failure>
    <div class="box">
      <use />
    </div>
  </failure>
</vhs:if>

它还有一个存储元素,因为我不喜欢它两次编写相同的代码。因此,您可以选择保存一些流体并将其传递给成功和失败容器,而无需重复。

于 2015-09-07T14:26:05.107 回答
1

可以使用f:if、v:variable.setv:math的组合来实现复杂的 if 条件。使用数学 ViewHelper 来执行魔术并将其结果存储在变量中。然后使用 if 比较器对其进行验证和操作。

这是我的示例代码:

<f:for each="{customers}" as="customer" iteration="iterator">
    <v:variable.set name="isFirst" value="{v:math.modulo(a: iterator.cycle, b: settings.itemsperrow, fail: 0)}" />
    <f:if condition="{isFirst}==1">
        <div class="row">
    </f:if>
    <div class="col-md-{settings.colWidth}">
        <div class="clientlogo_ref">
            <f:image src="{customer.logo.originalResource.publicUrl}" />
        </div>                 
    </div>
    <f:if condition="{isFirst}==0">
        </div>
    </f:if>
</f:for>

此代码开始/结束每个 X 项目的网格行,由settings.itemsperrow定义。这是可变的,可以在插件的配置中设置。它使用模来计算iterator.cycle (以 1 开头的计数器) mod settings.itemsperrow。如果结果为 1,则它是行的第一个元素。0 表示它是最后一个,因此必须关闭行。

于 2016-11-10T14:52:02.643 回答
0

是的,它感觉不对,但这是你能做到的唯一方法。这是一个非常好的 viewhelper 站点 :: https://fluidtypo3.org/viewhelpers/fluid/master/IfViewHelper.html

于 2013-11-01T17:46:34.617 回答
0

对我来说使用'f:cycle'的最佳方式。如果我需要为每个第 3 个元素分配行,我只需这样做:

<v:variable.set  name="wraper" value='</div><div class="row">' />
<f:for each="{items}" as="item" iteration="itemIterator">
 ....
   <f:cycle values="{0: '', 1: '', 2: '{wraper}'}" as="cycle">
        {cycle -> f:format.raw()}
  </f:cycle>
 ...
</f:for>
于 2016-03-11T15:49:23.143 回答
0

如果您有 CObjects 帮助解决逻辑 OR 的问题:

# Sidebar | 1 ColPos = 78
lib.sidebar1 < styles.content.get
lib.sidebar1.select.where = colPos=78
# Sidebar | 2 ColPos = 79
lib.sidebar2 < styles.content.get
lib.sidebar2.select.where = colPos=79

#LogicalOR
lib.tempLogicalOrSidebar = COA
lib.tempLogicalOrSidebar {
    10 < lib.sidebar1
    10.stdWrap.override.cObject =< lib.sidebar2
}

流体条件:

<f:if condition="{f:cObject(typoscriptObjectPath: 'lib.tempLogicalOrSidebar.10')}">
于 2016-06-27T08:02:37.757 回答
0

2017 年状态:

这是一个使用堆栈属性的现代 VHS 视图助手条件的示例。此示例还包含一个 NULL 检查和一个逻辑或 ( ||) 以显示它是如何完成的。

<v:if stack="{0: '{itemId}', 1:'==', 2:NULL, 3: '||', 4: '{itemId}', 5: '==', 6: '{falMedia.uid}'}">
    <f:then>
    ...
    </f:then>
</v:if>

注意NULL没有引用!

于 2017-03-03T15:44:21.930 回答