[TASK] Merge submodule linkvalidator into core
[Packages/TYPO3.CMS.git] / typo3 / sysext / fluid / Classes / ViewHelpers / GroupedForViewHelper.php
1 <?php
2 namespace TYPO3\CMS\Fluid\ViewHelpers;
3
4 /* *
5 * This script is backported from the TYPO3 Flow package "TYPO3.Fluid". *
6 * *
7 * It is free software; you can redistribute it and/or modify it under *
8 * the terms of the GNU Lesser General Public License, either version 3 *
9 * of the License, or (at your option) any later version. *
10 * *
11 * The TYPO3 project - inspiring people to share! *
12 * */
13
14 /**
15 * Grouped loop view helper.
16 * Loops through the specified values.
17 *
18 * The groupBy argument also supports property paths.
19 *
20 * = Examples =
21 *
22 * <code title="Simple">
23 * <f:groupedFor each="{0: {name: 'apple', color: 'green'}, 1: {name: 'cherry', color: 'red'}, 2: {name: 'banana', color: 'yellow'}, 3: {name: 'strawberry', color: 'red'}}" as="fruitsOfThisColor" groupBy="color">
24 * <f:for each="{fruitsOfThisColor}" as="fruit">
25 * {fruit.name}
26 * </f:for>
27 * </f:groupedFor>
28 * </code>
29 * <output>
30 * apple cherry strawberry banana
31 * </output>
32 *
33 * <code title="Two dimensional list">
34 * <ul>
35 * <f:groupedFor each="{0: {name: 'apple', color: 'green'}, 1: {name: 'cherry', color: 'red'}, 2: {name: 'banana', color: 'yellow'}, 3: {name: 'strawberry', color: 'red'}}" as="fruitsOfThisColor" groupBy="color" groupKey="color">
36 * <li>
37 * {color} fruits:
38 * <ul>
39 * <f:for each="{fruitsOfThisColor}" as="fruit" key="label">
40 * <li>{label}: {fruit.name}</li>
41 * </f:for>
42 * </ul>
43 * </li>
44 * </f:groupedFor>
45 * </ul>
46 * </code>
47 * <output>
48 * <ul>
49 * <li>green fruits
50 * <ul>
51 * <li>0: apple</li>
52 * </ul>
53 * </li>
54 * <li>red fruits
55 * <ul>
56 * <li>1: cherry</li>
57 * </ul>
58 * <ul>
59 * <li>3: strawberry</li>
60 * </ul>
61 * </li>
62 * <li>yellow fruits
63 * <ul>
64 * <li>2: banana</li>
65 * </ul>
66 * </li>
67 * </ul>
68 * </output>
69 *
70 * @api
71 */
72 class GroupedForViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper {
73
74 /**
75 * Iterates through elements of $each and renders child nodes
76 *
77 * @param array $each The array or \TYPO3\CMS\Extbase\Persistence\ObjectStorage to iterated over
78 * @param string $as The name of the iteration variable
79 * @param string $groupBy Group by this property
80 * @param string $groupKey The name of the variable to store the current group
81 * @return string Rendered string
82 * @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception
83 * @api
84 */
85 public function render($each, $as, $groupBy, $groupKey = 'groupKey') {
86 $output = '';
87 if ($each === NULL) {
88 return '';
89 }
90 if (is_object($each)) {
91 if (!$each instanceof \Traversable) {
92 throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('GroupedForViewHelper only supports arrays and objects implementing \Traversable interface', 1253108907);
93 }
94 $each = iterator_to_array($each);
95 }
96
97 $groups = $this->groupElements($each, $groupBy);
98
99 foreach ($groups['values'] as $currentGroupIndex => $group) {
100 $this->templateVariableContainer->add($groupKey, $groups['keys'][$currentGroupIndex]);
101 $this->templateVariableContainer->add($as, $group);
102 $output .= $this->renderChildren();
103 $this->templateVariableContainer->remove($groupKey);
104 $this->templateVariableContainer->remove($as);
105 }
106 return $output;
107 }
108
109 /**
110 * Groups the given array by the specified groupBy property.
111 *
112 * @param array $elements The array / traversable object to be grouped
113 * @param string $groupBy Group by this property
114 * @return array The grouped array in the form array('keys' => array('key1' => [key1value], 'key2' => [key2value], ...), 'values' => array('key1' => array([key1value] => [element1]), ...), ...)
115 * @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception
116 */
117 protected function groupElements(array $elements, $groupBy) {
118 $groups = array('keys' => array(), 'values' => array());
119 foreach ($elements as $key => $value) {
120 if (is_array($value)) {
121 $currentGroupIndex = isset($value[$groupBy]) ? $value[$groupBy] : NULL;
122 } elseif (is_object($value)) {
123 $currentGroupIndex = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($value, $groupBy);
124 } else {
125 throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('GroupedForViewHelper only supports multi-dimensional arrays and objects', 1253120365);
126 }
127 $currentGroupKeyValue = $currentGroupIndex;
128 if (is_object($currentGroupIndex)) {
129 $currentGroupIndex = spl_object_hash($currentGroupIndex);
130 }
131 $groups['keys'][$currentGroupIndex] = $currentGroupKeyValue;
132 $groups['values'][$currentGroupIndex][$key] = $value;
133 }
134 return $groups;
135 }
136 }
137
138 ?>