1
|
|
|
<?php |
2
|
|
|
/* |
3
|
|
|
* 2017 Romain CANON <[email protected]> |
4
|
|
|
* |
5
|
|
|
* This file is part of the TYPO3 FormZ project. |
6
|
|
|
* It is free software; you can redistribute it and/or modify it |
7
|
|
|
* under the terms of the GNU General Public License, either |
8
|
|
|
* version 3 of the License, or any later version. |
9
|
|
|
* |
10
|
|
|
* For the full copyright and license information, see: |
11
|
|
|
* http://www.gnu.org/licenses/gpl-3.0.html |
12
|
|
|
*/ |
13
|
|
|
|
14
|
|
|
namespace Romm\Formz\Service\ViewHelper; |
15
|
|
|
|
16
|
|
|
use Romm\Formz\AssetHandler\Html\DataAttributesAssetHandler; |
17
|
|
|
use Romm\Formz\Behaviours\BehavioursManager; |
18
|
|
|
use Romm\Formz\Core\Core; |
19
|
|
|
use Romm\Formz\Exceptions\DuplicateEntryException; |
20
|
|
|
use Romm\Formz\Form\Definition\Step\Step\Step; |
21
|
|
|
use Romm\Formz\Form\FormObject\FormObject; |
22
|
|
|
use Romm\Formz\Validation\Validator\Form\AbstractFormValidator; |
23
|
|
|
use Romm\Formz\Validation\Validator\Form\DefaultFormValidator; |
24
|
|
|
use TYPO3\CMS\Core\SingletonInterface; |
25
|
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility; |
26
|
|
|
use TYPO3\CMS\Extbase\Configuration\ConfigurationManager; |
27
|
|
|
use TYPO3\CMS\Extbase\Error\Error; |
28
|
|
|
use TYPO3\CMS\Extbase\Error\Result; |
29
|
|
|
use TYPO3\CMS\Extbase\Mvc\Web\Request; |
30
|
|
|
use TYPO3\CMS\Fluid\Core\ViewHelper\ViewHelperVariableContainer; |
31
|
|
|
use TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* This class contains methods that help view helpers to manipulate data and |
35
|
|
|
* know more things concerning the current form state. |
36
|
|
|
* |
37
|
|
|
* It is mainly configured inside the `FormViewHelper`, and used in other |
38
|
|
|
* view helpers. |
39
|
|
|
*/ |
40
|
|
|
class FormViewHelperService implements SingletonInterface |
41
|
|
|
{ |
42
|
|
|
/** |
43
|
|
|
* @var bool |
44
|
|
|
*/ |
45
|
|
|
protected $formContext = false; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var FormObject |
49
|
|
|
*/ |
50
|
|
|
protected $formObject; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @var Request |
54
|
|
|
*/ |
55
|
|
|
protected $request; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* @var Result |
59
|
|
|
*/ |
60
|
|
|
protected $result; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Reset every state that can be used by this service. |
64
|
|
|
*/ |
65
|
|
|
public function resetState() |
66
|
|
|
{ |
67
|
|
|
$this->formContext = false; |
68
|
|
|
$this->formObject = null; |
69
|
|
|
$this->request = null; |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Will activate the form context, changing the result returned by the |
74
|
|
|
* function `formContextExists()`. |
75
|
|
|
* |
76
|
|
|
* @return FormViewHelperService |
77
|
|
|
* @throws DuplicateEntryException |
78
|
|
|
*/ |
79
|
|
|
public function activateFormContext() |
80
|
|
|
{ |
81
|
|
|
if (true === $this->formContext) { |
82
|
|
|
throw DuplicateEntryException::duplicatedFormContext(); |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
$this->formContext = true; |
86
|
|
|
$this->result = new Result; |
87
|
|
|
|
88
|
|
|
return $this; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Returns `true` if the `FormViewHelper` context exists. |
93
|
|
|
* |
94
|
|
|
* @return bool |
95
|
|
|
*/ |
96
|
|
|
public function formContextExists() |
97
|
|
|
{ |
98
|
|
|
return $this->formContext; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* Will loop on the submitted form fields and apply behaviours if their |
103
|
|
|
* configuration contains. |
104
|
|
|
*/ |
105
|
|
|
public function applyBehavioursOnSubmittedForm() |
106
|
|
|
{ |
107
|
|
|
if ($this->formObject->formWasSubmitted()) { |
108
|
|
|
$request = $this->request->getOriginalRequest(); |
109
|
|
|
$formName = $this->formObject->getName(); |
110
|
|
|
|
111
|
|
|
if ($request |
112
|
|
|
&& $request->hasArgument($formName) |
113
|
|
|
) { |
114
|
|
|
/** @var BehavioursManager $behavioursManager */ |
115
|
|
|
$behavioursManager = GeneralUtility::makeInstance(BehavioursManager::class); |
116
|
|
|
|
117
|
|
|
/** @var array $originalForm */ |
118
|
|
|
$originalForm = $request->getArgument($formName); |
119
|
|
|
|
120
|
|
|
$formProperties = $behavioursManager->applyBehaviourOnPropertiesArray( |
121
|
|
|
$originalForm, |
122
|
|
|
$this->formObject->getDefinition() |
123
|
|
|
); |
124
|
|
|
|
125
|
|
|
$request->setArgument($formName, $formProperties); |
126
|
|
|
} |
127
|
|
|
} |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* Takes care of injecting data for the form. |
132
|
|
|
* |
133
|
|
|
* If the form was generated using a content object, information about it |
134
|
|
|
* are injected, to be retrieved later to be able for instance to fetch the |
135
|
|
|
* object settings (TypoScript, FlexForm, ...). |
136
|
|
|
*/ |
137
|
|
|
public function injectFormRequestData() |
138
|
|
|
{ |
139
|
|
|
if (false === $this->formObject->hasForm()) { |
140
|
|
|
return; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** @var ConfigurationManager $configurationManager */ |
144
|
|
|
$configurationManager = Core::instantiate(ConfigurationManager::class); |
145
|
|
|
|
146
|
|
|
$contentObject = $configurationManager->getContentObject(); |
147
|
|
|
|
148
|
|
|
if (null !== $contentObject) { |
149
|
|
|
$requestData = $this->formObject->getRequestData(); |
150
|
|
|
|
151
|
|
|
$requestData->setContentObjectTable($contentObject->getCurrentTable()); |
152
|
|
|
$requestData->setContentObjectUid($contentObject->data['uid']); |
153
|
|
|
} |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* @todo |
158
|
|
|
* |
159
|
|
|
* @param DataAttributesAssetHandler $dataAttributesAssetHandler |
160
|
|
|
* @return array |
161
|
|
|
*/ |
162
|
|
|
public function getDataAttributes(DataAttributesAssetHandler $dataAttributesAssetHandler) |
163
|
|
|
{ |
164
|
|
|
$dataAttributes = []; |
165
|
|
|
|
166
|
|
|
if ($this->formObject->hasForm()) { |
167
|
|
|
if (false === $this->formObject->formWasValidated()) { |
168
|
|
|
$form = $this->formObject->getForm(); |
169
|
|
|
$formValidator = $this->getFormValidator($this->formObject->getName()); |
170
|
|
|
$formResult = $formValidator->validate($form); |
171
|
|
|
} else { |
172
|
|
|
$formResult = $this->formObject->getFormResult(); |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
$dataAttributes += $dataAttributesAssetHandler->getFieldsValuesDataAttributes($formResult); |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
if (true === $this->formObject->formWasSubmitted()) { |
179
|
|
|
$dataAttributes += [DataAttributesAssetHandler::getFieldSubmissionDone() => '1']; |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
if (true === $this->formObject->formWasValidated()) { |
183
|
|
|
$dataAttributes += $dataAttributesAssetHandler->getFieldsValidDataAttributes(); |
184
|
|
|
$dataAttributes += $dataAttributesAssetHandler->getFieldsMessagesDataAttributes(); |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
return $dataAttributes; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* Checks if the form uses steps, in which case the current step is needed |
192
|
|
|
* in order to display the form. If the step is not found, an exception is |
193
|
|
|
* thrown. |
194
|
|
|
*/ |
195
|
|
|
public function checkStepDefinition() |
196
|
|
|
{ |
197
|
|
|
if ($this->formObject->getDefinition()->hasSteps() |
198
|
|
|
&& null === $this->getCurrentStep() |
199
|
|
|
) { |
200
|
|
|
throw new \Exception('todo'); // @todo |
201
|
|
|
} |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* Will check all the fields that have been added below the form view |
206
|
|
|
* helper: each field that is found in the form definition and is *not* |
207
|
|
|
* supported by the current step will add an error and cancel the form |
208
|
|
|
* rendering. |
209
|
|
|
* |
210
|
|
|
* @param ViewHelperVariableContainer $variableContainer |
211
|
|
|
*/ |
212
|
|
|
public function checkStepFields(ViewHelperVariableContainer $variableContainer) |
213
|
|
|
{ |
214
|
|
|
$currentStep = $this->getCurrentStep(); |
215
|
|
|
|
216
|
|
|
if (null === $currentStep) { |
217
|
|
|
return; |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
$unsupportedFieldsList = []; |
221
|
|
|
$formDefinition = $this->formObject->getDefinition(); |
222
|
|
|
$fieldNames = $this->getCurrentFormFieldNames($variableContainer); |
223
|
|
|
|
224
|
|
|
foreach ($fieldNames as $fieldName) { |
225
|
|
|
if (false === $formDefinition->hasField($fieldName)) { |
226
|
|
|
continue; |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
$field = $formDefinition->getField($fieldName); |
230
|
|
|
|
231
|
|
|
if (false === $currentStep->supportsField($field)) { |
232
|
|
|
$unsupportedFieldsList[] = $fieldName; |
233
|
|
|
} |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
if ($unsupportedFieldsList) { |
|
|
|
|
237
|
|
|
$error = new Error( |
238
|
|
|
'The following fields are not supported by the step "%s": "%s". Please add these fields to the supported fields list of the step in order to render it in your template.', |
239
|
|
|
1494430935, |
240
|
|
|
[$currentStep->getIdentifier(), implode('", "', $unsupportedFieldsList)] |
241
|
|
|
); |
242
|
|
|
$this->result->addError($error); |
243
|
|
|
} |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* Returns the list of fields that have been added below the form view |
248
|
|
|
* helper. |
249
|
|
|
* |
250
|
|
|
* @param ViewHelperVariableContainer $variableContainer |
251
|
|
|
* @return array |
252
|
|
|
*/ |
253
|
|
|
public function getCurrentFormFieldNames(ViewHelperVariableContainer $variableContainer) |
254
|
|
|
{ |
255
|
|
|
$formFieldNames = $variableContainer->get(FormViewHelper::class, 'formFieldNames'); |
256
|
|
|
$cleanFormFieldNames = []; |
257
|
|
|
|
258
|
|
|
foreach ($formFieldNames as $fieldName) { |
259
|
|
|
$explode = explode('[', $fieldName); |
260
|
|
|
|
261
|
|
|
if (count($explode) >= 3) { |
262
|
|
|
$formName = rtrim($explode[1], ']'); |
263
|
|
|
$fieldName = rtrim($explode[2], ']'); |
264
|
|
|
|
265
|
|
|
if ($formName === $this->formObject->getName() |
266
|
|
|
&& $fieldName !== '__identity' |
267
|
|
|
) { |
268
|
|
|
$cleanFormFieldNames[$fieldName] = $fieldName; |
269
|
|
|
} |
270
|
|
|
} |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
return $cleanFormFieldNames; |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
/** |
277
|
|
|
* @param string $formName |
278
|
|
|
* @return AbstractFormValidator |
279
|
|
|
*/ |
280
|
|
|
protected function getFormValidator($formName) |
281
|
|
|
{ |
282
|
|
|
/** @var AbstractFormValidator $validator */ |
283
|
|
|
$validator = Core::instantiate( |
284
|
|
|
DefaultFormValidator::class, |
285
|
|
|
[ |
286
|
|
|
'name' => $formName, |
287
|
|
|
'dummy' => true |
288
|
|
|
] |
289
|
|
|
); |
290
|
|
|
|
291
|
|
|
return $validator; |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* @return Step|null |
296
|
|
|
*/ |
297
|
|
|
public function getCurrentStep() |
298
|
|
|
{ |
299
|
|
|
return $this->formObject->getCurrentStep($this->request); |
300
|
|
|
} |
301
|
|
|
|
302
|
|
|
/** |
303
|
|
|
* @return FormObject |
304
|
|
|
*/ |
305
|
|
|
public function getFormObject() |
306
|
|
|
{ |
307
|
|
|
return $this->formObject; |
308
|
|
|
} |
309
|
|
|
|
310
|
|
|
/** |
311
|
|
|
* @param FormObject $formObject |
312
|
|
|
*/ |
313
|
|
|
public function setFormObject(FormObject $formObject) |
314
|
|
|
{ |
315
|
|
|
$this->formObject = $formObject; |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
/** |
319
|
|
|
* @param Request $request |
320
|
|
|
*/ |
321
|
|
|
public function setRequest(Request $request) |
322
|
|
|
{ |
323
|
|
|
$this->request = $request; |
324
|
|
|
} |
325
|
|
|
|
326
|
|
|
/** |
327
|
|
|
* @return Result |
328
|
|
|
*/ |
329
|
|
|
public function getResult() |
330
|
|
|
{ |
331
|
|
|
return $this->result; |
332
|
|
|
} |
333
|
|
|
} |
334
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.