2 namespace TYPO3\CMS\Frontend\ContentObject
;
5 * This file is part of the TYPO3 CMS project.
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
14 * The TYPO3 project - inspiring people to share!
17 use TYPO3\CMS\Core\TypoScript\TypoScriptService
;
18 use TYPO3\CMS\Core\Utility\GeneralUtility
;
19 use TYPO3\CMS\Core\Utility\StringUtility
;
20 use TYPO3\CMS\Extbase\Configuration\ConfigurationManager
;
21 use TYPO3\CMS\Extbase\Mvc\Web\RequestBuilder
;
22 use TYPO3\CMS\Extbase\
Object\ObjectManager
;
23 use TYPO3\CMS\Fluid\View\StandaloneView
;
24 use TYPO3\CMS\Frontend\ContentObject\Exception\ContentRenderingException
;
27 * Contains FLUIDTEMPLATE class object
29 class FluidTemplateContentObject
extends AbstractContentObject
34 protected $view = null;
37 * @var ContentDataProcessor
39 protected $contentDataProcessor;
42 * @param ContentObjectRenderer $cObj
44 public function __construct(ContentObjectRenderer
$cObj)
46 parent
::__construct($cObj);
47 $this->contentDataProcessor
= GeneralUtility
::makeInstance(ContentDataProcessor
::class);
51 * @param ContentDataProcessor $contentDataProcessor
53 public function setContentDataProcessor($contentDataProcessor)
55 $this->contentDataProcessor
= $contentDataProcessor;
59 * Rendering the cObject, FLUIDTEMPLATE
61 * Configuration properties:
62 * - file string+stdWrap The FLUID template file
63 * - layoutRootPaths array of filepath+stdWrap Root paths to layouts (fallback)
64 * - partialRootPaths array of filepath+stdWrap Root paths to partials (fallback)
65 * - variable array of cObjects, the keys are the variable names in fluid
66 * - dataProcessing array of data processors which are classes to manipulate $data
67 * - extbase.pluginName
68 * - extbase.controllerExtensionName
69 * - extbase.controllerName
70 * - extbase.controllerActionName
74 * 10.templateName = MyTemplate
75 * 10.templateRootPaths.10 = EXT:site_configuration/Resources/Private/Templates/
76 * 10.partialRootPaths.10 = EXT:site_configuration/Resources/Private/Patials/
77 * 10.layoutRootPaths.10 = EXT:site_configuration/Resources/Private/Layouts/
80 * mylabel.value = Label from TypoScript coming
83 * @param array $conf Array of TypoScript properties
84 * @return string The HTML output
86 public function render($conf = [])
88 $parentView = $this->view
;
89 $this->initializeStandaloneViewInstance();
91 if (!is_array($conf)) {
95 $this->setFormat($conf);
96 $this->setTemplate($conf);
97 $this->setLayoutRootPath($conf);
98 $this->setPartialRootPath($conf);
99 $this->setExtbaseVariables($conf);
100 $this->assignSettings($conf);
101 $variables = $this->getContentObjectVariables($conf);
102 $variables = $this->contentDataProcessor
->process($this->cObj
, $conf, $variables);
104 $this->view
->assignMultiple($variables);
106 $this->renderFluidTemplateAssetsIntoPageRenderer();
107 $content = $this->renderFluidView();
108 $content = $this->applyStandardWrapToRenderedContent($content, $conf);
110 $this->view
= $parentView;
115 * Attempts to render HeaderAssets and FooterAssets sections from the
116 * Fluid template, then adds each (if not empty) to either header or
117 * footer, as appropriate, using PageRenderer.
119 protected function renderFluidTemplateAssetsIntoPageRenderer()
121 $pageRenderer = $this->getPageRenderer();
122 $headerAssets = $this->view
->renderSection('HeaderAssets', ['contentObject' => $this], true);
123 $footerAssets = $this->view
->renderSection('FooterAssets', ['contentObject' => $this], true);
124 if (!empty(trim($headerAssets))) {
125 $pageRenderer->addHeaderData($headerAssets);
127 if (!empty(trim($footerAssets))) {
128 $pageRenderer->addFooterData($footerAssets);
133 * Creating standalone view instance must not be done in construct() as
134 * it can lead to a nasty cache issue since content object instances
135 * are not always re-created by the content object rendered for every
136 * usage, but can be re-used. Thus, we need a fresh instance of
137 * StandaloneView every time render() is called.
139 protected function initializeStandaloneViewInstance()
141 $this->view
= GeneralUtility
::makeInstance(StandaloneView
::class);
147 * @param array $conf With possibly set file resource
148 * @throws \InvalidArgumentException
150 protected function setTemplate(array $conf)
152 // Fetch the Fluid template by templateName
154 (!empty($conf['templateName']) ||
!empty($conf['templateName.']))
155 && !empty($conf['templateRootPaths.']) && is_array($conf['templateRootPaths.'])
157 $templateRootPaths = $this->applyStandardWrapToFluidPaths($conf['templateRootPaths.']);
158 $this->view
->setTemplateRootPaths($templateRootPaths);
159 $templateName = isset($conf['templateName.'])
160 ?
$this->cObj
->stdWrap(isset($conf['templateName']) ?
$conf['templateName'] : '', $conf['templateName.'])
161 : $conf['templateName'];
162 $this->view
->setTemplate($templateName);
163 } elseif (!empty($conf['template']) && !empty($conf['template.'])) {
164 // Fetch the Fluid template by template cObject
165 $templateSource = $this->cObj
->cObjGetSingle($conf['template'], $conf['template.']);
166 if ($templateSource === '') {
167 throw new ContentRenderingException(
168 'Could not find template source for ' . $conf['template'],
172 $this->view
->setTemplateSource($templateSource);
174 // Fetch the Fluid template by file stdWrap
175 $file = isset($conf['file.']) ?
$this->cObj
->stdWrap($conf['file'], $conf['file.']) : $conf['file'];
176 /** @var $templateService \TYPO3\CMS\Core\TypoScript\TemplateService */
177 $templateService = $GLOBALS['TSFE']->tmpl
;
178 $templatePathAndFilename = $templateService->getFileName($file);
179 $this->view
->setTemplatePathAndFilename(PATH_site
. $templatePathAndFilename);
184 * Set layout root path if given in configuration
186 * @param array $conf Configuration array
188 protected function setLayoutRootPath(array $conf)
190 // Override the default layout path via typoscript
192 if (isset($conf['layoutRootPath']) ||
isset($conf['layoutRootPath.'])) {
193 $layoutRootPath = isset($conf['layoutRootPath.'])
194 ?
$this->cObj
->stdWrap($conf['layoutRootPath'], $conf['layoutRootPath.'])
195 : $conf['layoutRootPath'];
196 $layoutPaths[] = GeneralUtility
::getFileAbsFileName($layoutRootPath);
198 if (isset($conf['layoutRootPaths.'])) {
199 $layoutPaths = array_replace($layoutPaths, $this->applyStandardWrapToFluidPaths($conf['layoutRootPaths.']));
201 if (!empty($layoutPaths)) {
202 $this->view
->setLayoutRootPaths($layoutPaths);
207 * Set partial root path if given in configuration
209 * @param array $conf Configuration array
211 protected function setPartialRootPath(array $conf)
214 if (isset($conf['partialRootPath']) ||
isset($conf['partialRootPath.'])) {
215 $partialRootPath = isset($conf['partialRootPath.'])
216 ?
$this->cObj
->stdWrap($conf['partialRootPath'], $conf['partialRootPath.'])
217 : $conf['partialRootPath'];
218 $partialPaths[] = GeneralUtility
::getFileAbsFileName($partialRootPath);
220 if (isset($conf['partialRootPaths.'])) {
221 $partialPaths = array_replace($partialPaths, $this->applyStandardWrapToFluidPaths($conf['partialRootPaths.']));
223 if (!empty($partialPaths)) {
224 $this->view
->setPartialRootPaths($partialPaths);
229 * Set different format if given in configuration
231 * @param array $conf Configuration array
233 protected function setFormat(array $conf)
235 $format = isset($conf['format.']) ?
$this->cObj
->stdWrap($conf['format'], $conf['format.']) : $conf['format'];
237 $this->view
->setFormat($format);
242 * Set some extbase variables if given
244 * @param array $conf Configuration array
246 protected function setExtbaseVariables(array $conf)
248 /** @var $request \TYPO3\CMS\Extbase\Mvc\Request */
249 $requestPluginName = isset($conf['extbase.']['pluginName.']) ?
$this->cObj
->stdWrap($conf['extbase.']['pluginName'], $conf['extbase.']['pluginName.']) : $conf['extbase.']['pluginName'];
250 if ($requestPluginName) {
251 $this->view
->getRequest()->setPluginName($requestPluginName);
253 $requestControllerExtensionName = isset($conf['extbase.']['controllerExtensionName.']) ?
$this->cObj
->stdWrap($conf['extbase.']['controllerExtensionName'], $conf['extbase.']['controllerExtensionName.']) : $conf['extbase.']['controllerExtensionName'];
254 if ($requestControllerExtensionName) {
255 $this->view
->getRequest()->setControllerExtensionName($requestControllerExtensionName);
257 $requestControllerName = isset($conf['extbase.']['controllerName.']) ?
$this->cObj
->stdWrap($conf['extbase.']['controllerName'], $conf['extbase.']['controllerName.']) : $conf['extbase.']['controllerName'];
258 if ($requestControllerName) {
259 $this->view
->getRequest()->setControllerName($requestControllerName);
261 $requestControllerActionName = isset($conf['extbase.']['controllerActionName.']) ?
$this->cObj
->stdWrap($conf['extbase.']['controllerActionName'], $conf['extbase.']['controllerActionName.']) : $conf['extbase.']['controllerActionName'];
262 if ($requestControllerActionName) {
263 $this->view
->getRequest()->setControllerActionName($requestControllerActionName);
268 && $requestControllerExtensionName
269 && $requestControllerName
270 && $requestControllerActionName
272 $configurationManager = GeneralUtility
::makeInstance(ObjectManager
::class)->get(ConfigurationManager
::class);
273 $configurationManager->setConfiguration([
274 'extensionName' => $requestControllerExtensionName,
275 'pluginName' => $requestPluginName,
278 if (!isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$requestControllerExtensionName]['plugins'][$requestPluginName]['controllers'])) {
279 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$requestControllerExtensionName]['plugins'][$requestPluginName]['controllers'] = [
280 $requestControllerName => [
282 $requestControllerActionName,
288 $requestBuilder = GeneralUtility
::makeInstance(ObjectManager
::class)->get(RequestBuilder
::class);
289 $this->view
->getRenderingContext()->getControllerContext()->setRequest($requestBuilder->build());
294 * Compile rendered content objects in variables array ready to assign to the view
296 * @param array $conf Configuration array
297 * @return array the variables to be assigned
298 * @throws \InvalidArgumentException
300 protected function getContentObjectVariables(array $conf)
303 $reservedVariables = ['data', 'current'];
304 // Accumulate the variables to be process and loop them through cObjGetSingle
305 $variablesToProcess = (array)$conf['variables.'];
306 foreach ($variablesToProcess as $variableName => $cObjType) {
307 if (is_array($cObjType)) {
310 if (!in_array($variableName, $reservedVariables)) {
311 $variables[$variableName] = $this->cObj
->cObjGetSingle($cObjType, $variablesToProcess[$variableName . '.']);
313 throw new \
InvalidArgumentException(
314 'Cannot use reserved name "' . $variableName . '" as variable name in FLUIDTEMPLATE.',
319 $variables['data'] = $this->cObj
->data
;
320 $variables['current'] = $this->cObj
->data
[$this->cObj
->currentValKey
];
325 * Set any TypoScript settings to the view. This is similar to a
326 * default MVC action controller in extbase.
328 * @param array $conf Configuration
330 protected function assignSettings(array $conf)
332 if (isset($conf['settings.'])) {
333 /** @var $typoScriptService TypoScriptService */
334 $typoScriptService = GeneralUtility
::makeInstance(TypoScriptService
::class);
335 $settings = $typoScriptService->convertTypoScriptArrayToPlainArray($conf['settings.']);
336 $this->view
->assign('settings', $settings);
341 * Render fluid standalone view
345 protected function renderFluidView()
347 return $this->view
->render();
351 * Apply standard wrap to content
353 * @param string $content Rendered HTML content
354 * @param array $conf Configuration array
355 * @return string Standard wrapped content
357 protected function applyStandardWrapToRenderedContent($content, array $conf)
359 if (isset($conf['stdWrap.'])) {
360 $content = $this->cObj
->stdWrap($content, $conf['stdWrap.']);
366 * Applies stdWrap on Fluid path definitions
368 * @param array $paths
372 protected function applyStandardWrapToFluidPaths(array $paths)
375 foreach ($paths as $key => $path) {
376 if (StringUtility
::endsWith($key, '.')) {
377 if (isset($paths[substr($key, 0, -1)])) {
380 $path = $this->cObj
->stdWrap('', $path);
381 } elseif (isset($paths[$key . '.'])) {
382 $path = $this->cObj
->stdWrap($path, $paths[$key . '.']);
384 $finalPaths[$key] = GeneralUtility
::getFileAbsFileName($path);