php - 在 TYPO3 Fluid 中显示按年和按月分组的元素列表

标签 php typo3 fluid extbase

我有一个模型,其中一个字段是日期。我想显示该模型中的元素,按年和月分组,如下所示:

== 2013 ==
=== April ===
* Element 1
* Element 2
=== March ===
* Element 3
...
== 2012 ==
...

实现该目标的最佳方法是什么?我应该直接在 Controller 中构建一个嵌套数组吗?或者有没有办法只使用 Fluid 模板显示年和月标题?或者我应该编写自定义 ViewHelper 来提取和显示年和月标题吗?

最佳答案

最后,我通过使用派生自 GroupedBy ViewHelper 的自定义 ViewHelper 解决了这个问题,灵感来自 https://gist.github.com/daKmoR/1287203 , 并适用于 extbase。


这是 ViewHelper 的完整代码,位于 MyExt/Classes/ViewHelpers/GropuedForDateTimeViewHelper.php

<?php
namespace vendor\MyExt\ViewHelpers;

/*                                                                        *
 * This script belongs to the FLOW3 package "Fluid".                      *
 *                                                                        *
 * It is free software; you can redistribute it and/or modify it under    *
 * the terms of the GNU Lesser General Public License as published by the *
 * Free Software Foundation, either version 3 of the License, or (at your *
 * option) any later version.                                             *
 *                                                                        *
 * This script is distributed in the hope that it will be useful, but     *
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-    *
 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser       *
 * General Public License for more details.                               *
 *                                                                        *
 * You should have received a copy of the GNU Lesser General Public       *
 * License along with the script.                                         *
 * If not, see http://www.gnu.org/licenses/lgpl.html                      *
 *                                                                        *
 * The TYPO3 project - inspiring people to share!                         *
 *                                                                        */

/**
 * Grouped loop view helper for Datetime values.
 * Loops through the specified values
 *
 * = Examples =
 *
 * <code title="Simple">
 * // $items = array(
 * //   array('name' => 'apple', 'start' => DateTimeObject[2011-10-13 00:15:00]), 
 * //   array('name' => 'orange', 'start' => DateTimeObject[2011-12-01 00:10:00]),
 * //   array('name' => 'banana', 'start' => DateTimeObject[2008-05-24 00:40:00])
 * // );
 * <a:groupedForDateTime each="{items}" as="itemsByYear" groupBy="start" format="Y" groupKey="year">
 *   {year -> f:format.date(format: 'Y')}
 *   <f:for each="{itemsByYear}" as="item">
 *     {item.name}
 *   </f:for>
 * </a:groupedForDateTime>
 * </code>
 *
 * Output:
 * 2011
 *   apple
 *   orange
 * 2010
 *   banana
 *
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
 * @api
 */
class GroupedForDateTimeViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper {

    /**
     * Iterates through elements of $each and renders child nodes
     *
     * @param array $each The array or Tx_Extbase_Persistence_ObjectStorage to iterated over
     * @param string $as The name of the iteration variable
     * @param string $groupBy Group by this property
     * @param string $groupKey The name of the variable to store the current group
     * @param string $format The format for the datetime
     * @param string $dateTimeKey The name of the variable to store the current datetime
     * @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception
     * @return string Rendered string
     * @author Bastian Waidelich <bastian@typo3.org>
     * @author Thomas Allmer <at@delusionworld.com>
     * @api
     */
    public function render($each, $as, $groupBy, $groupKey = 'groupKey', $format = '', $dateTimeKey = 'dateTimeKey') {
        $output = '';
        if ($each === NULL) {
            return '';
        }

        if (is_object($each)) {
            if (!$each instanceof \Traversable) {
                throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('GroupedForViewHelper only supports arrays and objects implementing Traversable interface' , 1253108907);
            }
            $each = iterator_to_array($each);
        }

        $groups = $this->groupElements($each, $groupBy, $format);

        foreach ($groups['values'] as $currentGroupIndex => $group) {
            $this->templateVariableContainer->add($groupKey, $groups['keys'][$currentGroupIndex]);
            $this->templateVariableContainer->add($dateTimeKey, $groups['dateTimeKeys'][$currentGroupIndex]);
            $this->templateVariableContainer->add($as, $group);
            $output .= $this->renderChildren();
            $this->templateVariableContainer->remove($groupKey);
            $this->templateVariableContainer->remove($dateTimeKey);
            $this->templateVariableContainer->remove($as);
        }
        return $output;
    }

