FormValidatorExecutor   B
last analyzed

Complexity

Total Complexity 44

Size/Duplication

Total Lines 354
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 18

Importance

Changes 0
Metric Value
wmc 44
lcom 1
cbo 18
dl 0
loc 354
rs 8.8798
c 0
b 0
f 0

21 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A applyBehaviours() 0 8 1
A checkFieldsActivation() 0 10 3
A checkFieldActivation() 0 22 5
A checkFieldValidationActivation() 0 10 4
A validateFields() 0 14 4
B validateField() 0 24 6
A processFieldValidation() 0 33 4
A getResult() 0 4 1
A getFieldActivationProcessResult() 0 6 1
A getValidationActivationProcessResult() 0 6 1
A fieldActivationHasBeenChecked() 0 4 1
A markFieldActivationAsChecked() 0 4 1
A fieldActivationIsBeingChecked() 0 4 1
A markFieldActivationCheckBegin() 0 4 1
A markFieldActivationCheckEnd() 0 4 1
A fieldWasValidated() 0 4 1
A markFieldAsValidated() 0 4 1
A getFormObject() 0 11 2
A getConditionProcessor() 0 8 2
A getPhpConditionDataObject() 0 8 2

How to fix   Complexity   

Complex Class

Complex classes like FormValidatorExecutor often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FormValidatorExecutor, and based on these observations, apply Extract Interface, too.

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\Validation\Validator\Form;
15
16
use Romm\Formz\Behaviours\BehavioursManager;
17
use Romm\Formz\Condition\Processor\ConditionProcessor;
18
use Romm\Formz\Condition\Processor\ConditionProcessorFactory;
19
use Romm\Formz\Condition\Processor\DataObject\PhpConditionDataObject;
20
use Romm\Formz\Configuration\Form\Field\Field;
21
use Romm\Formz\Configuration\Form\Field\Validation\Validation;
22
use Romm\Formz\Core\Core;
23
use Romm\Formz\Error\FormResult;
24
use Romm\Formz\Form\FormInterface;
25
use Romm\Formz\Form\FormObject;
26
use Romm\Formz\Form\FormObjectFactory;
27
use Romm\Formz\Service\MessageService;
28
use Romm\Formz\Validation\DataObject\ValidatorDataObject;
29
use Romm\Formz\Validation\Validator\AbstractValidator;
30
use TYPO3\CMS\Core\Utility\GeneralUtility;
31
use TYPO3\CMS\Extbase\Error\Result;
32
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
33
use TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface;
34
35
class FormValidatorExecutor
36
{
37
    /**
38
     * @var FormInterface
39
     */
40
    protected $form;
41
42
    /**
43
     * @var string
44
     */
45
    protected $formName;
46
47
    /**
48
     * @var FormResult
49
     */
50
    protected $result;
51
52
    /**
53
     * @var FormObject
54
     */
55
    private $formObject;
56
57
    /**
58
     * @var ConditionProcessor
59
     */
60
    private $conditionProcessor;
61
62
    /**
63
     * @var array
64
     */
65
    protected $fieldsActivationChecked = [];
66
67
    /**
68
     * Current queue, used to prevent infinite loop.
69
     *
70
     * @var array
71
     */
72
    protected $fieldsActivationChecking = [];
73
74
    /**
75
     * @var array
76
     */
77
    protected $fieldsValidated = [];
78
79
    /**
80
     * Array of arbitral data which are handled by validators.
81
     *
82
     * @var array
83
     */
84
    protected $validationData = [];
85
86
    /**
87
     * @var PhpConditionDataObject
88
     */
89
    protected $phpConditionDataObject;
90
91
    /**
92
     * @param FormInterface $form
93
     * @param string        $formName
94
     * @param FormResult    $result
95
     */
96
    public function __construct(FormInterface $form, $formName, FormResult $result)
97
    {
98
        $this->form = $form;
99
        $this->formName = $formName;
100
        $this->result = $result;
101
    }
102
103
    /**
104
     * @return FormValidatorExecutor
105
     */
106
    public function applyBehaviours()
107
    {
108
        /** @var BehavioursManager $behavioursManager */
109
        $behavioursManager = GeneralUtility::makeInstance(BehavioursManager::class);
110
        $behavioursManager->applyBehaviourOnFormInstance($this->getFormObject());
111
112
        return $this;
113
    }
114
115
    /**
116
     * This function will take care of deactivating the validation for fields
117
     * that do not match their activation condition.
118
     *
119
     * @return FormValidatorExecutor
120
     */
121
    public function checkFieldsActivation()
122
    {
123
        foreach ($this->getFormObject()->getConfiguration()->getFields() as $field) {
124
            if (false === $this->result->fieldIsDeactivated($field)) {
125
                $this->checkFieldActivation($field);
126
            }
127
        }
128
129
        return $this;
130
    }
131
132
    /**
133
     * @param Field $field
134
     */
135
    protected function checkFieldActivation(Field $field)
136
    {
137
        // Prevents loop checking.
138
        if ($this->fieldActivationIsBeingChecked($field)
139
            || $this->fieldActivationHasBeenChecked($field)
140
        ) {
141
            return;
142
        }
143
144
        $this->markFieldActivationCheckBegin($field);
145
146
        if (true === $field->hasActivation()
147
            && false === $this->getFieldActivationProcessResult($field)
148
        ) {
149
            $this->result->deactivateField($field);
150
        }
151
152
        $this->checkFieldValidationActivation($field);
153
154
        $this->markFieldActivationAsChecked($field);
155
        $this->markFieldActivationCheckEnd($field);
156
    }
157
158
    /**
159
     * @param Field $field
160
     */
161
    protected function checkFieldValidationActivation(Field $field)
162
    {
163
        foreach ($field->getValidation() as $validation) {
164
            if (true === $validation->hasActivation()
165
                && false === $this->getValidationActivationProcessResult($validation)
166
            ) {
167
                $this->result->deactivateValidation($validation);
168
            }
169
        }
170
    }
171
172
    /**
173
     * @param callable $callback
174
     * @return FormValidatorExecutor
175
     */
176
    public function validateFields(callable $callback = null)
177
    {
178
        foreach ($this->getFormObject()->getConfiguration()->getFields() as $field) {
179
            $this->validateField($field);
180
181
            if ($this->fieldWasValidated($field)
182
                && $callback
183
            ) {
184
                call_user_func($callback, $field);
185
            }
186
        }
187
188
        return $this;
189
    }
190
191
    /**
192
     * Will loop on each validation rule and apply it of the field.
193
     * Errors are stored in `$this->result`.
194
     *
195
     * @param Field $field
196
     */
197
    public function validateField(Field $field)
198
    {
199
        if (false === $this->fieldWasValidated($field)) {
200
            $this->checkFieldActivation($field);
201
202
            if (false === $this->result->fieldIsDeactivated($field)) {
203
                $this->markFieldAsValidated($field);
204
205
                // Looping on the field's validation settings...
206
                foreach ($field->getValidation() as $validation) {
207
                    if ($this->result->validationIsDeactivated($validation)) {
208
                        continue;
209
                    }
210
211
                    $validatorResult = $this->processFieldValidation($field, $validation);
212
213
                    // Breaking the loop if an error occurred: we stop the validation process for the current field.
214
                    if ($validatorResult->hasErrors()) {
215
                        break;
216
                    }
217
                }
218
            }
219
        }
220
    }
221
222
    /**
223
     * @param Field      $field
224
     * @param Validation $validation
225
     * @return Result
226
     */
227
    protected function processFieldValidation(Field $field, Validation $validation)
228
    {
229
        $fieldName = $field->getName();
230
        $fieldValue = ObjectAccess::getProperty($this->form, $fieldName);
231
        $validatorDataObject = new ValidatorDataObject($this->getFormObject(), $validation);
232
233
        /** @var ValidatorInterface $validator */
234
        $validator = Core::instantiate(
235
            $validation->getClassName(),
236
            $validation->getOptions(),
237
            $validatorDataObject
238
        );
239
240
        $validatorResult = $validator->validate($fieldValue);
241
        $validatorResult = MessageService::get()->sanitizeValidatorResult($validatorResult, $validation->getName());
242
243
        if ($validator instanceof AbstractValidator
244
            && false === empty($validationData = $validator->getValidationData())
245
        ) {
246
            $this->validationData[$fieldName] = ($this->validationData[$fieldName]) ?: [];
247
            $this->validationData[$fieldName] = array_merge(
248
                $this->validationData[$fieldName],
249
                $validationData
250
            );
251
252
            $this->form->setValidationData($this->validationData);
0 ignored issues
show
Deprecated Code introduced by
The method Romm\Formz\Form\FormInterface::setValidationData() has been deprecated with message: This method is deprecated and will be deleted in FormZ v2.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
253
        }
254
255
        $this->result->forProperty($fieldName)->merge($validatorResult);
256
        unset($validatorDataObject);
257
258
        return $validatorResult;
259
    }
260
261
    /**
262
     * @return FormResult
263
     */
264
    public function getResult()
265
    {
266
        return $this->result;
267
    }
268
269
    /**
270
     * @param Field $field
271
     * @return bool
272
     */
273
    protected function getFieldActivationProcessResult(Field $field)
274
    {
275
        return $this->getConditionProcessor()
276
            ->getActivationConditionTreeForField($field)
277
            ->getPhpResult($this->getPhpConditionDataObject());
278
    }
279
280
    /**
281
     * @param Validation $validation
282
     * @return bool
283
     */
284
    protected function getValidationActivationProcessResult(Validation $validation)
285
    {
286
        return $this->getConditionProcessor()
287
            ->getActivationConditionTreeForValidation($validation)
288
            ->getPhpResult($this->getPhpConditionDataObject());
289
    }
290
291
    /**
292
     * @param Field $field
293
     * @return bool
294
     */
295
    protected function fieldActivationHasBeenChecked(Field $field)
296
    {
297
        return in_array($field->getName(), $this->fieldsActivationChecked);
298
    }
299
300
    /**
301
     * @param Field $field
302
     */
303
    protected function markFieldActivationAsChecked(Field $field)
304
    {
305
        $this->fieldsActivationChecked[] = $field->getName();
306
    }
307
308
    /**
309
     * @param Field $field
310
     * @return bool
311
     */
312
    protected function fieldActivationIsBeingChecked(Field $field)
313
    {
314
        return isset($this->fieldsActivationChecking[$field->getName()]);
315
    }
316
317
    /**
318
     * @param Field $field
319
     */
320
    protected function markFieldActivationCheckBegin(Field $field)
321
    {
322
        $this->fieldsActivationChecking[$field->getName()] = true;
323
    }
324
325
    /**
326
     * @param Field $field
327
     */
328
    protected function markFieldActivationCheckEnd(Field $field)
329
    {
330
        unset($this->fieldsActivationChecking[$field->getName()]);
331
    }
332
333
    /**
334
     * @param Field $field
335
     * @return bool
336
     */
337
    protected function fieldWasValidated(Field $field)
338
    {
339
        return in_array($field->getName(), $this->fieldsValidated);
340
    }
341
342
    /**
343
     * @param Field $field
344
     */
345
    protected function markFieldAsValidated(Field $field)
346
    {
347
        $this->fieldsValidated[] = $field->getName();
348
    }
349
350
    /**
351
     * @return FormObject
352
     */
353
    public function getFormObject()
354
    {
355
        if (null === $this->formObject) {
356
            /** @var FormObjectFactory $formObjectFactory */
357
            $formObjectFactory = Core::instantiate(FormObjectFactory::class);
358
359
            $this->formObject = $formObjectFactory->getInstanceFromFormInstance($this->form, $this->formName);
360
        }
361
362
        return $this->formObject;
363
    }
364
365
    /**
366
     * @return ConditionProcessor
367
     */
368
    protected function getConditionProcessor()
369
    {
370
        if (null === $this->conditionProcessor) {
371
            $this->conditionProcessor = ConditionProcessorFactory::getInstance()->get($this->getFormObject());
372
        }
373
374
        return $this->conditionProcessor;
375
    }
376
377
    /**
378
     * @return PhpConditionDataObject
379
     */
380
    protected function getPhpConditionDataObject()
381
    {
382
        if (null === $this->phpConditionDataObject) {
383
            $this->phpConditionDataObject = new PhpConditionDataObject($this->form, $this);
384
        }
385
386
        return $this->phpConditionDataObject;
387
    }
388
}
389