Completed
Push — wip/steps ( 0e4101...4c32fc )
by Romain
03:57
created

FormViewHelperService::setFormObject()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
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\Form;
15
16
use Romm\Formz\AssetHandler\Html\DataAttributesAssetHandler;
17
use Romm\Formz\Behaviours\BehavioursManager;
18
use Romm\Formz\Core\Core;
19
use Romm\Formz\Error\FormResult;
20
use Romm\Formz\Exceptions\DuplicateEntryException;
21
use Romm\Formz\Form\Definition\Step\Step\Step;
22
use Romm\Formz\Form\FormObject\FormObject;
23
use Romm\Formz\Validation\Validator\Form\AbstractFormValidator;
24
use Romm\Formz\Validation\Validator\Form\DefaultFormValidator;
25
use TYPO3\CMS\Core\SingletonInterface;
26
use TYPO3\CMS\Core\Utility\GeneralUtility;
27
use TYPO3\CMS\Extbase\Configuration\ConfigurationManager;
28
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
29
use TYPO3\CMS\Extbase\Error\Error;
30
use TYPO3\CMS\Extbase\Error\Result;
31
use TYPO3\CMS\Extbase\Mvc\Web\Request;
32
use TYPO3\CMS\Fluid\Core\ViewHelper\ViewHelperVariableContainer;
33
use TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper;
34
35
/**
36
 * This class contains methods that help view helpers to manipulate data and
37
 * know more things concerning the current form state.
38
 *
39
 * It is mainly configured inside the `FormViewHelper`, and used in other
40
 * view helpers.
41
 */
42
class FormViewHelperService implements SingletonInterface
43
{
44
    /**
45
     * @var bool
46
     */
47
    protected $formContext = false;
48
49
    /**
50
     * @var FormObject
51
     */
52
    protected $formObject;
53
54
    /**
55
     * @var Request
56
     */
57
    protected $request;
58
59
    /**
60
     * @var Result
61
     */
62
    protected $result;
63
64
    /**
65
     * Reset every state that can be used by this service.
66
     */
67
    public function resetState()
68
    {
69
        $this->formContext = false;
70
        $this->formObject = null;
71
        $this->request = null;
72
    }
73
74
    /**
75
     * Will activate the form context, changing the result returned by the
76
     * function `formContextExists()`.
77
     *
78
     * @return FormViewHelperService
79
     * @throws DuplicateEntryException
80
     */
81
    public function activateFormContext()
82
    {
83
        if (true === $this->formContext) {
84
            throw DuplicateEntryException::duplicatedFormContext();
85
        }
86
87
        $this->formContext = true;
88
        $this->result = new Result;
89
90
        return $this;
91
    }
92
93
    /**
94
     * Returns `true` if the `FormViewHelper` context exists.
95
     *
96
     * @return bool
97
     */
98
    public function formContextExists()
99
    {
100
        return $this->formContext;
101
    }
102
103
    /**
104
     * Will loop on the submitted form fields and apply behaviours if their
105
     * configuration contains.
106
     */
107
    public function applyBehavioursOnSubmittedForm()
108
    {
109
        if ($this->formObject->formWasSubmitted()) {
110
            $request = $this->request->getOriginalRequest();
111
            $formName = $this->formObject->getName();
112
113
            if ($request
114
                && $request->hasArgument($formName)
115
            ) {
116
                /** @var BehavioursManager $behavioursManager */
117
                $behavioursManager = GeneralUtility::makeInstance(BehavioursManager::class);
118
119
                /** @var array $originalForm */
120
                $originalForm = $request->getArgument($formName);
121
122
                $formProperties = $behavioursManager->applyBehaviourOnPropertiesArray(
123
                    $originalForm,
124
                    $this->formObject->getDefinition()
125
                );
126
127
                $request->setArgument($formName, $formProperties);
128
            }
129
        }
130
    }
131
132
    /**
133
     * Takes care of injecting data for the form.
134
     *
135
     * If the form was generated using a content object, information about it
136
     * are injected, to be retrieved later to be able for instance to fetch the
137
     * object settings (TypoScript, FlexForm, ...).
138
     */
139
    public function injectFormRequestData()
140
    {
141
        if (false === $this->formObject->hasForm()) {
142
            return;
143
        }
144
145
        $requestData = $this->formObject->getRequestData();
146
147
        $currentStepIdentifier = $this->getCurrentStep()
148
            ? $this->getCurrentStep()->getIdentifier()
149
            : null;
150
        $requestData->setCurrentStepIdentifier($currentStepIdentifier);
151
152
        /** @var ConfigurationManager $configurationManager */
153
        $configurationManager = Core::instantiate(ConfigurationManagerInterface::class);
154
155
        $contentObject = $configurationManager->getContentObject();
156
157
        if (null !== $contentObject) {
158
            $requestData->setContentObjectTable($contentObject->getCurrentTable());
159
            $requestData->setContentObjectUid($contentObject->data['uid']);
160
        }
161
    }
162
163
    /**
164
     * Fetches all data attributes that are bound to the form: fields values,
165
     * validation result and others.
166
     *
167
     * @param DataAttributesAssetHandler $dataAttributesAssetHandler
168
     * @return array
169
     */
170
    public function getDataAttributes(DataAttributesAssetHandler $dataAttributesAssetHandler)
171
    {
172
        $dataAttributes = [];
173
174
        if ($this->formObject->hasForm()) {
175
            /*
176
             * Getting the data attributes for the form values. It is needed to
177
             * have a validation result because a field can be deactivated (in
178
             * that case, the data attribute for this field is removed).
179
             */
180
            if (false === $this->formObject->formWasValidated()) {
181
                $formResult = $this->getFormValidationResult();
182
            } else {
183
                $formResult = $this->formObject->getFormResult();
184
            }
185
186
            $dataAttributes += $dataAttributesAssetHandler->getFieldsValuesDataAttributes($formResult);
187
        }
188
189
        if (true === $this->formObject->formWasSubmitted()) {
190
            $dataAttributes += $dataAttributesAssetHandler->getFieldSubmissionDoneDataAttribute();
191
        }
192
193
        if (true === $this->formObject->formWasValidated()) {
194
            $dataAttributes += $dataAttributesAssetHandler->getFieldsValidDataAttributes();
195
            $dataAttributes += $dataAttributesAssetHandler->getFieldsMessagesDataAttributes();
196
        }
197
198
        return $dataAttributes;
199
    }
200
201
    /**
202
     * Checks if the form uses steps, in which case the current step is needed
203
     * in order to display the form. If the step is not found, an exception is
204
     * thrown.
205
     */
206
    public function checkStepDefinition()
207
    {
208
        if ($this->formObject->getDefinition()->hasSteps()
209
            && null === $this->getCurrentStep()
210
        ) {
211
            throw new \Exception('todo'); // @todo
212
        }
213
    }
214
215
    /**
216
     * Will check all the fields that have been added below the form view
217
     * helper: each field that is found in the form definition and is *not*
218
     * supported by the current step will add an error and cancel the form
219
     * rendering.
220
     *
221
     * @param ViewHelperVariableContainer $variableContainer
222
     */
223
    public function checkStepFields(ViewHelperVariableContainer $variableContainer)
224
    {
225
        $currentStep = $this->getCurrentStep();
226
227
        if (null === $currentStep) {
228
            return;
229
        }
230
231
        $unsupportedFieldsList = [];
232
        $formDefinition = $this->formObject->getDefinition();
233
        $fieldNames = $this->getCurrentFormFieldNames($variableContainer);
234
235
        foreach ($fieldNames as $fieldName) {
236
            if (false === $formDefinition->hasField($fieldName)) {
237
                continue;
238
            }
239
240
            $field = $formDefinition->getField($fieldName);
241
242
            if (false === $currentStep->supportsField($field)) {
243
                $unsupportedFieldsList[] = $fieldName;
244
            }
245
        }
246
247
        if ($unsupportedFieldsList) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $unsupportedFieldsList of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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.

Loading history...
248
            $error = new Error(
249
                '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.',
250
                1494430935,
251
                [$currentStep->getIdentifier(), implode('", "', $unsupportedFieldsList)]
252
            );
253
            $this->result->addError($error);
254
        }
255
    }
