$path . 'Pages/', $paths), // @todo: We should *still* allow setting both partialRootPaths and layoutRootPaths, and only fall back to // [templateRootPaths]/Partials and [templateRootPaths]/Layouts if not set. And the fallback should be // advertised as best practice. partialRootPaths: array_map(static fn(string $path): string => $path . 'Partials/', $paths), layoutRootPaths: array_map(static fn(string $path): string => $path . 'Layouts/', $paths), request: $this->request, ); $view = $this->viewFactory->create($viewFactoryData); $pageSettings = $this->request->getAttribute('frontend.typoscript')->getSettingsTree()->toArray(); $view->assign('settings', $this->typoScriptService->convertTypoScriptArrayToPlainArray($pageSettings)); $variables = $this->getContentObjectVariables($conf); $variables = $this->contentDataProcessor->process($this->cObj, $conf, $variables); $view->assignMultiple($variables); // Fetch the Fluid template by the name of the Page Layout and underneath "Pages" $pageInformationObject = $this->request->getAttribute('frontend.page.information'); $pageLayoutName = $this->pageLayoutResolver->getLayoutIdentifierForPageWithoutPrefix( $pageInformationObject->getPageRecord(), $pageInformationObject->getRootLine() ); try { return $view->render($pageLayoutName); } catch (InvalidTemplateResourceException $e) { // Only add a PAGEVIEW specific message in case the exception has been thrown for the given template. if ($e instanceof InvalidPartialException || $e instanceof InvalidLayoutException || $e->templateName !== 'Default/' . $pageLayoutName) { throw $e; } throw new InvalidTemplateResourceException( sprintf( 'PAGEVIEW TypoScript object: Failed to resolve a template file for page layout "%s". See also: %s. The following paths were checked: "%s"', $pageLayoutName, Typo3Information::getDocsLink('t3tsref:cobj-pageview'), implode('", "', $e->evaluatedTemplatePaths), ), 1742058289, $e, $e->templateName, $e->evaluatedTemplatePaths, ); } } /** * Compile rendered content objects in variables array ready to assign to the view * * @param array $conf Configuration array * @return array the variables to be assigned */ private function getContentObjectVariables(array $conf): array { $pageInformation = $this->request->getAttribute('frontend.page.information'); $variables = [ 'site' => $this->request->getAttribute('site'), 'language' => $this->request->getAttribute('language'), 'page' => $pageInformation, ]; // Accumulate the variables to be process and loop them through cObjGetSingle if (is_array($conf['variables.'] ?? false) && $conf['variables.'] !== []) { foreach ($conf['variables.'] as $variableName => $cObjType) { if (!is_string($cObjType)) { continue; } if (in_array($variableName, self::reservedVariables, true)) { throw new \InvalidArgumentException( 'Cannot use reserved name "' . $variableName . '" as variable name in PAGEVIEW.', 1711748615 ); } $cObjConf = $conf['variables.'][$variableName . '.'] ?? []; $variables[$variableName] = $this->cObj->cObjGetSingle($cObjType, $cObjConf, 'variables.' . $variableName); } } if (!($conf['contentAs'] ?? false) && isset($variables['content'])) { throw new \InvalidArgumentException( 'No variable name ("contentAs" option) for the content areas has been defined in PAGEVIEW, and the fallback name "content" is not available because it has been manually set.', 1726475574 ); } $variables[$conf['contentAs'] ?? 'content'] = $pageInformation->getPageLayout()?->getContentAreas()->withRequest($this->request); return $variables; } }