Completed
Push — wip/steps ( d97a08...f0546c )
by Romain
03:30
created

StepMiddlewareService::getFormRawValues()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 10
nc 3
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\Middleware\Item\Step\Service;
15
16
use Romm\Formz\Condition\Processor\ConditionProcessorFactory;
17
use Romm\Formz\Condition\Processor\DataObject\PhpConditionDataObject;
18
use Romm\Formz\Exceptions\InvalidArgumentTypeException;
19
use Romm\Formz\Form\Definition\Step\Step\Step;
20
use Romm\Formz\Form\Definition\Step\Step\StepDefinition;
21
use Romm\Formz\Form\FormObject\FormObject;
22
use Romm\Formz\Form\FormObject\FormObjectFactory;
23
use Romm\Formz\Form\FormObject\Service\Step\FormStepPersistence;
24
use Romm\Formz\Middleware\Request\Redirect;
25
use Romm\Formz\Service\Traits\SelfInstantiateTrait;
26
use Romm\Formz\Validation\Validator\Form\DataObject\FormValidatorDataObject;
27
use Romm\Formz\Validation\Validator\Form\FormValidatorExecutor;
28
use TYPO3\CMS\Core\SingletonInterface;
29
use TYPO3\CMS\Core\Utility\GeneralUtility;
30
use TYPO3\CMS\Extbase\Mvc\Web\Request;
31
32
/**
33
 * This service allows extended form steps manipulation.
34
 */
