Passed
Push — master ( e31cd2...e6253a )
by Romain
03:51
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\Fluid\Core\ViewHelper\AbstractConditionViewHelper;
27
use TYPO3\CMS\Fluid\Core\ViewHelper\ViewHelperVariableContainer;
28
use TYPO3Fluid\Fluid\Core\Compiler\TemplateCompiler;
29
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode;
30
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
31
32
/**
33
 * Will process and render the wanted slot, by getting the value filled by the
34
 * user and replacing markers within it.
35
 *
36
 * This view-helper can be used in several ways:
37
 *
38
 * Inline
39
 * ------
40
 *
41
 * The processed slot value will be returned.
42
 *
43
 * ```
44
 * <nz:slot.render name="MySlot"
45
 *                 markers="{foo: 'bar'}" />
46
 * ```
47
 *
48
 * Conditional
49
 * -----------
50
 *
51
 * Can be used to check whether the slot exists, and do something if it doesn't.
52
 *
53
 * When using this way, a variable `slotValue` becomes accessible within the
54
 * view-helper, that contains the processed value of the slot. However, this
55
 * variable is filled only when the slot exists and can be processed.
56
 *
57
 * ```
58
 * <nz:slot.render name="SomeOptionalSlot">
59
 *     <f:then>
60
 *         {slotValue -> f:format.html()}
61
 *     </f:then>
62
 *     <f:else>
63
 *         Some default value
64
 *     </f:else>
65
 * </nz:slot.render>
66
 * ```
67
 *
68
 * Wrapping
69
 * --------
70
 *
71
 * You may need to add HTML around the slot value only when the slot exists.
72
 *
73
 * ```
74
 * <nz:slot.render name="SomeOptionalSlot">
75
 *     <hr />
76
 *
77
 *     <div class="some-class">
78
 *         {slotValue}
79
 *     </div>
80
 * </nz:slot.render>
81
 * ```
82
 */
83
class RenderViewHelper extends AbstractConditionViewHelper
84
{
85
    /**
86
     * Unfortunately, the rendering context is not passed to the method
87
     * `evaluateCondition`. We need to first save the variable container in the
88
     * class before the method is called.
89
     *
90
     * @var ViewHelperVariableContainer
91
     */
92
    protected static $currentVariableContainer;
93
94
    /**
95
     * @inheritdoc
96
     */
97
    public function initializeArguments()
98
    {
99
        parent::initializeArguments();
100
101
        $this->registerArgument('name', 'string', 'Name of the slot that will be rendered.', true);
102
        $this->registerArgument('markers', 'array', 'Additional markers that will be added to the slot and can be used within the FlexForm.', false, []);
103
    }
104
105
    /**
106
     * @inheritdoc
107
     */
108
    public function render()
109
    {
110
        return self::getSlotValue($this->arguments, $this->renderingContext);
111
    }
112
113
    /**
114
     * @inheritdoc
115
     */
116
    public static function renderStatic(array $arguments, Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
117
    {
118
        self::addSlotValueToVariables($arguments, $renderingContext);
119
120
        return parent::renderStatic($arguments, $renderChildrenClosure, $renderingContext);
121
    }
122
123
    /**
124
     * Adds a new variable `slotValue` to the view, that contains the processed
125
     * value of the slot.
126
     *
127
     * @param array $arguments
128
     * @param RenderingContextInterface $renderingContext
129
     */
130
    protected static function addSlotValueToVariables(array $arguments, RenderingContextInterface $renderingContext)
131
    {
132
        $slotValue = self::getSlotValue($arguments, $renderingContext);
133
134
        $renderingContext->getVariableProvider()->add('slotValue', $slotValue);
135
    }
136
137
    /**
138
     * @inheritdoc
139
     */
140
    public function compile($argumentsName, $closureName, &$initializationPhpCode, ViewHelperNode $node, TemplateCompiler $compiler)
141
    {
142
        if (empty($node->getChildNodes())) {
143
            return sprintf(
144
                '%s::getSlotValue(%s, $renderingContext)',
145
                get_class($this),
146
                $argumentsName
147
            );
148
        } else {
149
            return parent::compile($argumentsName, $closureName, $initializationPhpCode, $node, $compiler);
150
        }
151
    }
152
153
    /**
154
     * Fetches the final value of the wanted slot, by getting the user value and
155
     * replacing markers in it.
156
     *
157
     * @param array $arguments
158
     * @param RenderingContextInterface $renderingContext
159
     * @return string
160
     *
161
     * @throws DuplicateEntryException
162
     */
163
    public static function getSlotValue(array $arguments, RenderingContextInterface $renderingContext)
164
    {
165
        self::$currentVariableContainer = $renderingContext->getViewHelperVariableContainer();
166
167
        $result = '';
168
        $name = $arguments['name'];
169
        $newMarkers = $arguments['markers'];
170
171
        $slotValues = self::getSlotValues();
172
        $markers = self::getMarkers();
173
174
        foreach ($newMarkers as $key => $value) {
175
            if (isset($markers[$key])) {
176
                throw DuplicateEntryException::markerAlreadyDefined($key, $name);
177
            }
178
        }
179
180
        if (isset($slotValues[$name])) {
181
            foreach ($newMarkers as $key => $value) {
182
                $marker = new Marker($key);
183
                $marker->setValue($value);
184
185
                $markers[$key] = $marker;
186
            }
187
188
            $markerParser = Container::get(MarkerParser::class);
189
190
            $result = $markerParser->replaceMarkers(
191
                $slotValues[$name],
192
                $markers
193
            );
194
        }
195
196
        return $result;
197
    }
198
199
    /**
200
     * @param array $arguments
201
     * @return bool
202
     */
203
    protected static function evaluateCondition($arguments = null)
204
    {
205
        return self::getSlotContainer()->has($arguments['name']);
206
    }
207
208
    /**
209
     * @return SlotContainer
210
     */
211
    protected static function getSlotContainer()
212
    {
213
        return self::$currentVariableContainer->get(SlotView::class, SlotView::SLOT_CONTAINER);
214
    }
215
216
    /**
217
     * @return array
218
     */
219
    protected static function getSlotValues()
220
    {
221
        return self::$currentVariableContainer->get(SlotView::class, SlotView::SLOT_VALUES);
222
    }
223
224
    /**
225
     * @return array
226
     */
227
    protected static function getMarkers()
228
    {
229
        return self::$currentVariableContainer->get(SlotView::class, SlotView::MARKERS);
230
    }
231
}
232