Completed
Pull Request — master (#457)
by Claus
02:31
created

rewriteBooleanNodesInArgumentsObjectTree()   B

Complexity

Conditions 8
Paths 4

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
nc 4
nop 2
dl 0
loc 16
rs 8.4444
c 0
b 0
f 0
1
<?php
2
namespace TYPO3Fluid\Fluid\Core\Parser\SyntaxTree;
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\Parser\Exception;
10
use TYPO3Fluid\Fluid\Core\Parser\ParsingState;
11
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
12
use TYPO3Fluid\Fluid\Core\ViewHelper\ArgumentDefinition;
13
use TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperInterface;
14
15
/**
16
 * Node which will call a ViewHelper associated with this node.
17
 */
18
class ViewHelperNode extends AbstractNode
19
{
20
21
    /**
22
     * @var string
23
     */
24
    protected $viewHelperClassName;
25
26
    /**
27
     * @var NodeInterface[]
28
     */
29
    protected $arguments = [];
30
31
    /**
32
     * @var ViewHelperInterface
33
     */
34
    protected $uninitializedViewHelper = null;
35
36
    /**
37
     * @var ArgumentDefinition[]
38
     */
39
    protected $argumentDefinitions = [];
40
41
    /**
42
     * @var string
43
     */
44
    protected $pointerTemplateCode = null;
45
46
    /**
47
     * @var string
48
     */
49
    protected $namespace = '';
50
51
    /**
52
     * @var string
53
     */
54
    protected $identifier = '';
55
56
    /**
57
     * @var RenderingContextInterface
58
     */
59
    protected $renderingContext;
60
61
    /**
62
     * Constructor.
63
     *
64
     * @param RenderingContextInterface $renderingContext a RenderingContext, provided by invoker
65
     * @param string $namespace the namespace identifier of the ViewHelper.
66
     * @param string $identifier the name of the ViewHelper to render, inside the namespace provided.
67
     * @param NodeInterface[] $arguments Arguments of view helper - each value is a RootNode.
68
     * @param ParsingState $state
69
     */
70
    public function __construct(RenderingContextInterface $renderingContext, $namespace, $identifier, array $arguments, ParsingState $state)
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
71
    {
72
        $resolver = $renderingContext->getViewHelperResolver();
73
        $this->renderingContext = $renderingContext;
74
        $this->namespace = $namespace;
75
        $this->identifier = $identifier;
76
        $this->arguments = $arguments;
77
        $this->viewHelperClassName = $resolver->resolveViewHelperClassName($namespace, $identifier);
78
        $this->uninitializedViewHelper = $resolver->createViewHelperInstanceFromClassName($this->viewHelperClassName);
79
        $this->uninitializedViewHelper->setViewHelperNode($this);
80
        // Note: RenderingContext required here though replaced later. See https://github.com/TYPO3Fluid/Fluid/pull/93
81
        $this->uninitializedViewHelper->setRenderingContext($renderingContext);
82
        $this->argumentDefinitions = $resolver->getArgumentDefinitionsForViewHelper($this->uninitializedViewHelper);
83
        $this->rewriteBooleanNodesInArgumentsObjectTree($this->argumentDefinitions, $this->arguments);
84
        $this->validateArguments($this->argumentDefinitions, $this->arguments);
85
    }
86
87
    /**
88
     * @return ArgumentDefinition[]
89
     */
90
    public function getArgumentDefinitions()
91
    {
92
        return $this->argumentDefinitions;
93
    }
94
95
    /**
96
     * Returns the attached (but still uninitialized) ViewHelper for this ViewHelperNode.
97
     * We need this method because sometimes Interceptors need to ask some information from the ViewHelper.
98
     *
99
     * @return ViewHelperInterface
100
     */
101
    public function getUninitializedViewHelper()
102
    {
103
        return $this->uninitializedViewHelper;
104
    }
105
106
    /**
107
     * Get class name of view helper
108
     *
109
     * @return string Class Name of associated view helper
110
     */
111
    public function getViewHelperClassName()
112
    {
113
        return $this->viewHelperClassName;
114
    }
115
116
    /**
117
     * INTERNAL - only needed for compiling templates
118
     *
119
     * @return NodeInterface[]
120
     */
121
    public function getArguments()
122
    {
123
        return $this->arguments;
124
    }
125
126
    /**
127
     * INTERNAL - only needed for compiling templates
128
     *
129
     * @return NodeInterface[]
130
     */
131
    public function getParsedArguments()
132
    {
133
        return $this->arguments;
134
    }
135
136
    /**
137
     * INTERNAL - only needed for compiling templates
138
     *
139
     * @param string $argumentName
140
     * @return ArgumentDefinition
141
     */
142
    public function getArgumentDefinition($argumentName)
143
    {
144
        return $this->argumentDefinitions[$argumentName];
145
    }
146
147
    /**
148
     * @param NodeInterface $childNode
149
     * @return self
150
     */
151
    public function addChildNode(NodeInterface $childNode)
152
    {
153
        parent::addChildNode($childNode);
154
        $this->uninitializedViewHelper->setChildNodes($this->childNodes);
155
        return $this;
156
    }
157
158
    /**
159
     * @param string $pointerTemplateCode
160
     * @return void
161
     */
162
    public function setPointerTemplateCode($pointerTemplateCode)
163
    {
164
        $this->pointerTemplateCode = $pointerTemplateCode;
165
    }
166
167
    /**
168
     * Call the view helper associated with this object.
169
     *
170
     * First, it evaluates the arguments of the view helper.
171
     *
172
     * If the view helper implements \TYPO3Fluid\Fluid\Core\ViewHelper\ChildNodeAccessInterface,
173
     * it calls setChildNodes(array childNodes) on the view helper.
174
     *
175
     * Afterwards, checks that the view helper did not leave a variable lying around.
176
     *
177
     * @param RenderingContextInterface $renderingContext
178
     * @return string evaluated node after the view helper has been called.
179
     */
180
    public function evaluate(RenderingContextInterface $renderingContext)
181
    {
182
        return $renderingContext->getViewHelperInvoker()->invoke($this->uninitializedViewHelper, $this->arguments, $renderingContext);
183
    }
184
185
    /**
186
     * Wraps the argument tree, if a node is boolean, into a Boolean syntax tree node
187
     *
188
     * @param ArgumentDefinition[] $argumentDefinitions the argument definitions, key is the argument name, value is the ArgumentDefinition object
189
     * @param NodeInterface[] $argumentsObjectTree the arguments syntax tree, key is the argument name, value is an AbstractNode
190
     * @return void
191
     */
192
    protected function rewriteBooleanNodesInArgumentsObjectTree($argumentDefinitions, &$argumentsObjectTree)
193
    {
194
        /** @var $argumentDefinition ArgumentDefinition */
195
        foreach ($argumentDefinitions as $argumentName => $argumentDefinition) {
196
            if (($argumentDefinition->getType() === 'boolean' || $argumentDefinition->getType() === 'bool')
197
                 && isset($argumentsObjectTree[$argumentName])) {
198
                if (!is_numeric($argumentsObjectTree[$argumentName])
199
                    && !is_bool($argumentsObjectTree[$argumentName])
200
                    && $argumentsObjectTree[$argumentName] !== null) {
201
                    $argumentsObjectTree[$argumentName] = new BooleanNode($argumentsObjectTree[$argumentName]);
202
                } else {
203
                    $argumentsObjectTree[$argumentName] = (bool)$argumentsObjectTree[$argumentName];
204
                }
205
            }
206
        }
207
    }
208
209
    /**
210
     * @param ArgumentDefinition[] $argumentDefinitions
211
     * @param NodeInterface[] $argumentsObjectTree
212
     * @throws Exception
213
     */
214 View Code Duplication
    protected function validateArguments(array $argumentDefinitions, array $argumentsObjectTree)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
215
    {
216
        $additionalArguments = [];
217
        foreach ($argumentsObjectTree as $argumentName => $value) {
218
            if (!array_key_exists($argumentName, $argumentDefinitions)) {
219
                $additionalArguments[$argumentName] = $value;
220
            }
221
        }
222
        $this->abortIfRequiredArgumentsAreMissing($argumentDefinitions, $argumentsObjectTree);
223
        $this->uninitializedViewHelper->validateAdditionalArguments($additionalArguments);
224
    }
225
226
    /**
227
     * Throw an exception if required arguments are missing
228
     *
229
     * @param ArgumentDefinition[] $expectedArguments Array of all expected arguments
230
     * @param NodeInterface[] $actualArguments Actual arguments
231
     * @throws Exception
232
     */
233
    protected function abortIfRequiredArgumentsAreMissing($expectedArguments, $actualArguments)
234
    {
235
        $actualArgumentNames = array_keys($actualArguments);
236
        foreach ($expectedArguments as $expectedArgument) {
237
            if ($expectedArgument->isRequired() && !in_array($expectedArgument->getName(), $actualArgumentNames)) {
238
                throw new Exception('Required argument "' . $expectedArgument->getName() . '" was not supplied.', 1237823699);
239
            }
240
        }
241
    }
242
}
243