Completed
Pull Request — master (#470)
by Claus
01:35
created

IfViewHelper::evaluateParts()   F

Complexity

Conditions 16
Paths 672

Size

Total Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 16
nc 672
nop 2
dl 0
loc 53
rs 1.8555
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types=1);
3
namespace TYPO3Fluid\Fluid\ViewHelpers;
4
5
/*
6
 * This file belongs to the package "TYPO3 Fluid".
7
 * See LICENSE.txt that was shipped with this package.
8
 */
9
10
use TYPO3Fluid\Fluid\Component\ExpressionComponentInterface;
11
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
12
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractConditionViewHelper;
13
14
/**
15
 * This view helper implements an if/else condition.
16
 *
17
 * **Conditions:**
18
 *
19
 * As a condition is a boolean value, you can just use a boolean argument.
20
 * Alternatively, you can write a boolean expression there.
21
 * Boolean expressions have the following form:
22
 * XX Comparator YY
23
 * Comparator is one of: ==, !=, <, <=, >, >= and %
24
 * The % operator converts the result of the % operation to boolean.
25
 *
26
 * XX and YY can be one of:
27
 * - number
28
 * - Object Accessor
29
 * - Array
30
 * - a ViewHelper
31
 * - string
32
 *
33
 * ::
34
 *
35
 *   <f:if condition="{rank} > 100">
36
 *     Will be shown if rank is > 100
37
 *   </f:if>
38
 *   <f:if condition="{rank} % 2">
39
 *     Will be shown if rank % 2 != 0.
40
 *   </f:if>
41
 *   <f:if condition="{rank} == {k:bar()}">
42
 *     Checks if rank is equal to the result of the ViewHelper "k:bar"
43
 *   </f:if>
44
 *   <f:if condition="{foo.bar} == 'stringToCompare'">
45
 *     Will result in true if {foo.bar}'s represented value equals 'stringToCompare'.
46
 *   </f:if>
47
 *
48
 * = Examples =
49
 *
50
 * <code title="Basic usage">
51
 * <f:if condition="somecondition">
52
 *   This is being shown in case the condition matches
53
 * </f:if>
54
 * </code>
55
 * <output>
56
 * Everything inside the <f:if> tag is being displayed if the condition evaluates to TRUE.
57
 * </output>
58
 *
59
 * <code title="If / then / else">
60
 * <f:if condition="somecondition">
61
 *   <f:then>
62
 *     This is being shown in case the condition matches.
63
 *   </f:then>
64
 *   <f:else>
65
 *     This is being displayed in case the condition evaluates to FALSE.
66
 *   </f:else>
67
 * </f:if>
68
 * </code>
69
 * <output>
70
 * Everything inside the "then" tag is displayed if the condition evaluates to TRUE.
71
 * Otherwise, everything inside the "else"-tag is displayed.
72
 * </output>
73
 *
74
 * <code title="inline notation">
75
 * {f:if(condition: someCondition, then: 'condition is met', else: 'condition is not met')}
76
 * </code>
77
 * <output>
78
 * The value of the "then" attribute is displayed if the condition evaluates to TRUE.
79
 * Otherwise, everything the value of the "else"-attribute is displayed.
80
 * </output>
81
 */
82
class IfViewHelper extends AbstractConditionViewHelper implements ExpressionComponentInterface
83
{
84
    protected $parts = [];
85
86
    public function __construct(iterable $parts = [])
87
    {
88
        $this->parts = $parts;
89
    }
90
91
    public function initializeArguments()
92
    {
93
        parent::initializeArguments();
94
        $this->registerArgument('condition', 'boolean', 'Condition expression conforming to Fluid boolean rules', false, false);
95
    }
96
97
    /**
98
     * Renders <f:then> child if $condition is true, otherwise renders <f:else> child.
99
     * Method which only gets called if the template is not compiled. For static calling,
100
     * the then/else nodes are converted to closures and condition evaluation closures.
101
     *
102
     * @return mixed
103
     */
104
    public function render()
105
    {
106
        if (!empty($this->parts)) {
107
            return $this->evaluateParts($this->renderingContext, $this->parts);
108
        }
109
        return parent::render();
110
    }
111
112
    protected function condition(): bool
113
    {
114
        return (bool) $this->arguments['condition'];
115
    }
116
117
    /**
118
     * Matches possibilities:
119
     *
120
     * - {foo ? bar : baz}
121
     * - {foo ?: baz}
122
     *
123
     * But not:
124
     *
125
     * - {?bar:baz}
126
     * - {foo?bar:baz}
127
     * - {foo ?? bar}
128
     * - {foo ? bar : baz : more}
129
     *
130
     * And so on.
131
     *
132
     * @param array $parts
133
     * @return bool
134
     */
135
    public static function matches(array $parts): bool
136
    {
137
        return isset($parts[2]) && ($parts[1] === '?' && (($parts[2] ?? null) === ':' && !isset($parts[4])) || ($parts[3] ?? null) === ':' && !isset($parts[5]));
138
    }
139
140
    protected function evaluateParts(RenderingContextInterface $renderingContext, iterable $parts)
141
    {
142
        $check = null;
143
        $then = null;
144
        $else = null;
145
        $expression = '';
146
        $variables = $renderingContext->getVariableProvider();
147
        foreach ($parts as $part) {
148
            $expression .= $part . ' ';
149
            if ($part === ':' && $then === null) {
150
                $then = $check;
151
                continue;
152
            }
153
154
            if ($check === null) {
155
                $check = $part;
156
                continue;
157
            }
158
159
            if ($part === '?' || $part === ':') {
160
                continue;
161
            }
162
163
            if ($then === null) {
164
                $then = $part;
165
                continue;
166
            }
167
168
            if ($else === null) {
169
                $else = $part;
170
                break;
171
            }
172
        }
173
174
        $negated = false;
175
        if (!is_numeric($check)) {
176
            if ($check[0] === '!') {
177
                $check = substr($check, 1);
178
                $negated = true;
179
            }
180
            $check = $variables->get($check);
181
        }
182
183
        if (!is_numeric($then)) {
184
            $then = $variables->get($then) ?? $then;
185
        }
186
187
        if (!is_numeric($else)) {
188
            $else = $variables->get($else) ?? $else;
189
        }
190
191
        return $negated ? (!$check ? $then : $else) : ($check ? $then : $else);
192
    }
193
}
194