5ad12f4255a22fa350fb8e9a0d195e2843bbf1c9
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Classes / ViewHelpers / RenderAllFormValuesViewHelper.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Form\ViewHelpers;
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\Resource\File;
21 use TYPO3\CMS\Extbase\Domain\Model\FileReference;
22 use TYPO3\CMS\Form\Domain\Model\FormElements\FormElementInterface;
23 use TYPO3\CMS\Form\Domain\Model\Renderable\CompositeRenderableInterface;
24 use TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface;
25 use TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface;
26 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
27 use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
28 use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
29
30 /**
31 * Renders the values of a form
32 *
33 * Scope: frontend
34 * @api
35 */
36 class RenderAllFormValuesViewHelper extends AbstractViewHelper
37 {
38 use CompileWithRenderStatic;
39
40 /**
41 * @var bool
42 */
43 protected $escapeOutput = false;
44
45 /**
46 * Initialize the arguments.
47 *
48 * @internal
49 */
50 public function initializeArguments()
51 {
52 $this->registerArgument('renderable', RootRenderableInterface::class, 'A RootRenderableInterface instance', true);
53 $this->registerArgument('as', 'string', 'The name within the template', false, 'formValue');
54 }
55
56 /**
57 * Return array element by key.
58 *
59 * @param array $arguments
60 * @param \Closure $renderChildrenClosure
61 * @param RenderingContextInterface $renderingContext
62 * @return string the rendered form values
63 * @api
64 */
65 public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
66 {
67 $renderable = $arguments['renderable'];
68 $as = $arguments['as'];
69
70 if (!$renderable->isEnabled()) {
71 return '';
72 }
73
74 if ($renderable instanceof CompositeRenderableInterface) {
75 $elements = $renderable->getRenderablesRecursively();
76 } else {
77 $elements = [$renderable];
78 }
79
80 $formRuntime = $renderingContext
81 ->getViewHelperVariableContainer()
82 ->get(RenderRenderableViewHelper::class, 'formRuntime');
83
84 $output = '';
85 foreach ($elements as $element) {
86 $renderingOptions = $element->getRenderingOptions();
87
88 if (
89 !$element instanceof FormElementInterface
90 || (isset($renderingOptions['_isCompositeFormElement']) && (bool)$renderingOptions['_isCompositeFormElement'] === true)
91 || !$element->isEnabled()
92 || self::hasDisabledParent($element)
93 ) {
94 continue;
95 }
96
97 if (
98 (isset($renderingOptions['_isHiddenFormElement']) && (bool)$renderingOptions['_isHiddenFormElement'] === true)
99 || (isset($renderingOptions['_isReadOnlyFormElement']) && (bool)$renderingOptions['_isReadOnlyFormElement'] === true)
100 ) {
101 trigger_error(
102 'Using the properties "renderingOptions._isHiddenFormElement" and "renderingOptions._isReadOnlyFormElement" has been deprecated in v9 and will be removed in v10. Use variants instead.',
103 E_USER_DEPRECATED
104 );
105 continue;
106 }
107
108 $value = $formRuntime[$element->getIdentifier()];
109
110 $formValue = [
111 'element' => $element,
112 'value' => $value,
113 'processedValue' => self::processElementValue($element, $value, $renderChildrenClosure, $renderingContext),
114 'isMultiValue' => is_array($value) || $value instanceof \Iterator
115 ];
116 $renderingContext->getVariableProvider()->add($as, $formValue);
117 $output .= $renderChildrenClosure();
118 $renderingContext->getVariableProvider()->remove($as);
119 }
120 return $output;
121 }
122
123 /**
124 * Converts the given value to a simple type (string or array) considering the underlying FormElement definition
125 *
126 * @param FormElementInterface $element
127 * @param mixed $value
128 * @param \Closure $renderChildrenClosure
129 * @param RenderingContextInterface $renderingContext
130 * @return mixed
131 */
132 public static function processElementValue(
133 FormElementInterface $element,
134 $value,
135 \Closure $renderChildrenClosure,
136 RenderingContextInterface $renderingContext
137 ) {
138 $properties = $element->getProperties();
139 if (isset($properties['options']) && is_array($properties['options'])) {
140 $properties['options'] = TranslateElementPropertyViewHelper::renderStatic(
141 ['element' => $element, 'property' => 'options'],
142 $renderChildrenClosure,
143 $renderingContext
144 );
145 if (is_array($value)) {
146 return self::mapValuesToOptions($value, $properties['options']);
147 }
148 return self::mapValueToOption($value, $properties['options']);
149 }
150 if (is_object($value)) {
151 return self::processObject($element, $value);
152 }
153 return $value;
154 }
155
156 /**
157 * Replaces the given values (=keys) with the corresponding elements in $options
158 * @see mapValueToOption()
159 *
160 * @param array $value
161 * @param array $options
162 * @return array
163 */
164 public static function mapValuesToOptions(array $value, array $options): array
165 {
166 $result = [];
167 foreach ($value as $key) {
168 $result[] = self::mapValueToOption($key, $options);
169 }
170 return $result;
171 }
172
173 /**
174 * Replaces the given value (=key) with the corresponding element in $options
175 * If the key does not exist in $options, it is returned without modification
176 *
177 * @param mixed $value
178 * @param array $options
179 * @return mixed
180 */
181 public static function mapValueToOption($value, array $options)
182 {
183 return $options[$value] ?? $value;
184 }
185
186 /**
187 * Converts the given $object to a string representation considering the $element FormElement definition
188 *
189 * @param FormElementInterface $element
190 * @param object $object
191 * @return string
192 */
193 public static function processObject(FormElementInterface $element, $object): string
194 {
195 $properties = $element->getProperties();
196 if ($object instanceof \DateTime) {
197 if (
198 $element->getType() === 'DatePicker'
199 && isset($properties['dateFormat'])
200 ) {
201 $dateFormat = $properties['dateFormat'];
202 if (isset($properties['displayTimeSelector']) && $properties['displayTimeSelector'] === true) {
203 $dateFormat .= ' H:i';
204 }
205 } elseif ($element->getType() === 'Date') {
206 if (isset($properties['displayFormat'])) {
207 $dateFormat = $properties['displayFormat'];
208 } else {
209 $dateFormat = 'Y-m-d';
210 }
211 } else {
212 $dateFormat = \DateTime::W3C;
213 }
214
215 return $object->format($dateFormat);
216 }
217
218 if ($object instanceof File || $object instanceof FileReference) {
219 if ($object instanceof FileReference) {
220 $object = $object->getOriginalResource();
221 }
222 return $object->getName();
223 }
224
225 if (method_exists($object, '__toString')) {
226 return (string)$object;
227 }
228 return 'Object [' . get_class($object) . ']';
229 }
230
231 /**
232 * @return bool
233 */
234 public static function hasDisabledParent(RenderableInterface $renderable): bool
235 {
236 while ($renderable = $renderable->getParentRenderable()) {
237 if ($renderable instanceof RenderableInterface && !$renderable->isEnabled()) {
238 return true;
239 }
240 }
241
242 return false;
243 }
244 }