Completed
Push — wip/steps ( f858ae...f1ed33 )
by Romain
10:54
created

StepMiddlewareService::getNextStepDefinition()   C

Complexity

Conditions 8
Paths 16

Size

Total Lines 35
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

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