[FOLLOWUP][TASK] EXT:form - change signal slots to hooks
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Classes / Domain / Renderer / FluidFormRenderer.php
1 <?php
2 declare(strict_types=1);
3 namespace TYPO3\CMS\Form\Domain\Renderer;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It originated from the Neos.Form package (www.neos.io)
9 *
10 * It is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU General Public License, either version 2
12 * of the License, or any later version.
13 *
14 * For the full copyright and license information, please read the
15 * LICENSE.txt file that was distributed with this source code.
16 *
17 * The TYPO3 project - inspiring people to share!
18 */
19
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\CMS\Extbase\Object\ObjectManager;
22 use TYPO3\CMS\Fluid\View\TemplateView;
23 use TYPO3\CMS\Form\Domain\Exception\RenderingException;
24 use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
25 use TYPO3\CMS\Form\ViewHelpers\RenderRenderableViewHelper;
26
27 /**
28 * A fluid RendererInterface implementation which used to render a *FormDefinition*.
29 *
30 * This renderer is called from {@link \TYPO3\CMS\Form\Domain\Runtime\FormRuntime::render()}.
31 *
32 * Options
33 * =======
34 *
35 * The FluidFormRenderer uses some rendering options which are of particular
36 * importance, as they determine how the form field is resolved to a path
37 * in the file system.
38 *
39 * All rendering options are retrieved from the FormDefinition,
40 * using the {@link \TYPO3\CMS\Form\Domain\Model\FormDefinition::getRenderingOptions()}
41 * method.
42 *
43 * templateRootPaths
44 * -----------------
45 *
46 * Used to define several paths for templates, which will be tried in reversed
47 * order (the paths are searched from bottom to top). The first folder where
48 * the desired layout is found, is used. If the array keys are numeric,
49 * they are first sorted and then tried in reversed order.
50 * Within this paths, fluid will search for a file which is named like the
51 * renderable *type*.
52 * For example:
53 * templateRootPaths.10 = EXT:form/Resources/Private/Frontend/Templates/
54 * $renderable->getType() = Form
55 * Expected template file: EXT:form/Resources/Private/Frontend/Templates/Form.html
56 * There is a setting available to set a custom template name. Please read
57 * the section 'templateName'.
58 *
59 * Only the root renderable (FormDefinition) has to be a template file.
60 * All child renderables are partials. By default, the root renderable
61 * is called 'Form'.
62 *
63 * layoutRootPaths
64 * ---------------
65 *
66 * Used to define several paths for layouts, which will be tried in reversed
67 * order (the paths are searched from bottom to top). The first folder where
68 * the desired layout is found, is used. If the array keys are numeric,
69 * they are first sorted and then tried in reversed order.
70 *
71 * partialRootPaths
72 * ----------------
73 *
74 * Used to define several paths for partials, which will be tried in reversed
75 * order. The first folder where the desired partial is found, is used.
76 * The keys of the array define the order.
77 *
78 * Within this paths, fluid will search for a file which is named like the
79 * renderable *type*.
80 * For example:
81 * templateRootPaths.10 = EXT:form/Resources/Private/Frontend/Partials/
82 * $renderable->getType() = Text
83 * Expected template file: EXT:form/Resources/Private/Frontend/Partials/Text.html
84 * There is a setting available to set a custom partial name. Please read
85 * the section 'templateName'.
86 *
87 * templateName
88 * -----------
89 * By default, the renderable type will be taken as the name for the
90 * template / partial.
91 * For example:
92 * partialRootPaths.10 = EXT:form/Resources/Private/Frontend/Partials/
93 * $renderable->getType() = Text
94 * Expected partial file: EXT:form/Resources/Private/Frontend/Partials/Text.html
95 *
96 * Set 'templateName' to define a custom name which should be used instead.
97 * For example:
98 * templateName = Foo
99 * $renderable->getType() = Text
100 * Expected partial file: EXT:form/Resources/Private/Frontend/Partials/Foo.html
101 *
102 * Rendering Child Renderables
103 * ===========================
104 *
105 * If a renderable wants to render child renderables, inside its template / partial,
106 * it can do that using the <code><formvh:renderRenderable></code> ViewHelper.
107 *
108 * A template example from Page shall demonstrate this:
109 *
110 * <pre>
111 * <formvh:renderRenderable renderable="{page}">
112 * <f:for each="{page.elements}" as="element">
113 * <formvh:renderRenderable renderable="{element}">
114 * <f:render partial="{element.templateName}" arguments="{element: element}" />
115 * </formvh:renderRenderable>
116 * </f:for>
117 * </formvh:renderRenderable>
118 * </pre>
119 *
120 * Scope: frontend
121 * **This class is NOT meant to be sub classed by developers.**
122 * @internal
123 */
124 class FluidFormRenderer extends AbstractElementRenderer implements RendererInterface
125 {
126
127 /**
128 * Renders the FormDefinition.
129 *
130 * This method is expected to call the 'beforeRendering' hook
131 * on each renderable.
132 * This method call the 'beforeRendering' hook initially.
133 * Each other hooks will be called from the
134 * renderRenderable viewHelper.
135 * {@link \TYPO3\CMS\Form\ViewHelpers\RenderRenderableViewHelper::renderStatic()}
136 *
137 * @return string the rendered $formRuntime
138 * @internal
139 */
140 public function render(): string
141 {
142 $formElementType = $this->formRuntime->getType();
143 $renderingOptions = $this->formRuntime->getRenderingOptions();
144
145 $view = GeneralUtility::makeInstance(ObjectManager::class)
146 ->get(TemplateView::class);
147 $view->setControllerContext($this->controllerContext);
148
149 if (!isset($renderingOptions['templateRootPaths'])) {
150 throw new RenderingException(
151 sprintf('The option templateRootPaths must be set for renderable "%s"', $formElementType),
152 1480293084
153 );
154 }
155 if (!isset($renderingOptions['layoutRootPaths'])) {
156 throw new RenderingException(
157 sprintf('The option layoutRootPaths must be set for renderable "%s"', $formElementType),
158 1480293085
159 );
160 }
161 if (!isset($renderingOptions['partialRootPaths'])) {
162 throw new RenderingException(
163 sprintf('The option partialRootPaths must be set for renderable "%s"', $formElementType),
164 1480293086
165 );
166 }
167
168 $view->assign('form', $this->formRuntime);
169
170 $view->getRenderingContext()
171 ->getViewHelperVariableContainer()
172 ->addOrUpdate(RenderRenderableViewHelper::class, 'formRuntime', $this->formRuntime);
173
174 // Configure the fluid TemplatePaths with the rendering options
175 // from the renderable
176 $view->getTemplatePaths()->fillFromConfigurationArray($renderingOptions);
177
178 GeneralUtility::deprecationLog('EXT:form - calls for "beforeRendering" are deprecated since TYPO3 v8 and will be removed in TYPO3 v9');
179 $this->formRuntime->getFormDefinition()->beforeRendering($this->formRuntime);
180
181 if (
182 isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['beforeRendering'])
183 && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['beforeRendering'])
184 ) {
185 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['beforeRendering'] as $className) {
186 $hookObj = GeneralUtility::makeInstance($className);
187 if (method_exists($hookObj, 'beforeRendering')) {
188 $hookObj->beforeRendering(
189 $this->formRuntime,
190 $this->formRuntime->getFormDefinition()
191 );
192 }
193 }
194 }
195
196 return $view->render($this->formRuntime->getTemplateName());
197 }
198 }