在 Fluid Template 中呈现 newsItems 的复杂 for/if 条件
Complex for/if conditions for rendering newsItems in Fluid Template
我正在为 Typo3 中的新闻扩展 tx_news 制作一个特殊模板。
我是 Typo3 的新手,尤其是 Fluid。
我想要的是恰好 4 个新闻条目的输出,但每个条目都必须有一个图像。
我需要的是编程逻辑,比如:
如果 newsItem 有图像,并且到目前为止渲染的项目少于 4 个,则渲染。否则什么都不做。
我读了这个问答:
TYPO3 Fluid complex if conditions
所以我怀疑我需要像 viewhelper 这样的东西。
到目前为止我的模板有这个输出项目的代码:
<f:for each="{news}" as="newsItem" iteration="iterator">
<f:if condition="{newsItem.falMedia}">
<f:if condition="{iterator.cycle}<=4">
<f:render partial="List/TeaserItem" arguments="{newsItem: newsItem,settings:settings,iterator:iterator, contentObjectData:contentObjectData}" />
</f:if>
</f:if>
</f:for>
但这当然会在遍历新闻4次后停止。因此,如果一个没有图像的条目没有得到渲染,我将只输出三个项目。
我需要一个类似这样的 if 条件:
if ({newsItem.falMedia} && {iterator.cycle}<=4){
render image }
else {iterator.cycle--}
但我不知道如何将我的 for 循环的迭代器变量传递给新的 viewhelper,尤其是如何将它传递回 for 循环。
简而言之,这种逻辑在 Fluid 中是不可能的——原因很简单——它是模板引擎。
您需要创建自己的扩展并在其中创建一个 ViewHelper,它将获取新闻的集合,将检查它是否具有所需的设置(falMedia
在这种情况下存在)并将 return 可以迭代的有限数组。事实上,重用 f:for
将是最快的解决方案。
恐怕只有这样了。
这是示例(将其与原始 f:for
viewhelper 进行比较):
<?php
namespace TYPO3\CMS\Fluid\ViewHelpers;
class ForNewsWithMediaViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper {
/**
* Iterates through elements of $each and renders child nodes
*
* @param array $each The array or \TYPO3\CMS\Extbase\Persistence\ObjectStorage to iterated over
* @param string $as The name of the iteration variable
* @param string $key The name of the variable to store the current array key
* @param boolean $reverse If enabled, the iterator will start with the last element and proceed reversely
* @param string $iteration The name of the variable to store iteration information (index, cycle, isFirst, isLast, isEven, isOdd)
* @param int $limit Limit of the news items to show
* @return string Rendered string
* @api
*/
public function render($each, $as, $key = '', $reverse = FALSE, $iteration = NULL, $limit = NULL) {
return self::renderStatic($this->arguments, $this->buildRenderChildrenClosure(), $this->renderingContext, $limit);
}
/**
* @param array $arguments
* @param \Closure $renderChildrenClosure
* @param \TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface $renderingContext
* @param int $limit Limit of the news items to show
* @return string
* @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception
*/
static public function renderStatic(array $arguments, \Closure $renderChildrenClosure, \TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface $renderingContext, $limit = NULL) {
$templateVariableContainer = $renderingContext->getTemplateVariableContainer();
if ($arguments['each'] === NULL) {
return '';
}
if (is_object($arguments['each']) && !$arguments['each'] instanceof \Traversable) {
throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('ForViewHelper only supports arrays and objects implementing \Traversable interface', 1248728393);
}
if ($arguments['reverse'] === TRUE) {
// array_reverse only supports arrays
if (is_object($arguments['each'])) {
$arguments['each'] = iterator_to_array($arguments['each']);
}
$arguments['each'] = array_reverse($arguments['each']);
}
$iterationData = array(
'index' => 0,
'cycle' => 1,
'total' => count($arguments['each'])
);
$limitCycle = 1;
$output = '';
/**
* @type $singleElement Tx_News_Domain_Model_News
*/
foreach ($arguments['each'] as $keyValue => $singleElement) {
if (is_null($singleElement->getFalMedia())
|| !is_null($limit) && $limitCycle > $limit
) {
continue;
}
$limitCycle++;
$templateVariableContainer->add($arguments['as'], $singleElement);
if ($arguments['key'] !== '') {
$templateVariableContainer->add($arguments['key'], $keyValue);
}
if ($arguments['iteration'] !== NULL) {
$iterationData['isFirst'] = $iterationData['cycle'] === 1;
$iterationData['isLast'] = $iterationData['cycle'] === $iterationData['total'];
$iterationData['isEven'] = $iterationData['cycle'] % 2 === 0;
$iterationData['isOdd'] = !$iterationData['isEven'];
$templateVariableContainer->add($arguments['iteration'], $iterationData);
$iterationData['index']++;
$iterationData['cycle']++;
}
$output .= $renderChildrenClosure();
$templateVariableContainer->remove($arguments['as']);
if ($arguments['key'] !== '') {
$templateVariableContainer->remove($arguments['key']);
}
if ($arguments['iteration'] !== NULL) {
$templateVariableContainer->remove($arguments['iteration']);
}
}
return $output;
}
}
因此您可以在您的视图中将其用作:
<f:forNewsWithMedia each="{news}" as="newsItem" iteration="iterator" limit="4">
<f:render partial="List/TeaserItem" arguments="{newsItem: newsItem,settings:settings,iterator:iterator, contentObjectData:contentObjectData}" />
</f:forNewsWithMedia>
我正在为 Typo3 中的新闻扩展 tx_news 制作一个特殊模板。 我是 Typo3 的新手,尤其是 Fluid。
我想要的是恰好 4 个新闻条目的输出,但每个条目都必须有一个图像。
我需要的是编程逻辑,比如: 如果 newsItem 有图像,并且到目前为止渲染的项目少于 4 个,则渲染。否则什么都不做。
我读了这个问答: TYPO3 Fluid complex if conditions 所以我怀疑我需要像 viewhelper 这样的东西。
到目前为止我的模板有这个输出项目的代码:
<f:for each="{news}" as="newsItem" iteration="iterator">
<f:if condition="{newsItem.falMedia}">
<f:if condition="{iterator.cycle}<=4">
<f:render partial="List/TeaserItem" arguments="{newsItem: newsItem,settings:settings,iterator:iterator, contentObjectData:contentObjectData}" />
</f:if>
</f:if>
</f:for>
但这当然会在遍历新闻4次后停止。因此,如果一个没有图像的条目没有得到渲染,我将只输出三个项目。
我需要一个类似这样的 if 条件:
if ({newsItem.falMedia} && {iterator.cycle}<=4){
render image }
else {iterator.cycle--}
但我不知道如何将我的 for 循环的迭代器变量传递给新的 viewhelper,尤其是如何将它传递回 for 循环。
简而言之,这种逻辑在 Fluid 中是不可能的——原因很简单——它是模板引擎。
您需要创建自己的扩展并在其中创建一个 ViewHelper,它将获取新闻的集合,将检查它是否具有所需的设置(falMedia
在这种情况下存在)并将 return 可以迭代的有限数组。事实上,重用 f:for
将是最快的解决方案。
恐怕只有这样了。
这是示例(将其与原始 f:for
viewhelper 进行比较):
<?php
namespace TYPO3\CMS\Fluid\ViewHelpers;
class ForNewsWithMediaViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper {
/**
* Iterates through elements of $each and renders child nodes
*
* @param array $each The array or \TYPO3\CMS\Extbase\Persistence\ObjectStorage to iterated over
* @param string $as The name of the iteration variable
* @param string $key The name of the variable to store the current array key
* @param boolean $reverse If enabled, the iterator will start with the last element and proceed reversely
* @param string $iteration The name of the variable to store iteration information (index, cycle, isFirst, isLast, isEven, isOdd)
* @param int $limit Limit of the news items to show
* @return string Rendered string
* @api
*/
public function render($each, $as, $key = '', $reverse = FALSE, $iteration = NULL, $limit = NULL) {
return self::renderStatic($this->arguments, $this->buildRenderChildrenClosure(), $this->renderingContext, $limit);
}
/**
* @param array $arguments
* @param \Closure $renderChildrenClosure
* @param \TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface $renderingContext
* @param int $limit Limit of the news items to show
* @return string
* @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception
*/
static public function renderStatic(array $arguments, \Closure $renderChildrenClosure, \TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface $renderingContext, $limit = NULL) {
$templateVariableContainer = $renderingContext->getTemplateVariableContainer();
if ($arguments['each'] === NULL) {
return '';
}
if (is_object($arguments['each']) && !$arguments['each'] instanceof \Traversable) {
throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('ForViewHelper only supports arrays and objects implementing \Traversable interface', 1248728393);
}
if ($arguments['reverse'] === TRUE) {
// array_reverse only supports arrays
if (is_object($arguments['each'])) {
$arguments['each'] = iterator_to_array($arguments['each']);
}
$arguments['each'] = array_reverse($arguments['each']);
}
$iterationData = array(
'index' => 0,
'cycle' => 1,
'total' => count($arguments['each'])
);
$limitCycle = 1;
$output = '';
/**
* @type $singleElement Tx_News_Domain_Model_News
*/
foreach ($arguments['each'] as $keyValue => $singleElement) {
if (is_null($singleElement->getFalMedia())
|| !is_null($limit) && $limitCycle > $limit
) {
continue;
}
$limitCycle++;
$templateVariableContainer->add($arguments['as'], $singleElement);
if ($arguments['key'] !== '') {
$templateVariableContainer->add($arguments['key'], $keyValue);
}
if ($arguments['iteration'] !== NULL) {
$iterationData['isFirst'] = $iterationData['cycle'] === 1;
$iterationData['isLast'] = $iterationData['cycle'] === $iterationData['total'];
$iterationData['isEven'] = $iterationData['cycle'] % 2 === 0;
$iterationData['isOdd'] = !$iterationData['isEven'];
$templateVariableContainer->add($arguments['iteration'], $iterationData);
$iterationData['index']++;
$iterationData['cycle']++;
}
$output .= $renderChildrenClosure();
$templateVariableContainer->remove($arguments['as']);
if ($arguments['key'] !== '') {
$templateVariableContainer->remove($arguments['key']);
}
if ($arguments['iteration'] !== NULL) {
$templateVariableContainer->remove($arguments['iteration']);
}
}
return $output;
}
}
因此您可以在您的视图中将其用作:
<f:forNewsWithMedia each="{news}" as="newsItem" iteration="iterator" limit="4">
<f:render partial="List/TeaserItem" arguments="{newsItem: newsItem,settings:settings,iterator:iterator, contentObjectData:contentObjectData}" />
</f:forNewsWithMedia>