Completed
Push — wip/steps ( a4f896...83acbb )
by Romain
06:13
created

StepMiddlewareService   C

Complexity

Total Complexity 35

Size/Duplication

Total Lines 333
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 18

Importance

Changes 0
Metric Value
wmc 35
lcom 1
cbo 18
dl 0
loc 333
rs 6.6
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
A reset() 0 9 1
B getNextStep() 0 24 3
A addValidatedFields() 0 4 1
A stepIsValid() 0 4 1
A getFirstInvalidStep() 0 4 1
C getNextStepDefinition() 0 35 8
C getNextSubstepDefinition() 0 33 8
A findSubstepDefinition() 0 4 1
A findSubstepDefinitionRecursive() 0 14 3
A moveForwardToStep() 0 5 1
A redirectToStep() 0 13 1
A getStepDefinitionConditionResult() 0 9 1
A getSubstepDefinitionConditionResult() 0 9 1
A getStepDefinition() 0 6 1
A getStepPersistence() 0 4 1
A getFormObject() 0 4 1
A getFirstStepDefinition() 0 4 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\Middleware\Item\Step\Service;
15
16
use Romm\Formz\Condition\Processor\ConditionProcessorFactory;
17
use Romm\Formz\Condition\Processor\DataObject\PhpConditionDataObject;
18
use Romm\Formz\Error\FormResult;
19
use Romm\Formz\Form\Definition\Step\Step\Step;
20
use Romm\Formz\Form\Definition\Step\Step\StepDefinition;
21
use Romm\Formz\Form\Definition\Step\Step\Substep\SubstepDefinition;
22
use Romm\Formz\Form\FormObject\FormObject;
23
use Romm\Formz\Form\FormObject\FormObjectFactory;
24
use Romm\Formz\Form\FormObject\Service\Step\FormStepPersistence;
25
use Romm\Formz\Middleware\Request\Redirect;
26
use Romm\Formz\Service\Traits\SelfInstantiateTrait;
27
use Romm\Formz\Validation\Form\DataObject\FormValidatorDataObject;
28
use Romm\Formz\Validation\Form\FormValidatorExecutor;
29
use TYPO3\CMS\Core\SingletonInterface;
30
use TYPO3\CMS\Core\Utility\GeneralUtility;
31
use TYPO3\CMS\Extbase\Mvc\Web\Request;
32
33
/**
34
 * This service allows extended form steps manipulation.
35
 */
