2013-04-08 73 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