Completed
Push — middleware-wip ( f76eb7...e5756f )
by Romain
07:43
created

FormViewHelperService::checkStepDefinition()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 4
nc 2
nop 0
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) {
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...
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