2013-04-08 80 views
0

我有一个模型,其中一个字段是日期。我想要显示从该模型元素,按年份和按月份进行分组,这样的:按TYPO3液体显示按年份和按月份分组的元素列表

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

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

回答

2

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


这里是视图助手的完整代码,位于MyExt /班/ 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 <[email protected]> 
    * @author Thomas Allmer <[email protected]> 
    * @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 <[email protected]> 
    */ 
    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> 
2

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

在这种情况下,您将可以使用<f:groupedFor ...>视图帮助程序。

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

+0

谢谢你的回答。它给了我一个很好的起点。最后,我发现使用基于GrouperFor ViewHelper的自定义ViewHelper更简单。 – 2013-04-11 03:05:21