Skip to content

Instantly share code, notes, and snippets.

@daKmoR
Created October 14, 2011 14:05
Show Gist options
  • Save daKmoR/1287203 to your computer and use it in GitHub Desktop.
Save daKmoR/1287203 to your computer and use it in GitHub Desktop.
GroupedForDateTimeViewHelper for Fluid
<div class="itemsListYearMonth">
<a:groupedForDateTime each="{items}" as="itemsByYear" groupBy="start" format="Y" groupKey="year">
<a:groupedForDateTime each="{itemsByYear}" as="itemsByMonth" groupBy="start" format="m" dateTimeKey="month">
<div class="yearMonth clearfix">
<div class="timeframe" data-behavior="FixTimeframe">
{month -> f:format.date(format: 'F Y')}
</div>
<f:for each="{itemsByMonth}" as="item">
<div class="item">
<p class="startEnd"><a:format.duration start="{item.start}" end="{item.end}" /></p>
<h2>{item.name}</h2>
<div class="text">
<f:format.html>{item.bodyText}</f:format.html>
</div>
</div>
</f:for>
</div>
</a:groupedForDateTime>
</a:groupedForDateTime>
</div>
<div class="itemsListYearMonth">
<div class="yearMonth clearfix">
<div class="timeframe" data-behavior="FixTimeframe">
Oktober 2011
</div>
<div class="item">
<p class="startEnd">24.–25.10.2011</p>
<h2>Laborführung</h2>
<div class="text">
<p>[...]</p>
</div>
</div>
<div class="item">
<p class="startEnd">27.10.–02.11.2011</p>
<h2>Sitzung</h2>
<div class="text">
<p>[...]</p>
</div>
</div>
</div>
<div class="yearMonth clearfix">
<div class="timeframe" data-behavior="FixTimeframe">
Dezember 2011
</div>
<div class="item">
<p class="startEnd">24.12.2011</p>
<h2>Weihnachten</h2>
<div class="text">
<p>[...]</p>
</div>
</div>
</div>
</div>
<?php
/* *
* 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 Tx_Assets_ViewHelpers_GroupedForDateTimeViewHelper extends Tx_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
* @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 Tx_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
* @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 = Tx_Extbase_Reflection_ObjectAccess::getProperty($value, $groupBy);
} else {
throw new Tx_Fluid_Core_ViewHelper_Exception('GroupedForViewHelper only supports multi-dimensional arrays and objects' , 1253120365);
}
$formatedDatetime = $currentGroupIndex->format($format);
$groups['dateTimeKeys'][$formatedDatetime] = $currentGroupIndex;
$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;
}
}
?>
@daKmoR
Copy link
Author

daKmoR commented Apr 20, 2020

I created this 9 years ago 😱
sorry but I won't update this as I barely use TYPO3 anymore 😅

@Megafry
Copy link

Megafry commented Sep 2, 2020

Hi @daKmoR
Thanks for your code, I updated it for TYPO3 10.4 (no guarantee) :-)

{namespace a=Xyz\MyExtname\ViewHelpers}

<?php
namespace Xyz\MyExtname\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!                         *
 *                                                                        */
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
 use TYPO3Fluid\Fluid\Core\Variables\VariableExtractor;
 use TYPO3Fluid\Fluid\Core\ViewHelper;
 use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;

 /**
 * 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 AbstractViewHelper
{
    use CompileWithRenderStatic;

    /**
 * @var boolean
 */
    protected $escapeOutput = false;


    /**
     * @return void
     */
    public function initializeArguments()
    {
        parent::initializeArguments();
        $this->registerArgument('each', 'array', 'The array or \SplObjectStorage to iterated over', true);
        $this->registerArgument('as', 'string', 'The name of the iteration variable', true);
        $this->registerArgument('groupBy', 'string', 'Group by this property', true);
        $this->registerArgument('groupKey', 'string', 'The name of the variable to store the current group', false, 'groupKey');
        $this->registerArgument('format', 'string', 'The format for the datetime', false);
        $this->registerArgument('dateTimeKey', 'string', 'dateTimeKey The name of the variable to store the current datetime', false);
    }

    /**
     * @param array $arguments
     * @param \Closure $renderChildrenClosure
     * @param RenderingContextInterface $renderingContext
     * @return mixed
     */
    public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
    {
        $each = $arguments['each'];
        $as = $arguments['as'];
        $groupBy = $arguments['groupBy'];
        $groupKey = $arguments['groupKey'] ? $arguments['groupKey'] : 'groupKey';
        $format = $arguments['format'] ? $arguments['format'] : '';
        $dateTimeKey = $arguments['dateTimeKey'] ? $arguments['dateTimeKey'] : 'dateTimeKey';
        $output = '';

        if ($each === null) {
            return '';
        }
        if (is_object($each)) {
            if (!$each instanceof \Traversable) {
                throw new ViewHelper\Exception('GroupedForViewHelper only supports arrays and objects implementing \Traversable interface', 1253108907);
            }
            $each = iterator_to_array($each);
        }
        $groups = static::groupElements($each, $groupBy, $format);
        $templateVariableContainer = $renderingContext->getVariableProvider();
        foreach ($groups['values'] as $currentGroupIndex => $group) {
            $templateVariableContainer->add($groupKey, $groups['keys'][$currentGroupIndex]);
            $templateVariableContainer->add($as, $group);
            $output .= $renderChildrenClosure();
            $templateVariableContainer->remove($groupKey);
            $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 \TYPO3Fluid\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 static function groupElements(array $elements, $groupBy, $format)
    {
        $extractor = new VariableExtractor();
        $groups = ['keys' => [], 'values' => []];
        foreach ($elements as $key => $value) {
            if (is_array($value)) {
                $currentGroupIndex = isset($value[$groupBy]) ? $value[$groupBy] : null;
            } elseif (is_object($value)) {
                $currentGroupIndex = $extractor->getByPath($value, $groupBy);
            } else {
                throw new 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 ($currentGroupIndex instanceof \DateTime) {
                //  $currentGroupIndex = $currentGroupIndex->format(\DateTime::RFC850);
                $formatedDatetime = $currentGroupIndex->format($format);
                $groups['dateTimeKeys'][$formatedDatetime] = $currentGroupIndex;
            } elseif (is_object($currentGroupIndex)) {
                $currentGroupIndex = spl_object_hash($currentGroupIndex);
            }

            $groups['keys'][$currentGroupIndex] = $currentGroupKeyValue;
            $groups['values'][$currentGroupIndex][$key] = $value;
        }
        return $groups;
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment