Completed
Push — master ( 8e078a...edce3c )
by
unknown
15:28
created

FluidTemplateContentObject::setExtbaseVariables()   B

Complexity

Conditions 10
Paths 48

Size

Total Lines 43
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 28
nc 48
nop 1
dl 0
loc 43
rs 7.6666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the TYPO3 CMS project.
5
 *
6
 * It is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License, either version 2
8
 * of the License, or any later version.
9
 *
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 *
13
 * The TYPO3 project - inspiring people to share!
14
 */
15
16
namespace TYPO3\CMS\Frontend\ContentObject;
17
18
use TYPO3\CMS\Core\TypoScript\TypoScriptService;
19
use TYPO3\CMS\Core\Utility\GeneralUtility;
20
use TYPO3\CMS\Core\Utility\StringUtility;
21
use TYPO3\CMS\Extbase\Configuration\ConfigurationManager;
22
use TYPO3\CMS\Extbase\Mvc\Web\RequestBuilder;
23
use TYPO3\CMS\Extbase\Object\ObjectManager;
24
use TYPO3\CMS\Fluid\View\StandaloneView;
25
use TYPO3\CMS\Frontend\ContentObject\Exception\ContentRenderingException;
26
27
/**
28
 * Contains FLUIDTEMPLATE class object
29
 */
