Completed
Push — wip/steps ( a8ec08...593c83 )
by Romain
02:14
created

ControllerProcessor::getScope()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
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\Controller\Processor;
15
16
use Romm\Formz\Form\FormInterface;
17
use Romm\Formz\Form\FormObject\FormObject;
18
use Romm\Formz\Form\FormObject\FormObjectFactory;
19
use Romm\Formz\Middleware\Scope\ScopeInterface;
20
use Romm\Formz\Service\Traits\ExtendedSelfInstantiateTrait;
21
use TYPO3\CMS\Core\SingletonInterface;
22
use TYPO3\CMS\Extbase\Mvc\Controller\Argument;
23
use TYPO3\CMS\Extbase\Mvc\Controller\Arguments;
24
use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
25
use TYPO3\CMS\Extbase\Mvc\Request as MvcRequest;
26
use TYPO3\CMS\Extbase\Mvc\Web\Request;
27
28
class ControllerProcessor implements SingletonInterface
29
{
30
    use ExtendedSelfInstantiateTrait;
31
32
    /**
33
     * @var FormObjectFactory
34
     */
35
    protected $formObjectFactory;
36
37
    /**
38
     * @var FormObject[]
39
     */
40
    protected $formArguments;
41
42
    /**
43
     * @var bool
44
     */
45
    protected $dispatched = false;
46
47
    /**
48
     * @var Request
49
     */
50
    protected $originalRequest;
51
52
    /**
53
     * @var Request
54
     */
55
    protected $request;
56
57
    /**
58
     * @var Arguments
59
     */
60
    protected $requestArguments;
61
62
    /**
63
     * An interface name that does implement:
64
     *
65
     * @see \Romm\Formz\Middleware\Scope\ScopeInterface
66
     *
67
     * It will be used to filter the middlewares that will be called.
68
     *
69
     * @var string
70
     */
71
    protected $scope;
72
73
    /**
74
     * @var array
75
     */
76
    protected $settings = [];
77
78
    /**
79
     * @todo
80
     *
81
     * @var string
82
     */
83
    protected $lastDispatchedRequest;
84
85
    /**
86
     * @var callable
87
     */
88
    protected $exceptionCallback;
89
90
    /**
91
     * @param MvcRequest $request
92
     * @param Arguments  $requestArguments
93
     * @param array      $settings
94
     * @param string     $scope
95
     * @return $this
96
     */
97
    public static function prepare(MvcRequest $request, Arguments $requestArguments, array $settings, $scope)
98
    {
99
        return self::get()->setData($request, $requestArguments, $settings, $scope);
100
    }
101
102
    /**
103
     * Injects the data needed for this class to work properly. This method must
104
     * be called before the dispatch is called.
105
     *
106
     * @param MvcRequest $request
107
     * @param Arguments  $requestArguments
108
     * @param string     $scope
109
     * @param array      $settings
110
     * @return $this
111
     */
112
    public function setData(MvcRequest $request, Arguments $requestArguments, $scope, array $settings)
113
    {
114
        if (false === in_array(ScopeInterface::class, class_implements($scope))) {
115
            throw new \Exception('todo scope : ' . $scope); // @todo
116
        }
117
118
        /** @var Request $request */
119
        $dispatchedRequest = $request->getControllerObjectName() . '::' . $request->getControllerActionName() . '::' . $scope;
120
121
        if ($dispatchedRequest !== $this->lastDispatchedRequest) {
122
            $this->lastDispatchedRequest = $dispatchedRequest;
123
124
            $this->originalRequest = $request;
125
            $this->request = clone $request;
126
            $this->requestArguments = $requestArguments;
127
            $this->scope = $scope;
128
            $this->settings = $settings;
129
            $this->formArguments = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array<integer,object<Rom...FormObject\FormObject>> of property $formArguments.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
130
            $this->dispatched = false;
131
        }
132
133
        return $this;
134
    }
135
136
    /**
137
     * Will dispatch the current request to the form controller, which will take
138
     * care of processing everything properly.
139
     *
140
     * In case no form is found in the controller action parameters, the current
141
     * request is not killed.
142
     *
143
     * @throws StopActionException
144
     */
145
    public function dispatch()
146
    {
147
        if (false === $this->dispatched) {
148
            $this->dispatched = true;
149
150
            $this->doDispatch();
151
        }
152
    }
153
154
    /**
155
     * Wrapper for unit testing.
156
     */
157
    protected function doDispatch()
158
    {
159
        if (false === empty($this->getRequestForms())) {
160
            $this->originalRequest->setDispatched(false);
161
            $this->originalRequest->setControllerVendorName('Romm');
162
            $this->originalRequest->setControllerExtensionName('Formz');
163
            $this->originalRequest->setControllerName('Form');
164
            $this->originalRequest->setControllerActionName('processForm');
165
166
            $this->checkFormObjectsErrors();
167
168
            throw new StopActionException;
169
        }
170
    }
171
172
    /**
173
     * Will check if the form objects found in the request arguments contain
174
     * configuration errors. If they do, we dispatch the request to the error
175
     * view, where all errors will be explained properly to the user.
176
     */
177
    protected function checkFormObjectsErrors()
178
    {
179
        foreach ($this->getRequestForms() as $formObject) {
180
            if ($formObject->getDefinitionValidationResult()->hasErrors()) {
181
                $this->originalRequest->setControllerActionName('formObjectError');
182
                $this->originalRequest->setArguments(['formObject' => $formObject]);
183
184
                break;
185
            }
186
        }
187
    }
188
189
    /**
190
     * Loops on the request arguments, and pick up each one that is a form
191
     * instance (it implements `FormInterface`).
192
     *
193
     * @return FormObject[]
194
     */
195
    public function getRequestForms()
196
    {
197
        if (null === $this->formArguments) {
198
            $this->formArguments = [];
199
200
            /** @var Argument $argument */
201
            foreach ($this->requestArguments as $argument) {
202
                $type = $argument->getDataType();
203
204
                if (class_exists($type)
205
                    && in_array(FormInterface::class, class_implements($type))
206
                ) {
207
                    $formClassName = $argument->getDataType();
208
                    $formName = $argument->getName();
209
210
                    $formObject = $this->formObjectFactory->getInstanceWithClassName($formClassName, $formName);
211
                    $this->formArguments[$formName] = $formObject;
212
                }
213
            }
214
        }
215
216
        return $this->formArguments;
217
    }
218
219
    /**
220
     * @return Request
221
     */
222
    public function getRequest()
223
    {
224
        return $this->request;
225
    }
226
227
    /**
228
     * @return Arguments
229
     */
230
    public function getRequestArguments()
231
    {
232
        return $this->requestArguments;
233
    }
234
235
    /**
236
     * @return array
237
     */
238
    public function getSettings()
239
    {
240
        return $this->settings;
241
    }
242
243
    /**
244
     * @return string
245
     */
246
    public function getScope()
247
    {
248
        return $this->scope;
249
    }
250
251
    /**
252
     * @param callable $callback
253
     * @return $this
254
     */
255
    public function setExceptionCallback(callable $callback)
256
    {
257
        $this->exceptionCallback = $callback;
258
259
        return $this;
260
    }
261
262
    /**
263
     * @return callable
264
     */
265
    public function getExceptionCallback()
266
    {
267
        return $this->exceptionCallback;
268
    }
269
270
    /**
271
     * @return bool
272
     */
273
    public function hasExceptionCallback()
274
    {
275
        return null !== $this->exceptionCallback;
276
    }
277
278
    /**
279
     * @param FormObjectFactory $formObjectFactory
280
     */
281
    public function injectFormObjectFactory(FormObjectFactory $formObjectFactory)
282
    {
283
        $this->formObjectFactory = $formObjectFactory;
284
    }
285
}
286