TYPO3 Жидкий комплекс, если условия

Я пытаюсь написать следующее, если условие в жидкости, но оно не работает, как я надеюсь.

Условие Как часть цикла for я хочу проверить, является ли элемент первым или четвертым, восьмым и т.д.

Я бы подумал, что следующее будет работать, но он отображает код для каждой итерации.

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

Мне удалось заставить его работать с вложенным if, но он просто чувствует себя неправильно, имея один и тот же раздел кода дважды, а также с проверкой цикла использует <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>

Ответ 1

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>

Что может быть более подходящим для некоторых случаев (особенно при использовании условие в встроенном синтаксисе, где вы не можете перейти в режим тега в чтобы получить доступ к f: else с новым аргументом if).

TYPO3 6.2 LTS и 7 LTS

Для более сложных if-Conditions (например, нескольких или/и комбинаций) вы можете добавить свой собственный ViewHelper в your_extension/Classes/ViewHelpers/. Вам просто нужно расширить Fluids AbstractConditionViewHelper. Простой if-ViewHelper, который поставляется с Fluid, выглядит так:

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 и т.д. Затем вы просто пишете свои if-условия в php и визуализируете то или еще ребенок. Для вашего примера вы можете пойти примерно так:

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();
        }
    }
}

Файл будет в вашем_экстенде/Classes/ViewHelpers/ExtendedIfViewHelper.php. Затем вы должны добавить свое пространство имен в Fluid-Template, подобное этому (что позволяет использовать все ваши самозанятые ViewHelpers из вашего_экземпляра/Classes/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>

Изменить: обновлено.

Ответ 2

Обновление этой информации с текущей ситуацией:

В 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).

Ответ 4

Вы также можете использовать If Condition Extend ViewHelper, предоставленный VHS расширение:

<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 предоставляет множество полезных ViewHelpers. Я чувствую, что многие из них должны быть включены в жидкость TYPO3.

Ответ 5

Для многих случаев достаточно использовать сравнение массива, поэтому вам не нужно создавать настраиваемый помощник вида.

и

<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: (с этим сравнением массива вы также можете сравнить строки)

Ответ 6

В дополнение к ответу Дэниелса я сделал ViewHelper, который принимает несколько условий, либо с "и" -модом (по умолчанию), либо с "или" -mode:

<?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, потому что мне не нравится писать один и тот же код дважды. Таким образом, вы можете дополнительно сэкономить жидкость и передать ее как контейнерам с успехом, так и отказам без необходимости повторения.

Ответ 8

Для меня лучший способ использовать "f: цикл". Если мне нужно выделить для строк три элемента, которые я просто делаю:

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

Ответ 9

Если у вас есть 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')}">

Ответ 10

Можно реализовать сложные условия if с комбинацией f: if, v: variable.set и v: math. Используйте математический ViewHelper, чтобы выполнить магию и сохраните ее результат в переменной. Затем используйте, если компараторы проверяют и действуют на него.

Вот мой пример кода:

<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. Это переменная и может быть задана в конфигурации плагина. Он использует modulo для вычисления iterator.cycle(счетчик, начинающийся с 1) mod settings.itemsperrow. Если результат равен 1, это первый элемент строки. 0 означает, что он последний, поэтому строка должна быть закрыта.

Ответ 11

Статус 2017:

Вот пример современного состояния VHS viewhelper с использованием атрибута стека. Этот пример также содержит проверку NULL и логическую или (||), чтобы показать, как это делается.

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

Учтите, что NULL НЕ цитируется!