Completed
Pull Request — master (#457)
by Claus
02:40
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
     * Returns the attached (but still uninitialized) ViewHelper for this ViewHelperNode.
89
     * We need this method because sometimes Interceptors need to ask some information from the ViewHelper.
90
     *
91
     * @return ViewHelperInterface
92
     */
93
    public function getUninitializedViewHelper()
94
    {
95
        return $this->uninitializedViewHelper;
96
    }
97
98
    /**
99
     * Get class name of view helper
100
     *
101
     * @return string Class Name of associated view helper
102
     */
103
    public function getViewHelperClassName()
104
    {
105
        return $this->viewHelperClassName;
106
    }
107
108
    /**
109
     * INTERNAL - only needed for compiling templates
110
     *
111
     * @return NodeInterface[]
112
     */
113
    public function getArguments()
114
    {
115
        return $this->arguments;
116
    }
117
118
    /**
119
     * INTERNAL - only needed for compiling templates
120
     *
121
     * @return NodeInterface[]
122
     */
123
    public function getParsedArguments()
124
    {
125
        return $this->arguments;
126
    }
127
128
    /**
129
     * @param NodeInterface $childNode
130
     * @return self
131
     */
132
    public function addChildNode(NodeInterface $childNode)
133
    {
134
        parent::addChildNode($childNode);
135
        $this->uninitializedViewHelper->setChildNodes($this->childNodes);
136
        return $this;
137
    }
138
139
    /**
140
     * @param string $pointerTemplateCode
141
     * @return void
142
     */
143
    public function setPointerTemplateCode($pointerTemplateCode)
144
    {
145
        $this->pointerTemplateCode = $pointerTemplateCode;
146
    }
147
148
    /**
149
     * Call the view helper associated with this object.
150
     *
151
     * First, it evaluates the arguments of the view helper.
152
     *
153
     * If the view helper implements \TYPO3Fluid\Fluid\Core\ViewHelper\ChildNodeAccessInterface,
154
     * it calls setChildNodes(array childNodes) on the view helper.
155
     *
156
     * Afterwards, checks that the view helper did not leave a variable lying around.
157
     *
158
     * @param RenderingContextInterface $renderingContext
159
     * @return string evaluated node after the view helper has been called.
160
     */
161
    public function evaluate(RenderingContextInterface $renderingContext)
162
    {
163
        return $renderingContext->getViewHelperInvoker()->invoke($this->uninitializedViewHelper, $this->arguments, $renderingContext);
164
    }
165
166
    /**
167
     * Wraps the argument tree, if a node is boolean, into a Boolean syntax tree node
168
     *
169
     * @param ArgumentDefinition[] $argumentDefinitions the argument definitions, key is the argument name, value is the ArgumentDefinition object
170
     * @param NodeInterface[] $argumentsObjectTree the arguments syntax tree, key is the argument name, value is an AbstractNode
171
     * @return void
172
     */
173
    protected function rewriteBooleanNodesInArgumentsObjectTree($argumentDefinitions, &$argumentsObjectTree)
174
    {
175
        /** @var $argumentDefinition ArgumentDefinition */
176
        foreach ($argumentDefinitions as $argumentName => $argumentDefinition) {
177
            if (($argumentDefinition->getType() === 'boolean' || $argumentDefinition->getType() === 'bool')
178
                 && isset($argumentsObjectTree[$argumentName])) {
179
                if (!is_numeric($argumentsObjectTree[$argumentName])
180
                    && !is_bool($argumentsObjectTree[$argumentName])
181
                    && $argumentsObjectTree[$argumentName] !== null) {
182
                    $argumentsObjectTree[$argumentName] = new BooleanNode($argumentsObjectTree[$argumentName]);
183
                } else {
184
                    $argumentsObjectTree[$argumentName] = (bool)$argumentsObjectTree[$argumentName];
185
                }
186
            }
187
        }
188
    }
189
190
    /**
191
     * @param ArgumentDefinition[] $argumentDefinitions
192
     * @param NodeInterface[] $argumentsObjectTree
193
     * @throws Exception
194
     */
195 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...
196
    {
197
        $additionalArguments = [];
198
        foreach ($argumentsObjectTree as $argumentName => $value) {
199
            if (!array_key_exists($argumentName, $argumentDefinitions)) {
200
                $additionalArguments[$argumentName] = $value;
201
            }
202
        }
203
        $this->abortIfRequiredArgumentsAreMissing($argumentDefinitions, $argumentsObjectTree);
204
        $this->uninitializedViewHelper->validateAdditionalArguments($additionalArguments);
205
    }
206
207
    /**
208
     * Throw an exception if required arguments are missing
209
     *
210
     * @param ArgumentDefinition[] $expectedArguments Array of all expected arguments
211
     * @param NodeInterface[] $actualArguments Actual arguments
212
     * @throws Exception
213
     */
214
    protected function abortIfRequiredArgumentsAreMissing($expectedArguments, $actualArguments)
215
    {
216
        $actualArgumentNames = array_keys($actualArguments);
217
        foreach ($expectedArguments as $expectedArgument) {
218
            if ($expectedArgument->isRequired() && !in_array($expectedArgument->getName(), $actualArgumentNames)) {
219
                throw new Exception('Required argument "' . $expectedArgument->getName() . '" was not supplied.', 1237823699);
220
            }
221
        }
222
    }
223
}
224