Completed
Push — wip/steps ( 1506fd...4499a9 )
by
unknown
08:43
created

StepMiddlewareService::getFirstNotValidatedStep()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
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\Middleware\Item\Step\Service;
15
16
use Romm\Formz\Condition\Processor\ConditionProcessorFactory;
17
use Romm\Formz\Condition\Processor\DataObject\PhpConditionDataObject;
18
use Romm\Formz\Core\Core;
19
use Romm\Formz\Error\FormResult;
20
use Romm\Formz\Form\Definition\Step\Step\Step;
21
use Romm\Formz\Form\Definition\Step\Step\StepDefinition;
22
use Romm\Formz\Form\Definition\Step\Step\Substep\SubstepDefinition;
23
use Romm\Formz\Form\FormObject\FormObject;
24
use Romm\Formz\Form\FormObject\FormObjectFactory;
25
use Romm\Formz\Form\FormObject\Service\Step\FormStepPersistence;
26
use Romm\Formz\Middleware\Request\Redirect;
27
use Romm\Formz\Service\Traits\SelfInstantiateTrait;
28
use Romm\Formz\Validation\Form\DataObject\FormValidatorDataObject;
29
use Romm\Formz\Validation\Form\FormValidatorExecutor;
30
use TYPO3\CMS\Core\SingletonInterface;
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 = Core::instantiate(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
     * @see \Romm\Formz\Middleware\Item\Step\Service\StepMiddlewareValidationService::getFirstNotValidatedStep
184
     *
185
     * @param StepDefinition $stepDefinition
186
     * @return StepDefinition|null
187
     */
188
    public function getFirstNotValidatedStep(StepDefinition $stepDefinition)
189
    {
190
        return $this->validationService->getFirstNotValidatedStep($stepDefinition);
191
    }
192
193
    /**
194
     * @param StepDefinition $step
195
     * @return StepDefinition
196
     */
197
    public function getNextStepDefinition(StepDefinition $step)
198
    {
199
        $nextStep = null;
200
201
        if ($step->hasDivergence()) {
202
            $divergenceSteps = $step->getDivergenceSteps();
203
204
            foreach ($divergenceSteps as $divergenceStep) {
205
                if (true === $this->getStepDefinitionConditionResult($divergenceStep)) {
206
                    $nextStep = $divergenceStep;
207
                    break;
208
                }
209
            }
210
        }
211
212
        if (null === $nextStep) {
213
            while ($step->hasNextStep()) {
214
                $step = $step->getNextStep();
215
216
                if ($step->hasActivation()) {
217
                    if (true === $this->getStepDefinitionConditionResult($step)) {
218
                        $nextStep = $step;
219
                        break;
220
                    } else {
221
                        $this->persistence->removeStep($step);
222
                    }
223
                } else {
224
                    $nextStep = $step;
225
                    break;
226
                }
227
            }
228
        }
229
230
        return $nextStep;
231
    }
232
233
    public function getNextSubstepDefinition(SubstepDefinition $substepDefinition)
234
    {
235
        $nextSubstep = null;
236
237
        if ($substepDefinition->hasDivergence()) {
238
            $divergenceSteps = $substepDefinition->getDivergenceSubsteps();
239
240
            foreach ($divergenceSteps as $divergenceStep) {
241
                if (true === $this->getSubstepDefinitionConditionResult($divergenceStep)) {
242
                    return $divergenceStep;
243
                }
244
            }
245
        }
246
247
        if (null === $nextSubstep) {
248
            while ($substepDefinition->hasNextSubstep()) {
249
                $substepDefinition = $substepDefinition->getNextSubstep();
250
251
                if ($this->substepIsValid($substepDefinition)) {
252
                    return $substepDefinition;
253
                }
254
            }
255
        }
256
257
        return $nextSubstep;
258
    }
259
260
    public function findSubstepDefinition(Step $step, callable $callback)
261
    {
262
        return $this->findSubstepDefinitionRecursive($step->getSubsteps()->getFirstSubstepDefinition(), $callback);
263
    }
264
265
    /**
266
     * Finds the first valid substep.
267
     *
268
     * @param Step $step
269
     * @return SubstepDefinition|null
270
     */
271
    public function findFirstSubstepDefinition(Step $step)
272
    {
273
        $firstSubstepDefinition = $step->getSubsteps()->getFirstSubstepDefinition();
274
275
        return $this->substepIsValid($firstSubstepDefinition)
276
            ? $firstSubstepDefinition
277
            : $this->getNextSubstepDefinition($firstSubstepDefinition);
278
    }
279
280
    protected function findSubstepDefinitionRecursive(SubstepDefinition $substepDefinition, callable $callback)
281
    {
282
        $result = $callback($substepDefinition);
283
284
        if (true === $result) {
285
            return $substepDefinition;
286
        }
287
288
        $substepDefinition = $this->getNextSubstepDefinition($substepDefinition);
289
290
        return $substepDefinition
291
            ? $this->findSubstepDefinitionRecursive($substepDefinition, $callback)
292
            : null;
293
    }
294
295
    /**
296
     * @param StepDefinition $stepDefinition
297
     * @param Redirect       $redirect
298
     */
299
    public function moveForwardToStep(StepDefinition $stepDefinition, Redirect $redirect)
300
    {
301
        $this->persistence->setStepLevel($stepDefinition);
302
        $this->redirectToStep($stepDefinition->getStep(), $redirect);
303
    }
304
305
    /**
306
     * Redirects the current request to the given step.
307
     *
308
     * @param Step     $step
309
     * @param Redirect $redirect
310
     */
311
    public function redirectToStep(Step $step, Redirect $redirect)
312
    {
313
        $redirect->toPage($step->getPageUid())
314
            ->toExtension($step->getExtension())
315
            ->toController($step->getController())
316
            ->toAction($step->getAction())
317
            ->withArguments([
318
                'fz-hash' => [
319
                    $this->formObject->getName() => $this->formObject->getFormHash()
320
                ]
321
            ])
322
            ->dispatch();
323
    }
324
325
    /**
326
     * @param StepDefinition $stepDefinition
327
     * @return bool
328
     */
329
    public function getStepDefinitionConditionResult(StepDefinition $stepDefinition)
330
    {
331
        $conditionProcessor = ConditionProcessorFactory::getInstance()->get($this->getFormObject());
332
        $tree = $conditionProcessor->getActivationConditionTreeForStep($stepDefinition);
333
        $todo = new FormValidatorExecutor(new FormValidatorDataObject($this->getFormObject(), new FormResult(), true)); // @todo
334
        $dataObject = new PhpConditionDataObject($this->getFormObject()->getForm(), $todo);
335
336
        return $tree->getPhpResult($dataObject);
337
    }
338
339
    /**
340
     * @param SubstepDefinition $substepDefinition
341
     * @return bool
342
     */
343
    public function getSubstepDefinitionConditionResult(SubstepDefinition $substepDefinition)
344
    {
345
        $conditionProcessor = ConditionProcessorFactory::getInstance()->get($this->getFormObject());
346
        $tree = $conditionProcessor->getActivationConditionTreeForSubstep($substepDefinition);
347
        $todo = new FormValidatorExecutor(new FormValidatorDataObject($this->getFormObject(), new FormResult(), true)); // @todo
348
        $dataObject = new PhpConditionDataObject($this->getFormObject()->getForm(), $todo);
349
350
        return $tree->getPhpResult($dataObject);
351
    }
352
353
    private function substepIsValid(SubstepDefinition $substepDefinition)
354
    {
355
        if ($substepDefinition->hasActivation()) {
356
            return $this->getSubstepDefinitionConditionResult($substepDefinition);
357
        }
358
359
        return true;
360
    }
361
362
    /**
363
     * @param Step $step
364
     * @return StepDefinition|null
365
     */
366
    public function getStepDefinition(Step $step)
367
    {
368
        return FormObjectFactory::get()
369
            ->getStepService($this->getFormObject())
370
            ->getStepDefinition($step);
371
    }
372
373
    /**
374
     * @return FormStepPersistence
375
     */
376
    public function getStepPersistence()
377
    {
378
        return $this->persistence;
379
    }
380
381
    /**
382
     * @return FormObject
383
     */
384
    public function getFormObject()
385
    {
386
        return $this->formObject;
387
    }
388
389
    /**
390
     * @return StepDefinition
391
     */
392
    public function getFirstStepDefinition()
393
    {
394
        return $this->formObject->getDefinition()->getSteps()->getFirstStepDefinition();
395
    }
396
}
397