Completed
Pull Request — master (#193)
by Christian
02:28
created

CycleViewHelper   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 92
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 0
loc 92
rs 10
c 0
b 0
f 0
wmc 12
lcom 1
cbo 1

5 Methods

Rating   Name   Duplication   Size   Complexity  
A initializeArguments() 0 6 1
A render() 0 4 1
B renderStatic() 0 24 4
A initializeValues() 0 12 4
A initializeIndex() 0 9 2
1
<?php
2
namespace TYPO3Fluid\Fluid\ViewHelpers;
3
4
/*
5
 * This file belongs to the package "TYPO3 Fluid".
6
 * See LICENSE.txt that was shipped with this package.
7
 */
8
9
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
10
use TYPO3Fluid\Fluid\Core\ViewHelper;
11
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
12
13
/**
14
 * This ViewHelper cycles through the specified values.
15
 * This can be often used to specify CSS classes for example.
16
 * **Note:** To achieve the "zebra class" effect in a loop you can also use the "iteration" argument of the **for** ViewHelper.
17
 *
18
 * = Examples =
19
 *
20
 * <code title="Simple">
21
 * <f:for each="{0:1, 1:2, 2:3, 3:4}" as="foo"><f:cycle values="{0: 'foo', 1: 'bar', 2: 'baz'}" as="cycle">{cycle}</f:cycle></f:for>
22
 * </code>
23
 * <output>
24
 * foobarbazfoo
25
 * </output>
26
 *
27
 * <code title="Alternating CSS class">
28
 * <ul>
29
 *   <f:for each="{0:1, 1:2, 2:3, 3:4}" as="foo">
30
 *     <f:cycle values="{0: 'odd', 1: 'even'}" as="zebraClass">
31
 *       <li class="{zebraClass}">{foo}</li>
32
 *     </f:cycle>
33
 *   </f:for>
34
 * </ul>
35
 * </code>
36
 * <output>
37
 * <ul>
38
 *   <li class="odd">1</li>
39
 *   <li class="even">2</li>
40
 *   <li class="odd">3</li>
41
 *   <li class="even">4</li>
42
 * </ul>
43
 * </output>
44
 *
45
 * Note: The above examples could also be achieved using the "iteration" argument of the ForViewHelper
46
 *
47
 * @api
48
 */
49
class CycleViewHelper extends AbstractViewHelper
50
{
51
    /**
52
     * @var boolean
53
     */
54
    protected $escapeOutput = false;
55
56
    /**
57
     * @return void
58
     */
59
    public function initializeArguments()
60
    {
61
        parent::initializeArguments();
62
        $this->registerArgument('values', 'array', 'The array or object implementing \ArrayAccess (for example \SplObjectStorage) to iterated over', false);
63
        $this->registerArgument('as', 'strong', 'The name of the iteration variable', true);
64
    }
65
66
    /**
67
     * Renders cycle view helper
68
     *
69
     * @return string Rendered result
70
     * @api
71
     */
72
    public function render()
73
    {
74
        return static::renderStatic($this->arguments, $this->buildRenderChildrenClosure(), $this->renderingContext);
75
    }
76
77
    /**
78
     * @param array $arguments
79
     * @param \Closure $renderChildrenClosure
80
     * @param RenderingContextInterface $renderingContext
81
     * @return mixed
82
     */
83
    public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
84
    {
85
        $values = $arguments['values'];
86
        $as = $arguments['as'];
87
        if ($values === null) {
88
            return $renderChildrenClosure();
89
        }
90
        $values = static::initializeValues($values);
91
        $index = static::initializeIndex($as, $renderingContext->getViewHelperVariableContainer());
92
93
        $currentValue = isset($values[$index]) ? $values[$index] : null;
94
95
        $renderingContext->getVariableProvider()->add($as, $currentValue);
96
        $output = $renderChildrenClosure();
97
        $renderingContext->getVariableProvider()->remove($as);
98
99
        $index++;
100
        if (!isset($values[$index])) {
101
            $index = 0;
102
        }
103
        $renderingContext->getViewHelperVariableContainer()->addOrUpdate(static::class, $as, $index);
104
105
        return $output;
106
    }
107
108
    /**
109
     * @param mixed $values
110
     * @return array
111
     * @throws ViewHelper\Exception
112
     */
113
    protected static function initializeValues($values)
114
    {
115
        if (is_array($values)) {
116
            return array_values($values);
117
        }
118
119
        if (is_object($values) && $values instanceof \Traversable) {
120
            return iterator_to_array($values, false);
121
        }
122
123
        throw new ViewHelper\Exception('CycleViewHelper only supports arrays and objects implementing \Traversable interface', 1248728393);
124
    }
125
126
    /**
127
     * @param string $as
128
     * @param ViewHelper\ViewHelperVariableContainer $viewHelperVariableContainer
129
     * @return integer
130
     */
131
    protected static function initializeIndex($as, ViewHelper\ViewHelperVariableContainer $viewHelperVariableContainer)
132
    {
133
        $index = 0;
134
        if ($viewHelperVariableContainer->exists(static::class, $as)) {
135
            $index = $viewHelperVariableContainer->get(static::class, $as);
136
        }
137
138
        return $index;
139
    }
140
}
141