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

FluidRenderer::setBaseTemplateClosure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 5
rs 10
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
    /**
48
     * @param callable|null $baseTemplateClosure
49
     * @return FluidRenderer
50
     * @deprecated Will be removed in Fluid 4.0
51
     */
52
    public function setBaseTemplateClosure(?callable $baseTemplateClosure): self
53
    {
54
        $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...
55
        return $this;
56
    }
57
58
    /**
59
     * @param callable|null $baseIdentifierClosure
60
     * @return FluidRenderer
61
     * @deprecated Will be removed in Fluid 4.0
62
     */
63
    public function setBaseIdentifierClosure(?callable $baseIdentifierClosure): self
64
    {
65
        $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...
66
        return $this;
67
    }
68
69
    public function getRenderingContext(): RenderingContextInterface
70
    {
71
        return $this->baseRenderingContext;
72
    }
73
74
    public function setRenderingContext(RenderingContextInterface $renderingContext): void
75
    {
76
        $this->baseRenderingContext = $renderingContext;
77
    }
78
79
    public function renderSource(string $source)
80
    {
81
        $renderingContext = $this->baseRenderingContext;
82
        $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...
83
        $templateParser = $renderingContext->getTemplateParser();
84
        try {
85
            $parsedTemplate = $templateParser->getOrParseAndStoreTemplate(
86
                sha1($source),
87
                function() use ($source): string { return $source; }
88
            );
89
            $parsedTemplate->getArguments()
90
                ->assignAll($renderingContext->getVariableProvider()->getAll())
91
                ->setRenderingContext($renderingContext)
92
                ->validate();
93
        } catch (PassthroughSourceException $error) {
94
            return $error->getSource();
95
        }
96
97
        $this->renderingStack[] = $parsedTemplate;
98
        $output = $parsedTemplate->evaluate($this->baseRenderingContext);
99
        array_pop($this->renderingStack);
100
        return $output;
101
    }
102
103
    public function renderComponent(ComponentInterface $component)
104
    {
105
        $this->renderingStack[] = $component;
106
        $output = $component->evaluate($this->baseRenderingContext);
107
        array_pop($this->renderingStack);
108
        return $output;
109
    }
110
111
    /**
112
     * Loads the template source and render the template.
113
     * If "layoutName" is set in a PostParseFacet callback, it will render the file with the given layout.
114
     *
115
     * @param string $filePathAndName
116
     * @return mixed Rendered Template
117
     */
118
    public function renderFile(string $filePathAndName)
119
    {
120
        return $this->renderSource(file_get_contents($filePathAndName));
121
    }
122
123
    /**
124
     * Renders a given section.
125
     *
126
     * Deprecated in favor of the Atoms concept which can be accessed through the ViewHelperResolver.
127
     *
128
     * A section can be rendered by resolving the appropriate (template, layout or partial-like)
129
     * Atom and using either getTypedChildren() or getNamedChild() to extract the desired section
130
     * and render it via the Component interface the return value implements.
131
     *
132
     * @param string $sectionName Name of section to render
133
     * @param array $variables The variables to use
134
     * @param boolean $ignoreUnknown Ignore an unknown section and just return an empty string
135
     * @return mixed rendered template for the section
136
     * @throws ChildNotFoundException
137
     * @throws InvalidTemplateResourceException
138
     * @throws Exception
139
     */
140
    public function renderSection(string $sectionName, array $variables = [], bool $ignoreUnknown = false)
141
    {
142
        $renderingContext = $this->baseRenderingContext;
143
144
        if (empty($variables)) {
145
            // Rendering a section without variables always assigns all variables. If the section doesn't need variables
146
            // it will behave no differently - and when calling the section from a layout-like Atom, presence of all
147
            // variables is assumed without passing any to the f:render statement.
148
            $variables = $renderingContext->getVariableProvider()->getAll();
149
        }
150
151
        try {
152
            $parsedTemplate = $this->getCurrentParsedTemplate();
153
            $section = $parsedTemplate->getNamedChild($sectionName);
154
            $section->getArguments()->assignAll($variables)->setRenderingContext($renderingContext)->validate();
155
        } catch (ChildNotFoundException $error) {
156
            if (!$ignoreUnknown) {
157
                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...
158
            }
159
            return '';
160
        } catch (InvalidTemplateResourceException $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 (Exception $error) {
166
            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...
167
        }
168
169
        $output = $section->evaluate($renderingContext);
170
171
        return $output;
172
    }
173
174
    /**
175
     * Renders a partial.
176
     *
177
     * Deprecated in favor of Atoms concept which can be accessed through the
178
     * ViewHelperResolver to fetch and render a (partial-like) Atom directly.
179
     *
180
     * @param string $partialName
181
     * @param string|null $sectionName
182
     * @param array $variables
183
     * @param boolean $ignoreUnknown Ignore an unknown section and just return an empty string
184
     * @return mixed
185
     * @throws ChildNotFoundException
186
     * @throws InvalidTemplateResourceException
187
     * @throws Exception
188
     * @deprecated Will be removed in Fluid 4.0
189
     */
190
    public function renderPartial(string $partialName, ?string $sectionName, array $variables = [], bool $ignoreUnknown = false)
191
    {
192
        $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...
193
        $renderingContext = $this->baseRenderingContext;
194
        try {
195
            $parsedPartial = $renderingContext->getTemplateParser()->getOrParseAndStoreTemplate(
196
                $templatePaths->getPartialIdentifier($partialName),
197
                function (RenderingContextInterface $renderingContext) use ($partialName): string {
198
                    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...
199
                }
200
            );
201
            $parsedPartial->getArguments()->setRenderingContext($renderingContext);
202
            $this->renderingStack[] = $parsedPartial;
203
            if ($sectionName !== null) {
204
                $output = $this->renderSection($sectionName, $variables, $ignoreUnknown);
205
            } else {
206
                $parsedPartial->getArguments()->assignAll($variables)->validate();
207
                $output = $parsedPartial->evaluate($renderingContext);
208
            }
209
            array_pop($this->renderingStack);
210
        } catch (PassthroughSourceException $error) {
211
            return $error->getSource();
212
        } catch (InvalidTemplateResourceException $error) {
213
            if (!$ignoreUnknown) {
214
                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...
215
            }
216
            return '';
217
        } catch (Exception $error) {
218
            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...
219
        }
220
221
        return $output;
222
    }
223
224
    protected function getCurrentParsedTemplate(): ComponentInterface
225
    {
226
        $renderingContext = $this->baseRenderingContext;
227
        $parsedTemplate = end($this->renderingStack);
228
        if ($parsedTemplate) {
229
            return $parsedTemplate;
230
        }
231
        $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...
232
        $templateParser = $renderingContext->getTemplateParser();
233
234
        // Retrieve the current parsed template, which happens if the renderSection() method was called as first entry
235
        // method (as opposed to rendering through renderFile / renderSource which causes stack entries which in turn
236
        // causes this method to return early).
237
        // Support for the closures will be removed in Fluid 4.0 since they are a temporary measure.
238
        $parsedTemplate = $templateParser->getOrParseAndStoreTemplate(
239
            $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...
240
            $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...
241
                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...
242
            }
243
        );
244
        return $parsedTemplate;
245
    }
246
}