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

RenderViewHelper::addSlotValueToVariables()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 2
dl 0
loc 12
rs 9.4285
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
152
        /**
153
         * @deprecated Must be removed when TYPO3 v7 is not supported anymore.
154
         */
155
        if ($renderingContext->getTemplateVariableContainer()->exists('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

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

240
        /** @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...
241
242
        parent::setChildNodes($childNodes);
243
    }
244
245
    /**
246
     * @return SlotContainer
247
     */
248
    protected static function getSlotContainer()
249
    {
250
        return self::$currentVariableContainer->get(SlotView::class, SlotView::SLOT_CONTAINER);
251
    }
252
253
    /**
254
     * @return array
255
     */
256
    protected static function getSlotValues()
257
    {
258
        return self::$currentVariableContainer->get(SlotView::class, SlotView::SLOT_VALUES);
259
    }
260
261
    /**
262
     * @return array
263
     */
264
    protected static function getMarkers()
265
    {
266
        return self::$currentVariableContainer->get(SlotView::class, SlotView::MARKERS);
267
    }
268
}
269