30
class FluidTemplateContentObject extends AbstractContentObject
31
{
32
    /**
33
     * @var StandaloneView
34
     */
35
    protected $view;
36
37
    /**
38
     * @var ContentDataProcessor
39
     */
40
    protected $contentDataProcessor;
41
42
    /**
43
     * @param ContentObjectRenderer $cObj
44
     */
45
    public function __construct(ContentObjectRenderer $cObj)
46
    {
47
        parent::__construct($cObj);
48
        $this->contentDataProcessor = GeneralUtility::makeInstance(ContentDataProcessor::class);
49
    }
50
51
    /**
52
     * @param ContentDataProcessor $contentDataProcessor
53
     */
54
    public function setContentDataProcessor($contentDataProcessor)
55
    {
56
        $this->contentDataProcessor = $contentDataProcessor;
57
    }
58
59
    /**
60
     * Rendering the cObject, FLUIDTEMPLATE
61
     *
62
     * Configuration properties:
63
     * - file string+stdWrap The FLUID template file
64
     * - layoutRootPaths array of filepath+stdWrap Root paths to layouts (fallback)
65
     * - partialRootPaths array of filepath+stdWrap Root paths to partials (fallback)
66
     * - variable array of cObjects, the keys are the variable names in fluid
67
     * - dataProcessing array of data processors which are classes to manipulate $data
68
     * - extbase.pluginName
69
     * - extbase.controllerExtensionName
70
     * - extbase.controllerName
71
     * - extbase.controllerActionName
72
     *
73
     * Example:
74
     * 10 = FLUIDTEMPLATE
75
     * 10.templateName = MyTemplate
76
     * 10.templateRootPaths.10 = EXT:site_configuration/Resources/Private/Templates/
77
     * 10.partialRootPaths.10 = EXT:site_configuration/Resources/Private/Partials/
78
     * 10.layoutRootPaths.10 = EXT:site_configuration/Resources/Private/Layouts/
79
     * 10.variables {
80
     *   mylabel = TEXT
81
     *   mylabel.value = Label from TypoScript coming
82
     * }
83
     *
84
     * @param array $conf Array of TypoScript properties
85
     * @return string The HTML output
86
     */
87
    public function render($conf = [])
88
    {
89
        $parentView = $this->view;
90
        $this->initializeStandaloneViewInstance();
91
92
        if (!is_array($conf)) {
0 ignored issues
show
introduced by
The condition is_array($conf) is always true.
Loading history...
93
            $conf = [];
94
        }
95
96
        $this->setFormat($conf);
97
        $this->setTemplate($conf);
98
        $this->setLayoutRootPath($conf);
99
        $this->setPartialRootPath($conf);
100
        $this->setExtbaseVariables($conf);
101
        $this->assignSettings($conf);
102
        $variables = $this->getContentObjectVariables($conf);
103
        $variables = $this->contentDataProcessor->process($this->cObj, $conf, $variables);
104
105
        $this->view->assignMultiple($variables);
106
107
        $this->renderFluidTemplateAssetsIntoPageRenderer();
108
        $content = $this->renderFluidView();
109
        $content = $this->applyStandardWrapToRenderedContent($content, $conf);
110
111
        $this->view = $parentView;
112
        return $content;
113
    }
114
115
    /**
116
     * Attempts to render HeaderAssets and FooterAssets sections from the
117
     * Fluid template, then adds each (if not empty) to either header or
118
     * footer, as appropriate, using PageRenderer.
119
     */
120
    protected function renderFluidTemplateAssetsIntoPageRenderer()
121
    {
122
        $pageRenderer = $this->getPageRenderer();
123
        $headerAssets = $this->view->renderSection('HeaderAssets', ['contentObject' => $this], true);
124
        $footerAssets = $this->view->renderSection('FooterAssets', ['contentObject' => $this], true);
125
        if (!empty(trim($headerAssets))) {
126
            $pageRenderer->addHeaderData($headerAssets);
127
        }
128
        if (!empty(trim($footerAssets))) {
129
            $pageRenderer->addFooterData($footerAssets);
130
        }
131
    }
132
133
    /**
134
     * Creating standalone view instance must not be done in construct() as
135
     * it can lead to a nasty cache issue since content object instances
136
     * are not always re-created by the content object rendered for every
137
     * usage, but can be re-used. Thus, we need a fresh instance of
138
     * StandaloneView every time render() is called.
139
     */
140
    protected function initializeStandaloneViewInstance()
141
    {
142
        $this->view = GeneralUtility::makeInstance(StandaloneView::class);
143
    }
144
145
    /**
146
     * Set template
147
     *
148
     * @param array $conf With possibly set file resource
149
     * @throws \InvalidArgumentException
150
     */
151
    protected function setTemplate(array $conf)
152
    {
153
        // Fetch the Fluid template by templateName
154
        if (
155
            (!empty($conf['templateName']) || !empty($conf['templateName.']))
156
            && !empty($conf['templateRootPaths.']) && is_array($conf['templateRootPaths.'])
157
        ) {
158
            $templateRootPaths = $this->applyStandardWrapToFluidPaths($conf['templateRootPaths.']);
159
            $this->view->setTemplateRootPaths($templateRootPaths);
160
            $templateName = $this->cObj->stdWrapValue('templateName', $conf);
161
            $this->view->setTemplate($templateName);
162
        } elseif (!empty($conf['template']) && !empty($conf['template.'])) {
163
            // Fetch the Fluid template by template cObject
164
            $templateSource = $this->cObj->cObjGetSingle($conf['template'], $conf['template.'], 'template');
165
            if ($templateSource === '') {
166
                throw new ContentRenderingException(
167
                    'Could not find template source for ' . $conf['template'],
168
                    1437420865
169
                );
170
            }
171
            $this->view->setTemplateSource($templateSource);
172
        } else {
173
            // Fetch the Fluid template by file stdWrap
174
            $file = $this->cObj->stdWrapValue('file', $conf);
175
            // Get the absolute file name
176
            $templatePathAndFilename = GeneralUtility::getFileAbsFileName($file);
177
            $this->view->setTemplatePathAndFilename($templatePathAndFilename);
178
        }
179
    }
180
181
    /**
182
     * Set layout root path if given in configuration
183
     *
184
     * @param array $conf Configuration array
185
     */
186
    protected function setLayoutRootPath(array $conf)
187
    {
188
        // Override the default layout path via typoscript
189
        $layoutPaths = [];
190
        $layoutRootPath = $this->cObj->stdWrapValue('layoutRootPath', $conf);
191
        if ($layoutRootPath) {
192
            $layoutPaths[] = GeneralUtility::getFileAbsFileName($layoutRootPath);
193
        }
194
        if (isset($conf['layoutRootPaths.'])) {
195
            $layoutPaths = array_replace($layoutPaths, $this->applyStandardWrapToFluidPaths($conf['layoutRootPaths.']));
196
        }
197
        if (!empty($layoutPaths)) {
198
            $this->view->setLayoutRootPaths($layoutPaths);
199
        }
200
    }
201
202
    /**
203
     * Set partial root path if given in configuration
204
     *
205
     * @param array $conf Configuration array
206
     */
207
    protected function setPartialRootPath(array $conf)
208
    {
209
        $partialPaths = [];
210
        $partialRootPath = $this->cObj->stdWrapValue('partialRootPath', $conf);
211
        if ($partialRootPath) {
212
            $partialPaths[] = GeneralUtility::getFileAbsFileName($partialRootPath);
213
        }
214
        if (isset($conf['partialRootPaths.'])) {
215
            $partialPaths = array_replace($partialPaths, $this->applyStandardWrapToFluidPaths($conf['partialRootPaths.']));
216
        }
217
        if (!empty($partialPaths)) {
218
            $this->view->setPartialRootPaths($partialPaths);
219
        }
220
    }
221
222
    /**
223
     * Set different format if given in configuration
224
     *
225
     * @param array $conf Configuration array
226
     */
227
    protected function setFormat(array $conf)
228
    {
229
        $format = $this->cObj->stdWrapValue('format', $conf);
230
        if ($format) {
231
            $this->view->setFormat($format);
232
        }
233
    }
234
235
    /**
236
     * Set some extbase variables if given
237
     *
238
     * @param array $conf Configuration array
239
     */
240
    protected function setExtbaseVariables(array $conf)
241
    {
242
        $requestPluginName = $this->cObj->stdWrapValue('pluginName', $conf['extbase.'] ?? []);
243
        if ($requestPluginName) {
244
            $this->view->getRequest()->setPluginName($requestPluginName);
245
        }
246
        $requestControllerExtensionName = $this->cObj->stdWrapValue('controllerExtensionName', $conf['extbase.'] ?? []);
247
        if ($requestControllerExtensionName) {
248
            $this->view->getRequest()->setControllerExtensionName($requestControllerExtensionName);
249
        }
250
        $requestControllerName = $this->cObj->stdWrapValue('controllerName', $conf['extbase.'] ?? []);
251
        if ($requestControllerName) {
252
            $this->view->getRequest()->setControllerName($requestControllerName);
253
        }
254
        $requestControllerActionName = $this->cObj->stdWrapValue('controllerActionName', $conf['extbase.'] ?? []);
255
        if ($requestControllerActionName) {
256
            $this->view->getRequest()->setControllerActionName($requestControllerActionName);
257
        }
258
259
        if (
260
            $requestPluginName
261
            && $requestControllerExtensionName
262
            && $requestControllerName
263
            && $requestControllerActionName
264
        ) {
265
            $configurationManager = GeneralUtility::makeInstance(ObjectManager::class)->get(ConfigurationManager::class);
266
            $configurationManager->setConfiguration([
267
                'extensionName' => $requestControllerExtensionName,
268
                'pluginName' => $requestPluginName,
269
            ]);
270
271
            if (!isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$requestControllerExtensionName]['plugins'][$requestPluginName]['controllers'])) {
272
                $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$requestControllerExtensionName]['plugins'][$requestPluginName]['controllers'] = [
273
                    $requestControllerName => [
274
                        'actions' => [
275
                            $requestControllerActionName,
276
                        ],
277
                    ],
278
                ];
279
            }
