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

FormObjectSteps::findStepDefinition()   C

Complexity

Conditions 7
Paths 8

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 13
nc 8
nop 2
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\Form\FormObject\Service;
15
16
use Romm\Formz\Form\Definition\Step\Step\Step;
17
use Romm\Formz\Form\Definition\Step\Step\StepDefinition;
18
use Romm\Formz\Form\Definition\Step\Step\Substep\SubstepDefinition;
19
use Romm\Formz\Form\FormObject\FormObject;
20
use Romm\Formz\Form\FormObject\Service\Step\FormStepPersistence;
21
use TYPO3\CMS\Core\Utility\GeneralUtility;
22
23
class FormObjectSteps
24
{
25
    const METADATA_STEP_PERSISTENCE_KEY = 'core.formStepPersistence';
26
27
    /**
28
     * @var FormObject
29
     */
30
    protected $formObject;
31
32
    /**
33
     * Step persistence is saved in the form metadata.
34
     *
35
     * It allows having essential information about the form steps whenever it
36
     * is needed: submitted form values, as well as steps that were already
37
     * validated.
38
     *
39
     * @var FormStepPersistence
40
     */
41
    protected $stepPersistence;
42
43
    /**
44
     * @var Step
45
     */
46
    protected $currentStep;
47
48
    /**
49
     * @todo ADD REQUEST CONTEXT INSIDE THE FORM OBJECT ?!
50
     *
51
     * @var string
52
     */
53
    protected $currentHash;
54
55
    /**
56
     * @var SubstepDefinition
57
     */
58
    protected $currentSubstepDefinition;
59
60
    /**
61
     * @var int
62
     */
63
    protected $substepsLevel = 1;
64
65
    /**
66
     * @var bool
67
     */
68
    protected $lastSubstepValidated = false;
69
70
    /**
71
     * @param FormObject $formObject
72
     */
73
    public function __construct(FormObject $formObject)
74
    {
75
        $this->formObject = $formObject;
76
    }
77
78
    /**
79
     * This function will search among the registered steps to find the one that
80
     * has the same controller parameters.
81
     *
82
     * It is also possible not to find any step, in this case `null` is
83
     * returned.
84
     *
85
     * @todo: memoization with request spl object storage
86
     *
87
     * @param string $extensionName
88
     * @param string $controllerName
89
     * @param string $actionName
90
     */
91
    public function fetchCurrentStep($extensionName, $controllerName, $actionName)
92
    {
93
        $this->currentHash = "$extensionName:$controllerName->$actionName";
94
95
        if (null !== $this->currentStep[$this->currentHash]) {
96
            return;
97
        }
98
99
        $this->currentStep[$this->currentHash] = false;
100
101
        $definition = $this->formObject->getDefinition();
102
103
        if ($definition->hasSteps()) {
104
            foreach ($definition->getSteps()->getEntries() as $step) {
105
                $data = [
106
                    // @todo: no page uid to fetch?
107
//                $step->getPageUid()    => Core::get()->getPageController()->id,
108
                    $step->getExtension() => $extensionName,
109
                    $step->getController() => $controllerName
110
                ];
111
112
                foreach ($data as $stepData => $requestData) {
113
                    if (false === empty($stepData)
114
                        && $stepData !== $requestData
115
                    ) {
116
                        continue 2;
117
                    }
118
                }
119
120
                $actionList = $step->getAuthorizedActions();
121
122
                if (false === in_array($actionName, $actionList)) {
123
                    continue;
124
                }
125
126
                if ($this->currentStep[$this->currentHash] instanceof Step) {
127
                    throw new \Exception('todo'); // @todo
128
                }
129
130
                $this->currentStep[$this->currentHash] = $step;
131
            }
132
        }
133
    }
134
135
    /**
136
     * @param Step $step
137
     */
138
    public function setCurrentStep(Step $step)
139
    {
140
        $this->currentStep[$this->currentHash] = $step;
141
    }
142
143
    /**
144
     * @return Step|null
145
     */
146
    public function getCurrentStep()
147
    {
148
        if (null === $this->currentStep[$this->currentHash]) {
149
            throw new \Exception('todo'); // @todo
150
        }
151
152
        return $this->currentStep[$this->currentHash] ?: null;
153
    }
154
155
    /**
156
     * @param Step $step
157
     * @return StepDefinition|null
158
     */
159
    public function getStepDefinition(Step $step)
160
    {
161
        return $this->findStepDefinition($step, $this->formObject->getDefinition()->getSteps()->getFirstStepDefinition());
162
    }
163
164
    /**
165
     * @param Step           $step
166
     * @param StepDefinition $stepDefinition
167
     * @return StepDefinition|null
168
     */
169
    protected function findStepDefinition(Step $step, StepDefinition $stepDefinition)
170
    {
171
        if ($stepDefinition->getStep() === $step) {
172
            return $stepDefinition;
173
        }
174
175
        if ($stepDefinition->hasNextStep()) {
176
            $result = $this->findStepDefinition($step, $stepDefinition->getNextStep());
177
178
            if ($result instanceof StepDefinition) {
179
                return $result;
180
            }
181
        }
182
183
        if ($stepDefinition->hasDivergence()) {
184
            foreach ($stepDefinition->getDivergenceSteps() as $divergenceStep) {
185
                $result = $this->findStepDefinition($step, $divergenceStep);
186
187
                if ($result instanceof StepDefinition) {
188
                    return $result;
189
                }
190
            }
191
        }
192
193
        return null;
194
    }
195
196
    /**
197
     * Fetches the step persistence object for the form, which may have been
198
     * stored in the form metadata.
199
     *
200
     * If the form object hash did change since the persistence object was saved
201
     * it is "refreshed" with the new hash (some data are also deleted as they
202
     * are no longer considered as valid).
203
     *
204
     * @return FormStepPersistence
205
     */
206
    public function getStepPersistence()
207
    {
208
        // @todo check configuration has steps or fatal error
209
        if (null === $this->stepPersistence) {
210
            $objectHash = $this->formObject->getObjectHash();
211
            $metadata = $this->formObject->getFormMetadata();
212
213
            if ($metadata->has(self::METADATA_STEP_PERSISTENCE_KEY)) {
214
                $this->stepPersistence = $metadata->get(self::METADATA_STEP_PERSISTENCE_KEY);
215
216
                if (false === $this->stepPersistence instanceof FormStepPersistence) {
217
                    unset($this->stepPersistence);
218
                } elseif ($objectHash !== $this->stepPersistence->getObjectHash()) {
219
                    $this->stepPersistence->refreshObjectHash($objectHash);
220
                }
221
            }
222
223
            if (null === $this->stepPersistence) {
224
                $this->stepPersistence = GeneralUtility::makeInstance(FormStepPersistence::class, $objectHash);
225
                $metadata->set(self::METADATA_STEP_PERSISTENCE_KEY, $this->stepPersistence);
226
            }
227
        }
228
229
        return $this->stepPersistence;
230
    }
231
232
    /**
233
     * @return SubstepDefinition
234
     */
235
    public function getCurrentSubstepDefinition()
236
    {
237
        return $this->currentSubstepDefinition ?: $this->getCurrentStep()->getSubsteps()->getFirstSubstepDefinition();
238
    }
239
240
    /**
241
     * @param SubstepDefinition $currentSubstepDefinition
242
     */
243
    public function setCurrentSubstepDefinition(SubstepDefinition $currentSubstepDefinition)
244
    {
245
        $this->currentSubstepDefinition = $currentSubstepDefinition;
246
    }
247
248
    /**
249
     * @param int $level
250
     */
251
    public function setSubstepsLevel($level)
252
    {
253
        $this->substepsLevel = max(1, (int)$level);
254
    }
255
256
    /**
257
     * @return int
258
     */
259
    public function getSubstepsLevel()
260
    {
261
        return $this->substepsLevel;
262
    }
263
264
    /**
265
     * @todo
266
     */
267
    public function markLastSubstepAsValidated()
268
    {
269
        $this->lastSubstepValidated = true;
270
    }
271
272
    /**
273
     * @return bool
274
     */
275
    public function lastSubstepWasValidated()
276
    {
277
        return $this->lastSubstepValidated;
278
    }
279
}
280