Completed
Pull Request — master (#470)
by Claus
01:32
created

FluidRenderer::renderPartial()   B

Complexity

Conditions 6
Paths 34

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
nc 34
nop 4
dl 0
loc 33
rs 8.7697
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
namespace TYPO3Fluid\Fluid\Core\Rendering;
4
5
use TYPO3Fluid\Fluid\Component\ComponentInterface;
6
use TYPO3Fluid\Fluid\Component\Error\ChildNotFoundException;
7
use TYPO3Fluid\Fluid\Core\Parser\PassthroughSourceException;
8
use TYPO3Fluid\Fluid\View\Exception;
9
use TYPO3Fluid\Fluid\View\Exception\InvalidTemplateResourceException;
10
11
class FluidRenderer
12
{
13
    /**
14
     * The initial rendering context for this template view.
15
     * Due to the rendering stack, another rendering context might be active
16
     * at certain points while rendering the template.
17
     *
18
     * @var RenderingContextInterface
19
     */
20
    protected $baseRenderingContext;
21
22
    /**
23
     * Stack containing the current rendering type, the current rendering context, and the current parsed template
24
     * Do not manipulate directly, instead use the methods"getCurrent*()", "startRendering(...)" and "stopRendering()"
25
     *
26
     * @var array
27
     */
28
    protected $renderingStack = [];
29
30
    /**
31
     * @var callable|null
32
     * @deprecated Will be removed in Fluid 4.0
33
     */
34
    protected $baseTemplateClosure;
35
36
    /**
37
     * @var callable|null
38
     * @deprecated Will be removed in Fluid 4.0
39
     */
40
    protected $baseIdentifierClosure;
41
42
    public function __construct(RenderingContextInterface $renderingContext)
43
    {
44
        $this->baseRenderingContext = $renderingContext;
45
    }
46
47
    public function getComponentBeingRendered(): ?ComponentInterface
48
    {
49
        return end($this->renderingStack) ?: null;
50
    }
51
52
    /**
53
     * @param callable|null $baseTemplateClosure
54
     * @return FluidRenderer
55
     * @deprecated Will be removed in Fluid 4.0
56
     */
57
    public function setBaseTemplateClosure(?callable $baseTemplateClosure): self
58
    {
59
        $this->baseTemplateClosure = $baseTemplateClosure;
0 ignored issues
show
Deprecated Code introduced by
The property TYPO3Fluid\Fluid\Core\Re...r::$baseTemplateClosure has been deprecated with message: Will be removed in Fluid 4.0

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...
60
        return $this;
61
    }
62
63
    /**
64
     * @param callable|null $baseIdentifierClosure
65
     * @return FluidRenderer
66
     * @deprecated Will be removed in Fluid 4.0
67
     */
68
    public function setBaseIdentifierClosure(?callable $baseIdentifierClosure): self
69
    {
70
        $this->baseIdentifierClosure = $baseIdentifierClosure;
0 ignored issues
show
Deprecated Code introduced by
The property TYPO3Fluid\Fluid\Core\Re...:$baseIdentifierClosure has been deprecated with message: Will be removed in Fluid 4.0

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...
71
        return $this;
72
    }
73
74
    public function getRenderingContext(): RenderingContextInterface
75
    {
76
        return $this->baseRenderingContext;
77
    }
78
79
    public function setRenderingContext(RenderingContextInterface $renderingContext): void
80
    {
81
        $this->baseRenderingContext = $renderingContext;
82
    }
83
84
    public function renderSource(string $source)
85
    {
86
        $renderingContext = $this->baseRenderingContext;
87
        $renderingContext->getTemplatePaths()->setTemplateSource($source);
0 ignored issues
show
Deprecated Code introduced by
The method TYPO3Fluid\Fluid\Core\Re...ace::getTemplatePaths() has been deprecated with message: Will be removed in Fluid 4.0

This method 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 method will be removed from the class and what other method or class to use instead.

Loading history...
88
        $templateParser = $renderingContext->getTemplateParser();
89
        try {
90
            $parsedTemplate = $templateParser->getOrParseAndStoreTemplate(
91
                sha1($source),
92
                function() use ($source): string { return $source; }
93
            );
94
            $parsedTemplate->getArguments()
95
                ->assignAll($renderingContext->getVariableProvider()->getAll())
96
                ->setRenderingContext($renderingContext)
97
                ->validate();
98
        } catch (PassthroughSourceException $error) {
99
            return $error->getSource();
100
        }
101
102
        $this->renderingStack[] = $parsedTemplate;
103
        $output = $parsedTemplate->evaluate($this->baseRenderingContext);
104
        array_pop($this->renderingStack);
105
        return $output;
106
    }
107
108
    public function renderComponent(ComponentInterface $component)
109
    {
110
        $this->renderingStack[] = $component;
111
        $output = $component->evaluate($this->baseRenderingContext);
112
        array_pop($this->renderingStack);
113
        return $output;
114
    }
115
116
    /**
117
     * Loads the template source and render the template.
118
     * If "layoutName" is set in a PostParseFacet callback, it will render the file with the given layout.
119
     *
120
     * @param string $filePathAndName
121
     * @return mixed Rendered Template
122
     */
123
    public function renderFile(string $filePathAndName)
124
    {
125
        return $this->renderSource(file_get_contents($filePathAndName));
126
    }
127
128
    /**
129
     * Renders a given section.
130
     *
131
     * Deprecated in favor of the Atoms concept which can be accessed through the ViewHelperResolver.
132
     *
133
     * A section can be rendered by resolving the appropriate (template, layout or partial-like)
134
     * Atom and using either getTypedChildren() or getNamedChild() to extract the desired section
135
     * and render it via the Component interface the return value implements.
136
     *
137
     * @param string $sectionName Name of section to render
138
     * @param array $variables The variables to use
139
     * @param boolean $ignoreUnknown Ignore an unknown section and just return an empty string
140
     * @return mixed rendered template for the section
141
     * @throws ChildNotFoundException
142
     * @throws InvalidTemplateResourceException
143
     * @throws Exception
144
     */
145
    public function renderSection(string $sectionName, array $variables = [], bool $ignoreUnknown = false)
146
    {
147
        $renderingContext = $this->baseRenderingContext;
148
149
        if (empty($variables)) {
150
            // Rendering a section without variables always assigns all variables. If the section doesn't need variables
151
            // it will behave no differently - and when calling the section from a layout-like Atom, presence of all
152
            // variables is assumed without passing any to the f:render statement.
153
            $variables = $renderingContext->getVariableProvider()->getAll();
154
        }
155
156
        try {
157
            $parsedTemplate = $this->getCurrentParsedTemplate();
158
            $section = $parsedTemplate->getNamedChild($sectionName);
159
            $section->getArguments()->assignAll($variables)->setRenderingContext($renderingContext)->validate();
160
        } catch (ChildNotFoundException $error) {
161
            if (!$ignoreUnknown) {
162
                return $renderingContext->getErrorHandler()->handleViewError($error);
0 ignored issues
show
Deprecated Code introduced by
The method TYPO3Fluid\Fluid\Core\Er...face::handleViewError() has been deprecated with message: Will be removed in Fluid 4.0

This method 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 method will be removed from the class and what other method or class to use instead.

Loading history...
163
            }
164
            return '';
165
        } catch (InvalidTemplateResourceException $error) {
166
            if (!$ignoreUnknown) {
167
                return $renderingContext->getErrorHandler()->handleViewError($error);
0 ignored issues
show
Deprecated Code introduced by
The method TYPO3Fluid\Fluid\Core\Er...face::handleViewError() has been deprecated with message: Will be removed in Fluid 4.0

This method 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 method will be removed from the class and what other method or class to use instead.

Loading history...
168
            }
169
            return '';
170
        } catch (Exception $error) {
171
            return $renderingContext->getErrorHandler()->handleViewError($error);
0 ignored issues
show
Deprecated Code introduced by
The method TYPO3Fluid\Fluid\Core\Er...face::handleViewError() has been deprecated with message: Will be removed in Fluid 4.0

This method 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 method will be removed from the class and what other method or class to use instead.

Loading history...
172
        }
173
174
        $output = $section->evaluate($renderingContext);
175
176
        return $output;
177
    }
178
179
    /**
180
     * Renders a partial.
181
     *
182
     * Deprecated in favor of Atoms concept which can be accessed through the
183
     * ViewHelperResolver to fetch and render a (partial-like) Atom directly.
184
     *
185
     * @param string $partialName
186
     * @param string|null $sectionName
187
     * @param array $variables
188
     * @param boolean $ignoreUnknown Ignore an unknown section and just return an empty string
189
     * @return mixed
190
     * @throws ChildNotFoundException
191
     * @throws InvalidTemplateResourceException
192
     * @throws Exception
193
     * @deprecated Will be removed in Fluid 4.0
194
     */
195
    public function renderPartial(string $partialName, ?string $sectionName, array $variables = [], bool $ignoreUnknown = false)
196
    {
197
        $templatePaths = $this->baseRenderingContext->getTemplatePaths();
0 ignored issues
show
Deprecated Code introduced by
The method TYPO3Fluid\Fluid\Core\Re...ace::getTemplatePaths() has been deprecated with message: Will be removed in Fluid 4.0

This method 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 method will be removed from the class and what other method or class to use instead.

Loading history...
198
        $renderingContext = $this->baseRenderingContext;
199
        try {
200
            $parsedPartial = $renderingContext->getTemplateParser()->getOrParseAndStoreTemplate(
201
                $templatePaths->getPartialIdentifier($partialName),
202
                function (RenderingContextInterface $renderingContext) use ($partialName): string {
203
                    return $renderingContext->getTemplatePaths()->getPartialSource($partialName);
0 ignored issues
show
Deprecated Code introduced by
The method TYPO3Fluid\Fluid\Core\Re...ace::getTemplatePaths() has been deprecated with message: Will be removed in Fluid 4.0

This method 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 method will be removed from the class and what other method or class to use instead.

Loading history...
204
                }
205
            );
206
            $parsedPartial->getArguments()->setRenderingContext($renderingContext);
207
            $this->renderingStack[] = $parsedPartial;
208
            if ($sectionName !== null) {
209
                $output = $this->renderSection($sectionName, $variables, $ignoreUnknown);
210
            } else {
211
                $parsedPartial->getArguments()->assignAll($variables)->validate();
212
                $output = $parsedPartial->evaluate($renderingContext);
213
            }
214
            array_pop($this->renderingStack);
215
        } catch (PassthroughSourceException $error) {
216
            return $error->getSource();
217
        } catch (InvalidTemplateResourceException $error) {
218
            if (!$ignoreUnknown) {
219
                return $renderingContext->getErrorHandler()->handleViewError($error);
0 ignored issues
show
Deprecated Code introduced by
The method TYPO3Fluid\Fluid\Core\Er...face::handleViewError() has been deprecated with message: Will be removed in Fluid 4.0

This method 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 method will be removed from the class and what other method or class to use instead.

Loading history...
220
            }
221
            return '';
222
        } catch (Exception $error) {
223
            return $renderingContext->getErrorHandler()->handleViewError($error);
0 ignored issues
show
Deprecated Code introduced by
The method TYPO3Fluid\Fluid\Core\Er...face::handleViewError() has been deprecated with message: Will be removed in Fluid 4.0

This method 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 method will be removed from the class and what other method or class to use instead.

Loading history...
224
        }
225
226
        return $output;
227
    }
228
229
    protected function getCurrentParsedTemplate(): ComponentInterface
230
    {
231
        $renderingContext = $this->baseRenderingContext;
232
        $parsedTemplate = end($this->renderingStack);
233
        if ($parsedTemplate) {
234
            return $parsedTemplate;
235
        }
236
        $templatePaths = $renderingContext->getTemplatePaths();
0 ignored issues
show
Deprecated Code introduced by
The method TYPO3Fluid\Fluid\Core\Re...ace::getTemplatePaths() has been deprecated with message: Will be removed in Fluid 4.0

This method 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 method will be removed from the class and what other method or class to use instead.

Loading history...
237
        $templateParser = $renderingContext->getTemplateParser();
238
239
        // Retrieve the current parsed template, which happens if the renderSection() method was called as first entry
240
        // method (as opposed to rendering through renderFile / renderSource which causes stack entries which in turn
241
        // causes this method to return early).
242
        // Support for the closures will be removed in Fluid 4.0 since they are a temporary measure.
243
        $parsedTemplate = $templateParser->getOrParseAndStoreTemplate(
244
            $this->baseIdentifierClosure ? call_user_func($this->baseIdentifierClosure) : $templatePaths->getTemplateIdentifier('Default', 'Default'),
0 ignored issues
show
Deprecated Code introduced by
The property TYPO3Fluid\Fluid\Core\Re...:$baseIdentifierClosure has been deprecated with message: Will be removed in Fluid 4.0

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...
245
            $this->baseTemplateClosure ?? function(RenderingContextInterface $renderingContext): string {
0 ignored issues
show
Documentation introduced by
$this->baseTemplateClosu...Default', 'Default'); } is of type callable, but the function expects a object<Closure>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Deprecated Code introduced by
The property TYPO3Fluid\Fluid\Core\Re...r::$baseTemplateClosure has been deprecated with message: Will be removed in Fluid 4.0

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...
246
                return $renderingContext->getTemplatePaths()->getTemplateSource('Default', 'Default');
0 ignored issues
show
Deprecated Code introduced by
The method TYPO3Fluid\Fluid\Core\Re...ace::getTemplatePaths() has been deprecated with message: Will be removed in Fluid 4.0

This method 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 method will be removed from the class and what other method or class to use instead.

Loading history...
247
            }
248
        );
249
        return $parsedTemplate;
250
    }
251
}