280
281
            $requestBuilder = GeneralUtility::makeInstance(ObjectManager::class)->get(RequestBuilder::class);
282
            $this->view->getRenderingContext()->getControllerContext()->setRequest($requestBuilder->build());
0 ignored issues
show
Bug introduced by
The method getControllerContext() does not exist on TYPO3Fluid\Fluid\Core\Re...nderingContextInterface. Did you maybe mean getControllerAction()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

282
            $this->view->getRenderingContext()->/** @scrutinizer ignore-call */ getControllerContext()->setRequest($requestBuilder->build());

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...
283
        }
284
    }
285
286
    /**
287
     * Compile rendered content objects in variables array ready to assign to the view
288
     *
289
     * @param array $conf Configuration array
290
     * @return array the variables to be assigned
291
     * @throws \InvalidArgumentException
292
     */
293
    protected function getContentObjectVariables(array $conf)
294
    {
295
        $variables = [];
296
        $reservedVariables = ['data', 'current'];
297
        // Accumulate the variables to be process and loop them through cObjGetSingle
298
        $variablesToProcess = (array)($conf['variables.'] ?? []);
299
        foreach ($variablesToProcess as $variableName => $cObjType) {
300
            if (is_array($cObjType)) {
301
                continue;
302
            }
303
            if (!in_array($variableName, $reservedVariables)) {
304
                $variables[$variableName] = $this->cObj->cObjGetSingle($cObjType, $variablesToProcess[$variableName . '.'], 'variables.' . $variableName);
305
            } else {
306
                throw new \InvalidArgumentException(
307
                    'Cannot use reserved name "' . $variableName . '" as variable name in FLUIDTEMPLATE.',
308
                    1288095720
309
                );
310
            }
311
        }
312
        $variables['data'] = $this->cObj->data;
313
        $variables['current'] = $this->cObj->data[$this->cObj->currentValKey ?? null] ?? null;
314
        return $variables;
315
    }
