【问题标题】:Display list of elements grouped by year and by month in TYPO3 Fluid在 TYPO3 Fluid 中显示按年和月分组的元素列表
【发布时间】:2013-03-30 00:37:41
【问题描述】:

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

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

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

【问题讨论】:

    标签: php typo3 fluid extbase


    【解决方案1】:

    最后,我通过使用自定义 ViewHelper 解决了这个问题,该 ViewHelper 源自 GroupedBy 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>
    

    【讨论】:

    • 这很好,我一直在使用基于这个答案的实现,但现在更新到 TYPO3 9.5 后它不再工作了,仅供参考
    【解决方案2】:

    首先,您需要在控制器中迭代您的结果集,将其保存到数组中,并确保每一行都提取日期以分隔yearmonth 的索引。

    在这种情况下,您将能够使用&lt;f:groupedFor ...&gt; 查看助手。

    其他选项是将这些字段(yearmonth)添加到您的模型中,并在保存/更新对象时设置适当的值。使用这种方法,您将避免上面提到的控制器迭代的需要,buuuutttt...如果您要使用普通 TYPO3 的后端访问这些记录,您将需要使用一些后处理钩子在数据库操作后设置这些字段。

    【讨论】:

    • 感谢您的回答。它给了我一个很好的起点。最后,我发现使用基于 GrouperFor ViewHelper 的自定义 ViewHelper 更简单。
    【解决方案3】:

    这里没有正确添加的简单解决方案是:

    对于年份和月份分组,将字段作为瞬态添加到您的模型中:

    ...
    /**
     * @var int
     * @transient
     */
    protected $year;
    
    
    /**
     * @var int
     * @transient
     */
    protected $month;
    /**
     * @return int
     */
    public function getYear()
    {
        if (!$this->year) {
            $this->year = $this->getDateTimeField()->format('Y');
        }
        return $this->year;
    }
    
    /**
     * @return int
     */
    public function getMonth()
    {
        if (!$this->month) {
           $this->month = $this->getDateTimeField('n');
        }
        return $this->month;
    }
    

    然后在模板中:

    <f:groupedFor each="{list}" as="groupedByYear" groupBy="year" groupKey="groupYear">
        <f:groupedFor each="{groupedByYear}" as="groupedByMonth" groupBy="month" groupKey="groupMonth" />
            ...
        </f:groupedFor>
    </f:groupedFor>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-22
      • 2021-09-21
      • 1970-01-01
      相关资源
      最近更新 更多