36
class StepMiddlewareService implements SingletonInterface
37
{
38
    use SelfInstantiateTrait;
39
40
    /**
41
     * @var FormObject
42
     */
43
    protected $formObject;
44
45
    /**
46
     * @var Request
47
     */
48
    protected $request;
49
50
    /**
51
     * @var StepMiddlewareValidationService
52
     */
53
    protected $validationService;
54
55
    /**
56
     * @var FormStepPersistence
57
     */
58
    protected $persistence;
59
60
    /**
61
     * @param FormObject $formObject
62
     * @param Request $request
63
     */
64
    public function reset(FormObject $formObject, Request $request)
65
    {
66
        $this->formObject = $formObject;
67
        $this->request = $request;
68
69
        $this->persistence = FormObjectFactory::get()->getStepService($formObject)->getStepPersistence();
70
71
        $this->validationService = GeneralUtility::makeInstance(StepMiddlewareValidationService::class, $this);
72
    }
73
74
    /**
75
     * @param Step $currentStep
76
     * @return StepDefinition|null
77
     */
78
    public function getNextStep(Step $currentStep)
79
    {
80
        /*
81
         * The form was submitted, and no error was found, we can safely
82
         * dispatch the request to the next step.
83
         */
84
        $currentStepDefinition = $this->getStepDefinition($currentStep);
85
86
        $this->validationService->markStepAsValidated($currentStepDefinition);
0 ignored issues
show
Bug introduced by
It seems like $currentStepDefinition defined by $this->getStepDefinition($currentStep) on line 84 can be null; however, Romm\Formz\Middleware\It...::markStepAsValidated() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
87
        // @todo tmp-delete?
88
//        // Saving submitted form data for further usage.
89
//        $this->markStepAsValidated($currentStepDefinition, $this->getFormRawValues());
90
        $this->addValidatedFields($this->formObject->getFormResult()->getValidatedFields());
91
92
        $nextStep = null;
93
94
        if ($currentStepDefinition->hasNextStep()
95
            || $currentStepDefinition->hasDivergence()
96
        ) {
97
            $nextStep = $this->getNextStepDefinition($currentStepDefinition);
0 ignored issues
show
Bug introduced by
It seems like $currentStepDefinition defined by $this->getStepDefinition($currentStep) on line 84 can be null; however, Romm\Formz\Middleware\It...getNextStepDefinition() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
98
        }
99
100
        return $nextStep;
101
    }
102
103
    // @todo tmp-delete?
104
//    /**
105
//     * Saves the submitted values in the metadata, for the given step.
106
//     *
107
//     * @param Step $currentStep
108
//     */
109
//    public function saveStepFormValues(Step $currentStep)
110
//    {
111
//        $this->persistence->addStepFormValues($this->getStepDefinition($currentStep), $this->getFormRawValues());
112
//    }
113
//
114
//    /**
115
//     * Fetches the raw values sent in the request.
116
//     *
117
//     * @return array
118
//     * @throws InvalidArgumentTypeException
119
//     */
120
//    protected function getFormRawValues()
121
//    {
122
//        $formName = $this->getFormObject()->getName();
123
//        $formArray = null;
124
//
125
//        if ($this->request->hasArgument($formName)) {
126
//            /** @var array $formArray */
127
//            $formArray = $this->request->getArgument($formName);
128
//
129
//            if (false === is_array($formArray)) {
130
//                throw InvalidArgumentTypeException::formArgumentNotArray($this->getFormObject(), $formArray);
131
//            }
132
//        } else {
133
//            $formArray = [];
134
//        }
135
//
136
//        return $formArray;
137
//    }
138
//
139
//    /**
140
//     * @see \Romm\Formz\Middleware\Item\Step\Service\StepMiddlewareValidationService::markStepAsValidated()
141
//     *
142
//     * @param StepDefinition $stepDefinition
143
//     * @param array          $formValues
144
//     */
145
//    public function markStepAsValidated(StepDefinition $stepDefinition, array $formValues)
146
//    {
147
//        $this->validationService->markStepAsValidated($stepDefinition, $formValues);
148
//    }
149
150
    /**
151
     * @see \Romm\Formz\Middleware\Item\Step\Service\StepMiddlewareValidationService::addValidatedFields
152
     *
153
     * @param array $validatedFields
154
     */
155
    public function addValidatedFields(array $validatedFields)
156
    {
157
        $this->validationService->addValidatedFields($validatedFields);
158
    }
159
160
    /**
161
     * @see \Romm\Formz\Middleware\Item\Step\Service\StepMiddlewareValidationService::stepDefinitionIsValid
162
     *
163
     * @param StepDefinition $stepDefinition
164
     * @return bool
165
     */
166
    public function stepIsValid(StepDefinition $stepDefinition)
167
    {
168
        return $this->validationService->stepDefinitionIsValid($stepDefinition);
169
    }
170
171
    /**
172
     * @see \Romm\Formz\Middleware\Item\Step\Service\StepMiddlewareValidationService::getFirstInvalidStep
173
     *
174
     * @param Step $step
175
     * @return StepDefinition|null
176
     */
177
    public function getFirstInvalidStep(Step $step)
178
    {
179
        return $this->validationService->getFirstInvalidStep($step);
180
    }
181
182
    /**
183
     * @param StepDefinition $step
184
     * @return StepDefinition
185
     */
186
    public function getNextStepDefinition(StepDefinition $step)
187
    {
188
        $nextStep = null;
189
190
        if ($step->hasDivergence()) {
191
            $divergenceSteps = $step->getDivergenceSteps();
192
193
            foreach ($divergenceSteps as $divergenceStep) {
194
                if (true === $this->getStepDefinitionConditionResult($divergenceStep)) {
195
                    $nextStep = $divergenceStep;
196
                    break;
197
                }
198
            }
199
        }
200
201
        if (null === $nextStep) {
202
            while ($step->hasNextStep()) {
203
                $step = $step->getNextStep();
204
205
                if ($step->hasActivation()) {
206
                    if (true === $this->getStepDefinitionConditionResult($step)) {
207
                        $nextStep = $step;
208
                        break;
209
                    } else {
210
                        $this->persistence->removeStep($step);
211
                    }
212
                } else {
213
                    $nextStep = $step;
214
                    break;
215
                }
216
            }
217
        }
218
219
        return $nextStep;
220
    }
221
222
    public function getNextSubstepDefinition(SubstepDefinition $substepDefinition)
223
    {
224
        $nextSubstep = null;
225
226
        if ($substepDefinition->hasDivergence()) {
227
            $divergenceSteps = $substepDefinition->getDivergenceSubsteps();
228
229
            foreach ($divergenceSteps as $divergenceStep) {
230
                if (true === $this->getSubstepDefinitionConditionResult($divergenceStep)) {
231
                    $nextSubstep = $divergenceStep;
232
                    break;
233
                }
234
            }
235
        }
236
237
        if (null === $nextSubstep) {
238
            while ($substepDefinition->hasNextSubstep()) {
239
                $substepDefinition = $substepDefinition->getNextSubstep();
240
241
                if ($substepDefinition->hasActivation()) {
242
                    if (true === $this->getSubstepDefinitionConditionResult($substepDefinition)) {
243
                        $nextSubstep = $substepDefinition;
244
                        break;
245
                    }
246
                } else {
247
                    $nextSubstep = $substepDefinition;
248
                    break;
249
                }
250
            }
251
        }
252
253
        return $nextSubstep;
254
    }
255
256
    public function findSubstepDefinition(Step $step, callable $callback)
257
    {
258
        return $this->findSubstepDefinitionRecursive($step->getSubsteps()->getFirstSubstepDefinition(), $callback);
259
    }
260
261
    protected function findSubstepDefinitionRecursive(SubstepDefinition $substepDefinition, callable $callback)
262
    {
263
        $result = $callback($substepDefinition);
264
265
        if (true === $result) {
266
            return $substepDefinition;
267
        }
268
269
        $substepDefinition = $this->getNextSubstepDefinition($substepDefinition);
270
271
        return $substepDefinition
272
            ? $this->findSubstepDefinitionRecursive($substepDefinition, $callback)
273
            : null;
274
    }
275
276
    /**
277
     * @param StepDefinition $stepDefinition
278
     * @param Redirect       $redirect
279
     */
280
    public function moveForwardToStep(StepDefinition $stepDefinition, Redirect $redirect)
281
    {
282
        $this->persistence->setStepLevel($stepDefinition);
283
        $this->redirectToStep($stepDefinition->getStep(), $redirect);
284
    }
285
286
    /**
287
     * Redirects the current request to the given step.
288
     *
289
     * @param Step     $step
290
     * @param Redirect $redirect
291
     */
292
    public function redirectToStep(Step $step, Redirect $redirect)
293
    {
294
        $redirect->toPage($step->getPageUid())
295
            ->toExtension($step->getExtension())
296
            ->toController($step->getController())
297
            ->toAction($step->getAction())
298
            ->withArguments([
299
                'fz-hash' => [
300
                    $this->formObject->getName() => $this->formObject->getFormHash()
301
                ]
302
            ])
303
            ->dispatch();
304
    }
305
306
    /**
307
     * @param StepDefinition $stepDefinition
308
     * @return bool
309
     */
310
    public function getStepDefinitionConditionResult(StepDefinition $stepDefinition)
311
    {
312
        $conditionProcessor = ConditionProcessorFactory::getInstance()->get($this->getFormObject());
313
        $tree = $conditionProcessor->getActivationConditionTreeForStep($stepDefinition);
314
        $todo = new FormValidatorExecutor(new FormValidatorDataObject($this->getFormObject(), new FormResult(), true)); // @todo
315
        $dataObject = new PhpConditionDataObject($this->getFormObject()->getForm(), $todo);
316
317
        return $tree->getPhpResult($dataObject);
318
    }
319
320
    /**
321
     * @param SubstepDefinition $substepDefinition
322
     * @return bool
323
     */
324
    public function getSubstepDefinitionConditionResult(SubstepDefinition $substepDefinition)
325
    {
326
        $conditionProcessor = ConditionProcessorFactory::getInstance()->get($this->getFormObject());
327
        $tree = $conditionProcessor->getActivationConditionTreeForSubstep($substepDefinition);
328
        $todo = new FormValidatorExecutor(new FormValidatorDataObject($this->getFormObject(), new FormResult(), true)); // @todo
329
        $dataObject = new PhpConditionDataObject($this->getFormObject()->getForm(), $todo);
330
331
        return $tree->getPhpResult($dataObject);
332
    }
333
334
    /**
335
     * @param Step $step
336
     * @return StepDefinition|null
337
     */
338
    public function getStepDefinition(Step $step)
339
    {
340
        return FormObjectFactory::get()
341
            ->getStepService($this->getFormObject())
342
            ->getStepDefinition($step);
343
    }
344
345
    /**
346
     * @return FormStepPersistence
347
     */
348
    public function getStepPersistence()
349
    {
350
        return $this->persistence;
351
    }
352
353
    /**
354
     * @return FormObject
355
     */
356
    public function getFormObject()
357
    {
358
        return $this->formObject;
359
    }
360
361
    /**
362
     * @return StepDefinition
363
     */
364
    public function getFirstStepDefinition()
365
    {
366
        return $this->formObject->getDefinition()->getSteps()->getFirstStepDefinition();
367
    }
368
}
369