316
317
    /**
318
     * Set any TypoScript settings to the view. This is similar to a
319
     * default MVC action controller in extbase.
320
     *
321
     * @param array $conf Configuration
322
     */
323
    protected function assignSettings(array $conf)
324
    {
325
        if (isset($conf['settings.'])) {
326
            /** @var TypoScriptService $typoScriptService */
327
            $typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
328
            $settings = $typoScriptService->convertTypoScriptArrayToPlainArray($conf['settings.']);
329
            $this->view->assign('settings', $settings);
330
        }
331
    }
332
333
    /**
334
     * Render fluid standalone view
335
     *
336
     * @return string
337
     */
338
    protected function renderFluidView()
339
    {
340
        return $this->view->render();
341
    }
342
343
    /**
344
     * Apply standard wrap to content
345
     *
346
     * @param string $content Rendered HTML content
347
     * @param array $conf Configuration array
348
     * @return string Standard wrapped content
349
     */
350
    protected function applyStandardWrapToRenderedContent($content, array $conf)
351
    {
352
        if (isset($conf['stdWrap.'])) {
353
            $content = $this->cObj->stdWrap($content, $conf['stdWrap.']);
354
        }
355
        return $content;
356
    }
357
358
    /**
359
     * Applies stdWrap on Fluid path definitions
360
     *
361
     * @param array $paths
362
     *
363
     * @return array
364
     */
365
    protected function applyStandardWrapToFluidPaths(array $paths)
366
    {
367
        $finalPaths = [];
368
        foreach ($paths as $key => $path) {
369
            if (StringUtility::endsWith($key, '.')) {
370
                if (isset($paths[substr($key, 0, -1)])) {
371
                    continue;
372
                }
373
                $path = $this->cObj->stdWrap('', $path);
374
            } elseif (isset($paths[$key . '.'])) {
375
                $path = $this->cObj->stdWrap($path, $paths[$key . '.']);
376
            }
377
            $finalPaths[$key] = GeneralUtility::getFileAbsFileName($path);
378
        }
379
        return $finalPaths;
380
    }
381
}
382