Passed
Branch task/deprecate-typo3-7.6 (a45a35)
by Romain
05:59
created

RenderViewHelper::setChildNodes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
rs 10
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\ViewHelper\AbstractConditionViewHelper;
28
use TYPO3\CMS\Fluid\Core\ViewHelper\ViewHelperVariableContainer;
29
use TYPO3Fluid\Fluid\Core\Compiler\TemplateCompiler;
30
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode;
31
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
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
     * @inheritdoc
97
     */
98
    public function initializeArguments()
99
    {
100
        parent::initializeArguments();
101
102
        $this->registerArgument('name', 'string', 'Name of the slot that will be rendered.', true);
103
        $this->registerArgument('markers', 'array', 'Additional markers that will be added to the slot and can be used within the FlexForm.', false, []);
104
    }
105
106
    /**
107
     * @inheritdoc
108
     */
109
    public function render()
110
    {
111
        return self::getSlotValue($this->arguments, $this->renderingContext);
112
    }
113
114
    /**
115
     * @inheritdoc
116
     */
117
    public static function renderStatic(array $arguments, Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
118
    {
119
        self::addSlotValueToVariables($arguments, $renderingContext);
120
121
        return parent::renderStatic($arguments, $renderChildrenClosure, $renderingContext);
122
    }
123
124
    /**
125
     * Adds a new variable `slotValue` to the view, that contains the processed
126
     * value of the slot.
127
     *
128
     * @param array $arguments
129
     * @param RenderingContextInterface $renderingContext
130
     */
131
    protected static function addSlotValueToVariables(array $arguments, RenderingContextInterface $renderingContext)
132
    {
133
        $slotValue = self::getSlotValue($arguments, $renderingContext);
134
135
        $renderingContext->getVariableProvider()->add('slotValue', $slotValue);
136
    }
137
138
    /**
139
     * @inheritdoc
140
     */
141
    public function compile($argumentsName, $closureName, &$initializationPhpCode, ViewHelperNode $node, TemplateCompiler $compiler)
142
    {
143
        if (empty($node->getChildNodes())) {
144
            return sprintf(
145
                '%s::getSlotValue(%s, $renderingContext)',
146
                get_class($this),
147
                $argumentsName
148
            );
149
        } else {
150
            return parent::compile($argumentsName, $closureName, $initializationPhpCode, $node, $compiler);
151
        }
152
    }
153
154
    /**
155
     * Fetches the final value of the wanted slot, by getting the user value and
156
     * replacing markers in it.
157
     *
158
     * @param array $arguments
159
     * @param RenderingContextInterface $renderingContext
160
     * @return string
161
     *
162
     * @throws DuplicateEntryException
163
     */
164
    public static function getSlotValue(array $arguments, RenderingContextInterface $renderingContext)
165
    {
166
        self::$currentVariableContainer = $renderingContext->getViewHelperVariableContainer();
167
168
        $result = '';
169
        $name = $arguments['name'];
170
        $newMarkers = $arguments['markers'];
171
172
        $slotValues = self::getSlotValues();
173
        $markers = self::getMarkers();
174
175
        foreach ($newMarkers as $key => $value) {
176
            if (isset($markers[$key])) {
177
                throw DuplicateEntryException::markerAlreadyDefined($key, $name);
178
            }
179
        }
180
181
        if (isset($slotValues[$name])) {
182
            foreach ($newMarkers as $key => $value) {
183
                $marker = new Marker($key);
184
                $marker->setValue($value);
185
186
                $markers[$key] = $marker;
187
            }
188
189
            $markerParser = Container::get(MarkerParser::class);
190
191
            $result = $markerParser->replaceMarkers(
192
                $slotValues[$name],
193
                $markers
194
            );
195
        }
196
197
        return $result;
198
    }
199
200
    /**
201
     * @param array $arguments
202
     * @return bool
203
     */
204
    protected static function evaluateCondition($arguments = null)
205
    {
206
        return self::getSlotContainer()->has($arguments['name']);
207
    }
208
209
    /**
210
     * @return SlotContainer
211
     */
212
    protected static function getSlotContainer()
213
    {
214
        return self::$currentVariableContainer->get(SlotView::class, SlotView::SLOT_CONTAINER);
215
    }
216
217
    /**
218
     * @return array
219
     */
220
    protected static function getSlotValues()
221
    {
222
        return self::$currentVariableContainer->get(SlotView::class, SlotView::SLOT_VALUES);
223
    }
224
225
    /**
226
     * @return array
227
     */
228
    protected static function getMarkers()
229
    {
230
        return self::$currentVariableContainer->get(SlotView::class, SlotView::MARKERS);
231
    }
232
}
233