    /**
     * Groups the given array by the specified groupBy property and format for the datetime.
     *
     * @param array $elements The array / traversable object to be grouped
     * @param string $groupBy Group by this property
     * @param string $format The format for the datetime
     * @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception
     * @return array The grouped array in the form array('keys' => array('key1' => [key1value], 'key2' => [key2value], ...), 'values' => array('key1' => array([key1value] => [element1]), ...), ...)
     * @author Bastian Waidelich <bastian@typo3.org>
     */
    protected function groupElements(array $elements, $groupBy, $format) {
        $groups = array('keys' => array(), 'values' => array());
        foreach ($elements as $key => $value) {
            if (is_array($value)) {
                $currentGroupIndex = isset($value[$groupBy]) ? $value[$groupBy] : NULL;
            } elseif (is_object($value)) {
                $currentGroupIndex = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($value, $groupBy);
            } else {
                throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('GroupedForViewHelper only supports multi-dimensional arrays and objects' , 1253120365);
            }
            if (strpos($format, '%') !== FALSE) {
                $formatedDatetime = strftime($format, $currentGroupIndex->format('U'));
            } else {
                $formatedDatetime = $currentGroupIndex->format($format);
            }
            $groups['dateTimeKeys'][$formatedDatetime] = $currentGroupIndex;

            if (strpos($format, '%') !== FALSE) {
                $currentGroupIndex = strftime($format, $currentGroupIndex->format('U'));
            } else {
                $currentGroupIndex = $currentGroupIndex->format($format);
            }

            $currentGroupKeyValue = $currentGroupIndex;
            if (is_object($currentGroupIndex)) {
                $currentGroupIndex = spl_object_hash($currentGroupIndex);
            }
            $groups['keys'][$currentGroupIndex] = $currentGroupKeyValue;
            $groups['values'][$currentGroupIndex][$key] = $value;
        }
        return $groups;
    }
}

?>

下面是一个使用它的模板示例:

{namespace m=vendor\MyExt\ViewHelpers}
<f:layout name="Default" />
<f:section name="main">

    <m:groupedForDateTime each="{myitems}" as="myitemsyear" groupBy="date" format="%Y" groupKey="year" dateTimeKey="yearKey">
        <h2>{year}</h2>
        <m:groupedForDateTime each="{myitemsyear}" as="myitemsmonth" groupBy="date" format="%B" groupKey="month" dateTimeKey="monthKey">
            <h3>{month}</h3>
            <ul>
            <f:for each="{myitemsmonth}" as="myitem">
                <li>{myitem}</li>
            </f:for>
            </ul>
        </m:groupedForDateTime>
    </m:groupedForDateTime>
</f:section>

关于php - 在 TYPO3 Fluid 中显示按年和按月分组的元素列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15870481/

相关文章:

javascript - 流体宽度 slider

java - 如何从 jsonobject 获取值 "10th"到 java?

php - 通过多个不同名称的复选框从mysql获取数据

caching - 如何设置 Typo3 以便启用客户端缓存?

php - 如何在没有 pear 或phar的情况下为TYPO3安装PEAR::Mail?

typo3 - 在for循环中流体访问其他数组

php - HTML-PHP 相对路径到绝对路径

php - 如何从 PHP 中的字符串中获取 64 位整数散列?

php - TYPO3 流资源是否允许无限循环?

css - 如何在 CSS 中创建随大图像扩展但对正常大小的内容保持默认大小的列宽?