【问题标题】:TYPO3 Fluid complex if conditionsTYPO3 Fluid complex if 条件
【发布时间】:2013-11-12 21:54:33
【问题描述】:

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

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

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

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

我已经设法让它与嵌套的 if 一起工作,但是两次使用相同的代码部分并且让循环检查使用 &lt;f:else&gt; 而不是 == 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>

【问题讨论】:

    标签: typo3 fluid


    【解决方案1】:

    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 没有被引用!

    【讨论】:

      【解决方案2】:

      可以使用 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 (counter 以 1 开始) mod settings.itemsperrow。如果结果为 1,则它是行的第一个元素。 0 表示它是最后一个,所以必须关闭行。

      【讨论】:

        【解决方案3】:

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

        <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:(通过这个数组比较你也可以比较字符串)

        【讨论】:

          【解决方案4】:

          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/ 中添加自己的 ViewHelper。你只需要扩展流体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 更多的参数,例如 $or$and$not 等。然后您只需在 php 中编写 if-Conditions 并渲染那么要不然孩子。对于您的示例,您可以使用以下内容:

          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>
          

          编辑:更新。

          【讨论】:

          • 感谢帮助者的帮助。我的示例将在 4 日做某事,因为它使用了 else,然后是当有一个余数一开始让我感到困惑时。 &lt;f:if condition="{rank} % 2"&gt;Will be shown if rank % 2 != 0.&lt;/f:if&gt;
          • 啊,你当然是对的。我的错。所以 viewHelper 也需要调整 ;)
          • 我稍后会验证结果,但我相信您的代码会运行良好。谢谢
          • 太棒了!这应该教会我不要害怕自己的 VH。但有一件事:当在 Localconfig 中设置 'exceptionalErrors' =&gt; 28674, 时,使用当前 7.6 和 PHP 7 的 7LTS 代码会引发错误 #1289386765: Could not analyse class: "STUBR\Template\ViewHelpers\OrViewHelper" maybe not loaded or no autoloader? PHP Warning: Declaration of STUBR\Template\ViewHelpers\OrViewHelper::render($condition, $or) should be compatible with TYPO3\CMS\Fluid\Core\ViewHelper\AbstractConditionViewHelper::render() in /home/user/public_html/typo3conf/ext/template/Classes/ViewHelpers/OrViewHelper.php line 34
          • 我在 forge.typo3.org/issues/76146 上发现这与 log_level E_STRICT 有关,可以通过将其关闭来关闭。但仍然:是否应该以某种方式修改 VH 以兼容?
          【解决方案5】:

          如果您有 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')}">
          

          【讨论】:

            【解决方案6】:

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

            在 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)。

            【讨论】:

            【解决方案7】:

            对我来说,使用“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>
            

            【讨论】:

              【解决方案8】:

              除了 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>
              

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

              【讨论】:

                【解决方案9】:

                是的,它感觉不对,但这是你能做到的唯一方法。这是一个非常适合查看助手的网站 :: https://fluidtypo3.org/viewhelpers/fluid/master/IfViewHelper.html

                【讨论】:

                • 感谢您的回答。我想知道是否有人考虑过或组合了一个视图助手来处理更复杂的条件?
                • 停止特别为 TYPO3 和 Fluid 辩护。很遗憾,您需要变通方法来执行布尔条件,这很尴尬。 TYPO3 是用 PHP 编写的。为什么不使用它? &lt;f:if condition="..."&gt; 不完整,&lt;? if (...): ?&gt; 不完整。它是完整的。成熟的,经过数百万开发人员使用多年的测试。在解析流畅的语法以显示网站时接受这种额外的开销只是愚蠢的。如果需要,视图仍然可以与逻辑分离,同时使用相同的语言来保留 MVC 概念。
                【解决方案10】:

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

                【讨论】:

                  【解决方案11】:

                  您也可以使用VHS extension提供的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中。

                  【讨论】:

                  • 今天这种情况看起来不同了,&lt;v:if stack="{0: dateObject, 1: '&gt;', 2: NowDateObject, 3: 'AND', 4: objecteValue, 5: '&gt;', 6: 1}"&gt; &lt;f:then&gt;IF THEN&lt;/f:then&gt; &lt;f:else&gt;IF ELSE&lt;/f:else&gt; &lt;/v:if&gt;fluidtypo3.org/viewhelpers/vhs/master/IfViewHelper.html
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-05-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-01-04
                  相关资源
                  最近更新 更多