Completed
Push — wip/steps ( a89def...4fedf8 )
by Romain
02:24
created

ControllerProcessor::getExceptionCallback()   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\Service\Traits\ExtendedSelfInstantiateTrait;
20
use TYPO3\CMS\Core\SingletonInterface;
21
use TYPO3\CMS\Extbase\Mvc\Controller\Argument;
22
use TYPO3\CMS\Extbase\Mvc\Controller\Arguments;
23
use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
24
use TYPO3\CMS\Extbase\Mvc\Request as MvcRequest;
25
use TYPO3\CMS\Extbase\Mvc\Web\Request;
26
27
class ControllerProcessor implements SingletonInterface
28
{
29
    use ExtendedSelfInstantiateTrait;
30
31
    /**
32
     * @var FormObjectFactory
33
     */
34
    protected $formObjectFactory;
35
36
    /**
37
     * @var FormObject[]
38
     */
39
    protected $formArguments;
40
41
    /**
42
     * @var bool
43
     */
44
    protected $dispatched = false;
45
46
    /**
47
     * @var Request
48
     */
49
    protected $originalRequest;
50
51
    /**
52
     * @var Request
53
     */
54
    protected $request;
55
56
    /**
57
     * @var Arguments
58
     */
59
    protected $requestArguments;
60
61
    /**
62
     * @var array
63
     */
64
    protected $settings = [];
65
66
    /**
67
     * @todo
68
     *
69
     * @var string
70
     */
71
    protected $lastDispatchedRequest;
72
73
    /**
74
     * @var callable
75
     */
76
    protected $exceptionCallback;
77
78
    /**
79
     * @param MvcRequest $request
80
     * @param Arguments  $requestArguments
81
     * @param array      $settings
82
     * @return $this
83
     */
84
    public static function prepare(MvcRequest $request, Arguments $requestArguments, array $settings)
85
    {
86
        return self::get()->setData($request, $requestArguments, $settings);
87
    }
88
89
    /**
90
     * Injects the data needed for this class to work properly. This method must
91
     * be called before the dispatch is called.
92
     *
93
     * @param MvcRequest $request
94
     * @param Arguments  $requestArguments
95
     * @param array      $settings
96
     * @return $this
97
     */
98
    public function setData(MvcRequest $request, Arguments $requestArguments, array $settings)
99
    {
100
        /** @var Request $request */
101
        $dispatchedRequest = $request->getControllerObjectName() . '::' . $request->getControllerActionName();
102
103
        if ($dispatchedRequest !== $this->lastDispatchedRequest) {
104
            $this->lastDispatchedRequest = $dispatchedRequest;
105
106
            $this->originalRequest = $request;
107
            $this->request = clone $request;
108
            $this->requestArguments = $requestArguments;
109
            $this->settings = $settings;
110
            $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...
111
            $this->dispatched = false;
112
        }
113
114
        return $this;
115
    }
116
117
    /**
118
     * Will dispatch the current request to the form controller, which will take
119
     * care of processing everything properly.
120
     *
121
     * In case no form is found in the controller action parameters, the current
122
     * request is not killed.
123
     *
124
     * @throws StopActionException
125
     */
126
    public function dispatch()
127
    {
128
        if (false === $this->dispatched) {
129
            $this->dispatched = true;
130
131
            $this->doDispatch();
132
        }
133
    }
134
135
    /**
136
     * Wrapper for unit testing.
137
     */
138
    protected function doDispatch()
139
    {
140
        if (false === empty($this->getRequestForms())) {
141
            $this->originalRequest->setDispatched(false);
142
            $this->originalRequest->setControllerVendorName('Romm');
143
            $this->originalRequest->setControllerExtensionName('Formz');
144
            $this->originalRequest->setControllerName('Form');
145
            $this->originalRequest->setControllerActionName('processForm');
146
147
            $this->checkFormObjectsErrors();
148
149
            throw new StopActionException;
150
        }
151
    }
152
153
    /**
154
     * Will check if the form objects found in the request arguments contain
155
     * configuration errors. If they do, we dispatch the request to the error
156
     * view, where all errors will be explained properly to the user.
157
     */
158
    protected function checkFormObjectsErrors()
159
    {
160
        foreach ($this->getRequestForms() as $formObject) {
161
            if ($formObject->getDefinitionValidationResult()->hasErrors()) {
162
                $this->originalRequest->setControllerActionName('formObjectError');
163
                $this->originalRequest->setArguments(['formObject' => $formObject]);
164
165
                break;
166
            }
167
        }
168
    }
169
170
    /**
171
     * Loops on the request arguments, and pick up each one that is a form
172
     * instance (it implements `FormInterface`).
173
     *
174
     * @return FormObject[]
175
     */
176
    public function getRequestForms()
177
    {
178
        if (null === $this->formArguments) {
179
            $this->formArguments = [];
180
181
            /** @var Argument $argument */
182
            foreach ($this->requestArguments as $argument) {
183
                $type = $argument->getDataType();
184
185
                if (class_exists($type)
186
                    && in_array(FormInterface::class, class_implements($type))
187
                ) {
188
                    $formClassName = $argument->getDataType();
189
                    $formName = $argument->getName();
190
191
                    $formObject = $this->formObjectFactory->getInstanceWithClassName($formClassName, $formName);
192
                    $this->formArguments[$formName] = $formObject;
193
                }
194
            }
195
        }
196
197
        return $this->formArguments;
198
    }
199
200
    /**
201
     * @return Request
202
     */
203
    public function getRequest()
204
    {
205
        return $this->request;
206
    }
207
208
    /**
209
     * @return Arguments
210
     */
211
    public function getRequestArguments()
212
    {
213
        return $this->requestArguments;
214
    }
215
216
    /**
217
     * @return array
218
     */
219
    public function getSettings()
220
    {
221
        return $this->settings;
222
    }
223
224
    /**
225
     * @param callable $callback
226
     * @return $this
227
     */
228
    public function setExceptionCallback(callable $callback)
229
    {
230
        $this->exceptionCallback = $callback;
231
232
        return $this;
233
    }
234
235
    /**
236
     * @return callable
237
     */
238
    public function getExceptionCallback()
239
    {
240
        return $this->exceptionCallback;
241
    }
242
243
    /**
244
     * @return bool
245
     */
246
    public function hasExceptionCallback()
247
    {
248
        return null !== $this->exceptionCallback;
249
    }
250
251
    /**
252
     * @param FormObjectFactory $formObjectFactory
253
     */
254
    public function injectFormObjectFactory(FormObjectFactory $formObjectFactory)
255
    {
256
        $this->formObjectFactory = $formObjectFactory;
257
    }
258
}
259