Completed
Pull Request — master (#305)
by Oliver
02:07
created

ViewHelperNode::validateArguments()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 2
dl 0
loc 11
rs 9.4285
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
     * Constructor.
48
     *
49
     * @param RenderingContextInterface $renderingContext a RenderingContext, provided by invoker
50
     * @param string $namespace the namespace identifier of the ViewHelper.
51
     * @param string $identifier the name of the ViewHelper to render, inside the namespace provided.
52
     * @param NodeInterface[] $arguments Arguments of view helper - each value is a RootNode.
53
     * @param ParsingState $state
54
     */
55
    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...
56
    {
57
        $resolver = $renderingContext->getViewHelperResolver();
58
        $this->arguments = $arguments;
59
        $this->viewHelperClassName = $resolver->resolveViewHelperClassName($namespace, $identifier);
60
        $this->uninitializedViewHelper = $resolver->createViewHelperInstanceFromClassName($this->viewHelperClassName);
61
        $this->uninitializedViewHelper->setViewHelperNode($this);
62
        // Note: RenderingContext required here though replaced later. See https://github.com/TYPO3Fluid/Fluid/pull/93
63
        $this->uninitializedViewHelper->setRenderingContext($renderingContext);
64
        $this->argumentDefinitions = $resolver->getArgumentDefinitionsForViewHelper($this->uninitializedViewHelper);
65
        $this->rewriteBooleanNodesInArgumentsObjectTree($this->argumentDefinitions, $this->arguments);
66
        $this->validateArguments($this->argumentDefinitions, $this->arguments);
67
    }
68
69
    /**
70
     * @return ArgumentDefinition[]
71
     */
72
    public function getArgumentDefinitions()
73
    {
74
        return $this->argumentDefinitions;
75
    }
76
77
    /**
78
     * Returns the attached (but still uninitialized) ViewHelper for this ViewHelperNode.
79
     * We need this method because sometimes Interceptors need to ask some information from the ViewHelper.
80
     *
81
     * @return ViewHelperInterface
82
     */
83
    public function getUninitializedViewHelper()
84
    {
85
        return $this->uninitializedViewHelper;
86
    }
87
88
    /**
89
     * Get class name of view helper
90
     *
91
     * @return string Class Name of associated view helper
92
     */
93
    public function getViewHelperClassName()
94
    {
95
        return $this->viewHelperClassName;
96
    }
97
98
    /**
99
     * INTERNAL - only needed for compiling templates
100
     *
101
     * @return NodeInterface[]
102
     */
103
    public function getArguments()
104
    {
105
        return $this->arguments;
106
    }
107
108
    /**
109
     * INTERNAL - only needed for compiling templates
110
     *
111
     * @param string $argumentName
112
     * @return ArgumentDefinition
113
     */
114
    public function getArgumentDefinition($argumentName)
115
    {
116
        return $this->argumentDefinitions[$argumentName];
117
    }
118
119
    /**
120
     * @param NodeInterface $childNode
121
     * @return void
122
     */
123
    public function addChildNode(NodeInterface $childNode)
124
    {
125
        parent::addChildNode($childNode);
126
        $this->uninitializedViewHelper->setChildNodes($this->childNodes);
127
    }
128
129
    /**
130
     * @param string $pointerTemplateCode
131
     * @return void
132
     */
133
    public function setPointerTemplateCode($pointerTemplateCode)
134
    {
135
        $this->pointerTemplateCode = $pointerTemplateCode;
136
    }
137
138
    /**
139
     * Call the view helper associated with this object.
140
     *
141
     * First, it evaluates the arguments of the view helper.
142
     *
143
     * If the view helper implements \TYPO3Fluid\Fluid\Core\ViewHelper\ChildNodeAccessInterface,
144
     * it calls setChildNodes(array childNodes) on the view helper.
145
     *
146
     * Afterwards, checks that the view helper did not leave a variable lying around.
147
     *
148
     * @param RenderingContextInterface $renderingContext
149
     * @return string evaluated node after the view helper has been called.
150
     */
151
    public function evaluate(RenderingContextInterface $renderingContext)
152
    {
153
        return $renderingContext->getViewHelperInvoker()->invoke($this->uninitializedViewHelper, $this->arguments, $renderingContext);
154
    }
155
156
    /**
157
     * Wraps the argument tree, if a node is boolean, into a Boolean syntax tree node
158
     *
159
     * @param ArgumentDefinition[] $argumentDefinitions the argument definitions, key is the argument name, value is the ArgumentDefinition object
160
     * @param NodeInterface[] $argumentsObjectTree the arguments syntax tree, key is the argument name, value is an AbstractNode
161
     * @return void
162
     */
163
    protected function rewriteBooleanNodesInArgumentsObjectTree($argumentDefinitions, &$argumentsObjectTree)
164
    {
165
        /** @var $argumentDefinition ArgumentDefinition */
166
        foreach ($argumentDefinitions as $argumentName => $argumentDefinition) {
167
            if (($argumentDefinition->getType() === 'boolean' || $argumentDefinition->getType() === 'bool')
168
                 && isset($argumentsObjectTree[$argumentName])) {
169
                $argumentsObjectTree[$argumentName] = new BooleanNode($argumentsObjectTree[$argumentName]);
170
            }
171
        }
172
    }
173
174
    /**
175
     * @param ArgumentDefinition[] $argumentDefinitions
176
     * @param NodeInterface[] $argumentsObjectTree
177
     * @throws Exception
178
     */
179
    protected function validateArguments(array $argumentDefinitions, array $argumentsObjectTree)
180
    {
181
        $additionalArguments = [];
182
        foreach ($argumentsObjectTree as $argumentName => $value) {
183
            if (!array_key_exists($argumentName, $argumentDefinitions)) {
184
                $additionalArguments[$argumentName] = $value;
185
            }
186
        }
187
        $this->abortIfRequiredArgumentsAreMissing($argumentDefinitions, $argumentsObjectTree);
188
        $this->uninitializedViewHelper->validateAdditionalArguments($additionalArguments);
189
    }
190
191
    /**
192
     * Throw an exception if required arguments are missing
193
     *
194
     * @param ArgumentDefinition[] $expectedArguments Array of all expected arguments
195
     * @param NodeInterface[] $actualArguments Actual arguments
196
     * @throws Exception
197
     */
198
    protected function abortIfRequiredArgumentsAreMissing($expectedArguments, $actualArguments)
199
    {
200
        $actualArgumentNames = array_keys($actualArguments);
201
        foreach ($expectedArguments as $expectedArgument) {
202
            if ($expectedArgument->isRequired() && !in_array($expectedArgument->getName(), $actualArgumentNames)) {
203
                throw new Exception('Required argument "' . $expectedArgument->getName() . '" was not supplied.', 1237823699);
204
            }
205
        }
206
    }
207
}
208