Passed
Pull Request — master (#44)
by Romain
03:38
created

RenderViewHelper::getSlotValue()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 34
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 19
nc 5
nop 2
dl 0
loc 34
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * Copyright (C) 2018
5
 * Nathan Boiron <[email protected]>
6
 * Romain Canon <[email protected]>
7
 *
8
 * This file is part of the TYPO3 NotiZ project.
9
 * It is free software; you can redistribute it and/or modify it
10
 * under the terms of the GNU General Public License, either
11
 * version 3 of the License, or any later version.
12
 *
13
 * For the full copyright and license information, see:
14
 * http://www.gnu.org/licenses/gpl-3.0.html
15
 */
16
17
namespace CuyZ\Notiz\ViewHelpers\Slot;
18
19
use Closure;
20
use CuyZ\Notiz\Core\Exception\DuplicateEntryException;
21
use CuyZ\Notiz\Core\Property\Service\MarkerParser;
22
use CuyZ\Notiz\Domain\Property\Marker;
23
use CuyZ\Notiz\Service\Container;
24
use CuyZ\Notiz\View\Slot\SlotContainer;
25
use CuyZ\Notiz\View\Slot\SlotView;
26
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
27
use TYPO3\CMS\Fluid\Core\Compiler\TemplateCompiler;
28
use TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\AbstractNode;
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Fluid\Core\Par...SyntaxTree\AbstractNode was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
29
use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
30
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractConditionViewHelper;
31
use TYPO3\CMS\Fluid\Core\ViewHelper\ViewHelperVariableContainer;
32
33
/**
34
 * Will process and render the wanted slot, by getting the value filled by the
35
 * user and replacing markers within it.
36
 *
37
 * This view-helper can be used in several ways:
38
 *
39
 * Inline
40
 * ------
41
 *
42
 * The processed slot value will be returned.
43
 *
44
 * ```
45
 * <nz:slot.render name="MySlot"
46
 *                 markers="{foo: 'bar'}" />
47
 * ```
48
 *
49
 * Conditional
50
 * -----------
51
 *
52
 * Can be used to check whether the slot exists, and do something if it doesn't.
53
 *
54
 * When using this way, a variable `slotValue` becomes accessible within the
55
 * view-helper, that contains the processed value of the slot. However, this
56
 * variable is filled only when the slot exists and can be processed.
57
 *
58
 * ```
59
 * <nz:slot.render name="SomeOptionalSlot">
60
 *     <f:then>
61
 *         {slotValue -> f:format.html()}
62
 *     </f:then>
63
 *     <f:else>
64
 *         Some default value
65
 *     </f:else>
66
 * </nz:slot.render>
67
 * ```
68
 *
69
 * Wrapping
70
 * --------
71
 *
72
 * You may need to add HTML around the slot value only when the slot exists.
73
 *
74
 * ```
75
 * <nz:slot.render name="SomeOptionalSlot">
76
 *     <hr />
77
 *
78
 *     <div class="some-class">
79
 *         {slotValue}
80
 *     </div>
81
 * </nz:slot.render>
82
 * ```
83
 */
84
class RenderViewHelper extends AbstractConditionViewHelper
85
{
86
    /**
87
     * Unfortunately, the rendering context is not passed to the method
88
     * `evaluateCondition`. We need to first save the variable container in the
89
     * class before the method is called.
90
     *
91
     * @var ViewHelperVariableContainer
92
     */
93
    protected static $currentVariableContainer;
94
95
    /**
96
     * @deprecated Must be removed when TYPO3 v7 is not supported anymore.
97
     *
98
     * @var AbstractNode[]
99
     */
100
    private $childNodesLegacy = [];
101
102
    /**
103
     * @inheritdoc
104
     */
105
    public function initializeArguments()
106
    {
107
        parent::initializeArguments();
108
109
        $this->registerArgument('name', 'string', 'Name of the slot that will be rendered.', true);
110
        $this->registerArgument('markers', 'array', 'Additional markers that will be added to the slot and can be used within the FlexForm.', false, []);
111
112
        if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '8.0.0', '>=')) {
113
            unset($this->argumentDefinitions['condition']);
114
        }
115
    }
116
117
    /**
118
     * @inheritdoc
119
     */
120
    public function render()
