Completed
Push — feature/middleware ( 92238f...1fcb04 )
by Romain
02:26
created

ControllerProcessor::doDispatch()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 9
nc 2
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
     * Contains information about the last request that was dispatched to FormZ.
68
     * It is used to prevent infinite loop.
69
     *
70
     * @var string
71
     */
72
    protected $lastDispatchedRequest;
73
74
    /**
75
     * @param MvcRequest $request
76
     * @param Arguments  $requestArguments
77
     * @return $this
78
     */
79
    public static function prepare(MvcRequest $request, Arguments $requestArguments)
80
    {
81
        return self::get()->setData($request, $requestArguments, []);
0 ignored issues
show
Bug introduced by
It seems like setData() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
82
    }
83
84
    /**
85
     * Injects the data needed for this class to work properly. This method must
86
     * be called before the `dispatch` method is called.
87
     *
88
     * @param MvcRequest $request
89
     * @param Arguments  $requestArguments
90
     * @param array      $settings
91
     * @return $this
92
     */
93
    public function setData(MvcRequest $request, Arguments $requestArguments, array $settings)
94
    {
95
        /** @var Request $request */
96
        $dispatchedRequest = $request->getControllerObjectName() . '::' . $request->getControllerActionName();
97
98
        if ($dispatchedRequest !== $this->lastDispatchedRequest) {
99
            $this->lastDispatchedRequest = $dispatchedRequest;
100
101
            $this->originalRequest = $request;
102
            $this->request = clone $request;
103
            $this->requestArguments = $requestArguments;
104
            $this->settings = $settings;
105
            $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...
106
            $this->dispatched = false;
107
        }
108
109
        return $this;
110
    }
111
112
    /**
113
     * Will dispatch the current request to the form controller, which will take
114
     * care of processing everything properly.
115
     *
116
     * In case no form is found in the controller action parameters, the current
117
     * request is not killed.
118
     *
119
     * @throws StopActionException
120
     */
121
    public function dispatch()
122
    {
123
        if (false === $this->dispatched) {
124
            $this->dispatched = true;
125
126
            $this->doDispatch();
127
        }
128
    }
129
130
    /**
131
     * Wrapper for unit testing.
132
     */
133
    protected function doDispatch()
134
    {
135
        if (false === empty($this->getRequestForms())) {
136
            $this->originalRequest->setDispatched(false);
137
            $this->originalRequest->setControllerVendorName('Romm');
138
            $this->originalRequest->setControllerExtensionName('Formz');
139
            $this->originalRequest->setControllerName('Form');
140
            $this->originalRequest->setControllerActionName('processForm');
141
142
            $this->checkFormObjectsErrors();
143
144
            throw new StopActionException;
145
        }
146
    }
147
148
    /**
149
     * Will check if the form objects found in the request arguments contain
150
     * configuration errors. If they do, we dispatch the request to the error
151
     * view, where all errors will be explained properly to the user.
152
     */
153
    protected function checkFormObjectsErrors()
154
    {
155
        foreach ($this->getRequestForms() as $formObject) {
156
            if ($formObject->getDefinitionValidationResult()->hasErrors()) {
157
                $this->originalRequest->setControllerActionName('formObjectError');
158
                $this->originalRequest->setArguments(['formObject' => $formObject]);
159
160
                break;
161
            }
162
        }
163
    }
164
165
    /**
166
     * Loops on the request arguments, and picks up each one that is a form
167
     * instance (it implements `FormInterface`).
168
     *
169
     * @return FormObject[]
170
     */
171
    public function getRequestForms()
172
    {
173
        if (null === $this->formArguments) {
174
            $this->formArguments = [];
175
176
            /** @var Argument $argument */
177
            foreach ($this->requestArguments as $argument) {
178
                $type = $argument->getDataType();
179
180
                if (class_exists($type)
181
                    && in_array(FormInterface::class, class_implements($type))
182
                ) {
183
                    $formClassName = $argument->getDataType();
184
                    $formName = $argument->getName();
185
                    $formObject = $this->formObjectFactory->getInstanceWithClassName($formClassName, $formName);
186
187
                    $this->formArguments[$formName] = $formObject;
188
                }
189
            }
190
        }
191
192
        return $this->formArguments;
193
    }
194
195
    /**
196
     * @return Request
197
     */
198
    public function getRequest()
199
    {
200
        return $this->request;
201
    }
202
203
    /**
204
     * @return Arguments
205
     */
206
    public function getRequestArguments()
207
    {
208
        return $this->requestArguments;
209
    }
210
211
    /**
212
     * @return array
213
     */
214
    public function getSettings()
215
    {
216
        return $this->settings;
217
    }
218
219
    /**
220
     * @param FormObjectFactory $formObjectFactory
221
     */
222
    public function injectFormObjectFactory(FormObjectFactory $formObjectFactory)
223
    {
224
        $this->formObjectFactory = $formObjectFactory;
225
    }
226
}
227