256
257
    /**
258
     * Returns the list of fields that have been added below the form view
259
     * helper.
260
     *
261
     * @param ViewHelperVariableContainer $variableContainer
262
     * @return array
263
     */
264
    public function getCurrentFormFieldNames(ViewHelperVariableContainer $variableContainer)
265
    {
266
        $formFieldNames = $variableContainer->get(FormViewHelper::class, 'formFieldNames');
267
        $cleanFormFieldNames = [];
268
269
        foreach ($formFieldNames as $fieldName) {
270
            $explode = explode('[', $fieldName);
271
272
            if (count($explode) >= 3) {
273
                $formName = rtrim($explode[1], ']');
274
                $fieldName = rtrim($explode[2], ']');
275
276
                if ($formName === $this->formObject->getName()
277
                    && $fieldName !== '__identity'
278
                ) {
279
                    $cleanFormFieldNames[$fieldName] = $fieldName;
280
                }
281
            }
282
        }
283
284
        return $cleanFormFieldNames;
285
    }
286
287
    /**
288
     * @return Step|null
289
     */
290
    public function getCurrentStep()
291
    {
292
        return $this->formObject->fetchCurrentStep($this->request)->getCurrentStep();
293
    }
294
295
    /**
296
     * @return FormObject
297
     */
298
    public function getFormObject()
299
    {
300
        return $this->formObject;
301
    }
302
303
    /**
304
     * @param FormObject $formObject
305
     */
306
    public function setFormObject(FormObject $formObject)
307
    {
308
        $this->formObject = $formObject;
309
    }
310
311
    /**
312
     * @param Request $request
313
     */
314
    public function setRequest(Request $request)
315
    {
316
        $this->request = $request;
317
    }
318
319
    /**
320
     * @return Result
321
     */
322
    public function getResult()
323
    {
324
        return $this->result;
325
    }
326
327
    /**
328
     * @return FormResult
329
     */
330
    protected function getFormValidationResult()
331
    {
332
        $formValidator = $this->getFormValidator($this->formObject->getName());
333
334
        return $formValidator->validate($this->formObject->getForm());
335
    }
336
337
    /**
338
     * @param string $formName
339
     * @return AbstractFormValidator
340
     */
341
    protected function getFormValidator($formName)
342
    {
343
        /** @var AbstractFormValidator $validator */
344
        $validator = Core::instantiate(
345
            DefaultFormValidator::class,
346
            [
347
                'name'  => $formName,
348
                'dummy' => true
349
            ]
350
        );
351
352
        return $validator;
353
    }
354
}
355