121
    {
122
        if (empty($this->childNodesLegacy)) {
0 ignored issues
show
Deprecated Code introduced by
The property CuyZ\Notiz\ViewHelpers\S...lper::$childNodesLegacy has been deprecated: Must be removed when TYPO3 v7 is not supported anymore. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

122
        if (empty(/** @scrutinizer ignore-deprecated */ $this->childNodesLegacy)) {

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
123
            return self::getSlotValue($this->arguments, $this->renderingContext);
124
        } else {
125
            self::addSlotValueToVariables($this->arguments, $this->renderingContext);
126
127
            return parent::render();
128
        }
129
    }
130
131
    /**
132
     * @inheritdoc
133
     */
134
    public static function renderStatic(array $arguments, Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
135
    {
136
        self::addSlotValueToVariables($arguments, $renderingContext);
137
138
        return parent::renderStatic($arguments, $renderChildrenClosure, $renderingContext);
139
    }
140
141
    /**
142
     * Adds a new variable `slotValue` to the view, that contains the processed
143
     * value of the slot.
144
     *
145
     * @param array $arguments
146
     * @param RenderingContextInterface $renderingContext
147
     */
148
    protected static function addSlotValueToVariables(array $arguments, RenderingContextInterface $renderingContext)
149
    {
150
        $slotValue = self::getSlotValue($arguments, $renderingContext);
151
        $renderingContext->getTemplateVariableContainer()->add('slotValue', $slotValue);
0 ignored issues
show
Bug introduced by
The method getTemplateVariableContainer() does not exist on TYPO3\CMS\Fluid\Core\Ren...nderingContextInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

151
        $renderingContext->/** @scrutinizer ignore-call */ 
152
                           getTemplateVariableContainer()->add('slotValue', $slotValue);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
152
    }
153
154
    /**
155
     * @inheritdoc
156
     */
157
    public function compile($argumentsName, $closureName, &$initializationPhpCode, AbstractNode $node, TemplateCompiler $compiler)
158
    {
159
        if (empty($node->getChildNodes())) {
160
            return sprintf(
161
                '%s::getSlotValue(%s, $renderingContext)',
162
                get_class($this),
163
                $argumentsName
164
            );
165
        } else {
166
            return parent::compile($argumentsName, $closureName, $initializationPhpCode, $node, $compiler);
167
        }
168
    }
169
170
    /**
171
     * Fetches the final value of the wanted slot, by getting the user value and
172
     * replacing markers in it.
173
     *
174
     * @param array $arguments
175
     * @param RenderingContextInterface $renderingContext
176
     * @return string
177
     *
178
     * @throws DuplicateEntryException
179
     */
180
    public static function getSlotValue(array $arguments, RenderingContextInterface $renderingContext)
181
    {
182
        self::$currentVariableContainer = $renderingContext->getViewHelperVariableContainer();
183
184
        $result = '';
185
        $name = $arguments['name'];
186
        $newMarkers = $arguments['markers'];
187
188
        $slotValues = self::getSlotValues();
189
        $markers = self::getMarkers();
190
191
        foreach ($newMarkers as $key => $value) {
192
            if (isset($markers[$key])) {
193
                throw DuplicateEntryException::markerAlreadyDefined($key, $name);
194
            }
195
        }
196
197
        if (isset($slotValues[$name])) {
198
            foreach ($newMarkers as $key => $value) {
199
                $marker = new Marker($key);
200
                $marker->setValue($value);
201
202
                $markers[$key] = $marker;
203
            }
204
205
            $markerParser = Container::get(MarkerParser::class);
206
207
            $result = $markerParser->replaceMarkers(
208
                $slotValues[$name],
209
                $markers
210
            );
211
        }
212
213
        return $result;
214
    }
215
216
    /**
217
     * @param array $arguments
218
     * @return bool
219
     */
220
    protected static function evaluateCondition($arguments = null)
221
    {
222
        return self::getSlotContainer()->has($arguments['name']);
223
    }
224
225
    /**
226
     * @deprecated Must be removed when TYPO3 v7 is not supported anymore.
227
     *
228
     * @param array $childNodes
229
     */
230
    public function setChildNodes(array $childNodes)
231
    {
232
        $this->childNodesLegacy = $childNodes;
0 ignored issues
show
Deprecated Code introduced by
The property CuyZ\Notiz\ViewHelpers\S...lper::$childNodesLegacy has been deprecated: Must be removed when TYPO3 v7 is not supported anymore. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

232
        /** @scrutinizer ignore-deprecated */ $this->childNodesLegacy = $childNodes;

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
233
234
        parent::setChildNodes($childNodes);
235
    }
236
237
    /**
238
     * @return SlotContainer
239
     */
240
    protected static function getSlotContainer()
241
    {
242
        return self::$currentVariableContainer->get(SlotView::class, SlotView::SLOT_CONTAINER);
243
    }
244
245
    /**
246
     * @return array
247
     */
248
    protected static function getSlotValues()
249
    {
250
        return self::$currentVariableContainer->get(SlotView::class, SlotView::SLOT_VALUES);
251
    }
252
253
    /**
254
     * @return array
255
     */
256
    protected static function getMarkers()
257
    {
258
        return self::$currentVariableContainer->get(SlotView::class, SlotView::MARKERS);
259
    }
260
}
261