35
class StepMiddlewareService implements SingletonInterface
36
{
37
    use SelfInstantiateTrait;
38
39
    /**
40
     * @var FormObject
41
     */
42
    protected $formObject;
43
44
    /**
45
     * @var Request
46
     */
47
    protected $request;
48
49
    /**
50
     * @var StepMiddlewareValidationService
51
     */
52
    protected $validationService;
53
54
    /**
55
     * @var FormStepPersistence
56
     */
57
    protected $persistence;
58
59
    /**
60
     * @param FormObject $formObject
61
     * @param Request $request
62
     */
63
    public function reset(FormObject $formObject, Request $request)
64
    {
65
        $this->formObject = $formObject;
66
        $this->request = $request;
67
68
        $this->persistence = FormObjectFactory::get()->getStepService($formObject)->getStepPersistence();
69
70
        $this->validationService = GeneralUtility::makeInstance(StepMiddlewareValidationService::class, $this);
71
    }
72
73
    public function redirectToNextStep(Step $currentStep, Redirect $redirect)
74
    {
75
        /*
76
         * The form was submitted, and no error was found, we can safely
77
         * dispatch the request to the next step.
78
         */
79
        $currentStepDefinition = $this->getStepDefinition($currentStep);
80
81
        // Saving submitted form data for further usage.
82
        $this->markStepAsValidated($currentStepDefinition, $this->getFormRawValues());
0 ignored issues
show
Bug introduced by
It seems like $currentStepDefinition defined by $this->getStepDefinition($currentStep) on line 79 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...
83
        $this->addValidatedFields($this->formObject->getFormResult()->getValidatedFields());
84
85
        $nextStep = null;
86
87
        if ($currentStepDefinition->hasNextStep()) {
88
            $nextStep = $this->getNextStepDefinition($currentStepDefinition, true);
0 ignored issues
show
Bug introduced by
It seems like $currentStepDefinition defined by $this->getStepDefinition($currentStep) on line 79 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...
89
        }
90
91
        if ($nextStep) {
92
            $this->moveForwardToStep($nextStep, $redirect);
93
        }
94
    }
95
96
    /**
97
     * Fetches the raw values sent in the request.
98
     *
99
     * @return array
100
     * @throws InvalidArgumentTypeException
101
     */
102
    protected function getFormRawValues()
103
    {
104
        $formName = $this->getFormObject()->getName();
105
        $formArray = null;
0 ignored issues
show
Unused Code introduced by
$formArray is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
106
107
        if ($this->request->hasArgument($formName)) {
108
            /** @var array $formArray */
109
            $formArray = $this->request->getArgument($formName);
110
111
            if (false === is_array($formArray)) {
112
                throw InvalidArgumentTypeException::formArgumentNotArray($this->getFormObject(), $formArray);
113
            }
114
        } else {
115
            $formArray = [];
116
        }
117
118
        return $formArray;
119
    }
120
121
    /**
122
     * @see \Romm\Formz\Middleware\Item\Step\Service\StepMiddlewareValidationService::markStepAsValidated
123
     *
124
     * @param StepDefinition $stepDefinition
125
     * @param array          $formValues
126
     */
127
    public function markStepAsValidated(StepDefinition $stepDefinition, array $formValues)
128
    {
129
        $this->validationService->markStepAsValidated($stepDefinition, $formValues);
130
    }
131
132
    /**
133
     * @see \Romm\Formz\Middleware\Item\Step\Service\StepMiddlewareValidationService::addValidatedFields
134
     *
135
     * @param array $validatedFields
136
     */
137
    public function addValidatedFields(array $validatedFields)
138
    {
139
        $this->validationService->addValidatedFields($validatedFields);
140
    }
141
142
    /**
143
     * @see \Romm\Formz\Middleware\Item\Step\Service\StepMiddlewareValidationService::stepDefinitionIsValid
144
     *
145
     * @param StepDefinition $stepDefinition
146
     * @return bool
147
     */
148
    public function stepIsValid(StepDefinition $stepDefinition)
149
    {
150
        return $this->validationService->stepDefinitionIsValid($stepDefinition);
151
    }
152
153
    /**
154
     * @see \Romm\Formz\Middleware\Item\Step\Service\StepMiddlewareValidationService::getFirstInvalidStep
155
     *
156
     * @param Step $step
157
     * @return StepDefinition|null
158
     */
159
    public function getFirstInvalidStep(Step $step)
160
    {
161
        return $this->validationService->getFirstInvalidStep($step);
162
    }
163
164
    /**
165
     * @param StepDefinition $step
166
     * @param bool           $removeConditionalSteps
167
     * @return StepDefinition
168
     */
169
    public function getNextStepDefinition(StepDefinition $step, $removeConditionalSteps = false)
170
    {
171
        $nextStep = null;
172
173
        if ($step->hasDivergence()) {
174
            $divergenceSteps = $step->getDivergenceSteps();
175
176
            foreach ($divergenceSteps as $divergenceStep) {
177
                if (true === $this->getStepDefinitionConditionResult($divergenceStep)) {
178
                    $nextStep = $divergenceStep;
179
                    break;
180
                }
181
            }
182
        }
183
184
        if (null === $nextStep) {
185
            while ($step->hasNextStep()) {
186
                $step = $step->getNextStep();
187
188
                if ($step->hasActivation()) {
189
                    if (true === $this->getStepDefinitionConditionResult($step)) {
190
                        $nextStep = $step;
191
                        break;
192
                    } elseif (true === $removeConditionalSteps) {
193
                        $this->persistence->removeStep($step);
194
                    }
195
                } else {
196
                    $nextStep = $step;
197
                    break;
198
                }
199
            }
200
        }
201
202
        return $nextStep;
203
    }
204
205
    /**
206
     * @param StepDefinition $stepDefinition
207
     * @param Redirect       $redirect
208
     */
209
    public function moveForwardToStep(StepDefinition $stepDefinition, Redirect $redirect)
210
    {
211
        $this->persistence->setStepLevel($stepDefinition);
212
        $this->redirectToStep($stepDefinition->getStep(), $redirect);
213
    }
214
215
    /**
216
     * Redirects the current request to the given step.
217
     *
218
     * @param Step     $step
219
     * @param Redirect $redirect
220
     */
221
    public function redirectToStep(Step $step, Redirect $redirect)
222
    {
223
        $redirect->toPage($step->getPageUid())
224
            ->toExtension($step->getExtension())
225
            ->toController($step->getController())
226
            ->toAction($step->getAction())
227
            ->withArguments([
228
                'fz-hash' => [
229
                    $this->formObject->getName() => $this->formObject->getFormHash()
230
                ]
231
            ])
232
            ->dispatch();
233
    }
234
235
    /**
236
     * @param StepDefinition $stepDefinition
237
     * @return bool
238
     */
239
    public function getStepDefinitionConditionResult(StepDefinition $stepDefinition)
240
    {
241
        $conditionProcessor = ConditionProcessorFactory::getInstance()->get($this->getFormObject());
242
        $tree = $conditionProcessor->getActivationConditionTreeForStep($stepDefinition);
243
        $todo = new FormValidatorExecutor($this->getFormObject(), new FormValidatorDataObject()); // @todo
244
        $dataObject = new PhpConditionDataObject($this->getFormObject()->getForm(), $todo);
245
246
        return $tree->getPhpResult($dataObject);
247
    }
248
249
    /**
250
     * @param Step $step
251
     * @return StepDefinition|null
252
     */
253
    public function getStepDefinition(Step $step)
254
    {
255
        return $this->findStepDefinition($step, $this->getFirstStepDefinition());
256
    }
257
258
    /**
259
     * @param Step           $step
260
     * @param StepDefinition $stepDefinition
261
     * @return StepDefinition|null
262
     */
263
    protected function findStepDefinition(Step $step, StepDefinition $stepDefinition)
264
    {
265
        if ($stepDefinition->getStep() === $step) {
266
            return $stepDefinition;
267
        }
268
269
        if ($stepDefinition->hasNextStep()) {
270
            $result = $this->findStepDefinition($step, $stepDefinition->getNextStep());
271
272
            if ($result instanceof StepDefinition) {
273
                return $result;
274
            }
275
        }
276
277
        if ($stepDefinition->hasDivergence()) {
278
            foreach ($stepDefinition->getDivergenceSteps() as $divergenceStep) {
279
                $result = $this->findStepDefinition($step, $divergenceStep);
280
281
                if ($result instanceof StepDefinition) {
282
                    return $result;
283
                }
284
            }
285
        }
286
287
        return null;
288
    }
289
290
    /**
291
     * @return FormStepPersistence
292
     */
293
    public function getStepPersistence()
294
    {
295
        return $this->persistence;
296
    }
297
298
    /**
299
     * @return FormObject
300
     */
301
    public function getFormObject()
302
    {
303
        return $this->formObject;
304
    }
305
306
    /**
307
     * @return StepDefinition
308
     */
309
    public function getFirstStepDefinition()
310
    {
311
        return $this->formObject->getDefinition()->getSteps()->getFirstStepDefinition();
312
    }
313
}
314