Display list of elements grouped by year and by month in TYPO3 Fluid

前端 未结 3 1794
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-12 04:49

I have a model where one field is a date. I want to display elements from that model, grouped by year and by month, like this:

== 2013 ==
=== April ===
* Ele         


        
相关标签:
3条回答
  • 2020-12-12 05:14

    A simple solution which have not been added here properly is this:

    For year and month grouping, add the fields as Transient to your model:

    ...
    /**
     * @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;
    }
    

    Then in the template:

    <f:groupedFor each="{list}" as="groupedByYear" groupBy="year" groupKey="groupYear">
        <f:groupedFor each="{groupedByYear}" as="groupedByMonth" groupBy="month" groupKey="groupMonth" />
            ...
        </f:groupedFor>
    </f:groupedFor>
    
    0 讨论(0)
  • 2020-12-12 05:18

    First you need to iterate your resultset in the controller, save it into array, and make sure that every row has extracted date to separate indexes for year and month.

    In such case you'll be able to use <f:groupedFor ...> view helper.

    Other option is adding these fields (year and month) to your model and setting proper values while saving/updating the object. Using this approach you'll avoid the need of the controller's iteration mentioned above, buuuutttt... if you are going to access these records with common TYPO3's backend, you will need to use some postprocess hooks to set these fields after database operations.

    0 讨论(0)
  • 2020-12-12 05:21

    Finally, I solved this problem by using a custom ViewHelper, derived from GroupedBy ViewHelper, inspired from https://gist.github.com/daKmoR/1287203, and adapted for extbase.


    Here is the complete code for the ViewHelper, located in 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;
        }
    }
    
    ?>
    

    And here is an example of a template using it:

    {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>
    
    0 讨论(0)
提交回复
热议问题