Completed
Push — middleware-wip ( 5dc6f3...73dcf0 )
by Romain
02:52
created

FormController::forwardToReferrer()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 11
rs 9.4285
cc 2
eloc 7
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;
15
16
use Romm\Formz\Core\Core;
17
use Romm\Formz\Form\FormInterface;
18
use Romm\Formz\Form\FormObject;
19
use Romm\Formz\Form\FormObjectFactory;
20
use Romm\Formz\Middleware\Request\Exception\RedirectException;
21
use Romm\Formz\Middleware\Request\Exception\StopPropagationException;
22
use Romm\Formz\Middleware\State\MiddlewareState;
23
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
24
use TYPO3\CMS\Extbase\Mvc\Controller\Argument;
25
use TYPO3\CMS\Extbase\Security\Cryptography\HashService;
26
27
class FormController extends ActionController
28
{
29
    /**
30
     * @var FormObject[]
31
     */
32
    protected $formArguments = [];
33
34
    /**
35
     * @var FormzControllerContext
36
     */
37
    protected $formzControllerContext;
38
39
    /**
40
     * @var HashService
41
     */
42
    protected $hashService;
43
44
    /**
45
     * @var FormObjectFactory
46
     */
47
    protected $formObjectFactory;
48
49
    /**
50
     * Main action used to dispatch the request properly, depending on FormZ
51
     * configuration.
52
     *
53
     * The request is based on the previously called controller action, and is
54
     * used to list which forms are handled (every argument of the action method
55
     * that implements the interface `FormInterface`).
56
     *
57
     * Middlewares will be called for each form argument, and may modify the
58
     * request, which is then dispatched again with modified data.
59
     */
60
    public function processFormAction()
61
    {
62
        $tt = new \TYPO3\CMS\Core\TimeTracker\TimeTracker();
63
        $tt->start();
64
65
        try {
66
            $this->invokeMiddlewares();
67
            $this->manageRequestResult();
68
        } catch (StopPropagationException $exception) {
69
            if ($exception instanceof RedirectException) {
70
                $this->redirectFromException($exception);
71
            }
72
73
            $this->forwardToReferrer();
74
        }
75
76
        $this->formzControllerContext->setDispatched(true);
77
78
        $request = $this->formzControllerContext->getRequest();
79
80
        $this->request->setControllerVendorName($this->formzControllerContext->getVendorName());
81
82
        $this->forward(
83
            $request->getControllerActionName(),
84
            $request->getControllerName(),
85
            $request->getControllerExtensionName(),
86
            $request->getArguments()
87
        );
88
    }
89
90
    /**
91
     * Will fetch every form argument for this request, and dispatch every
92
     * middleware that was registered in its TypoScript configuration.
93
     */
94
    protected function invokeMiddlewares()
95
    {
96
        foreach ($this->getRequestForms() as $formObject) {
97
            $formObject->reset();
98
99
            /*
100
             * If the configuration contains errors, then the middlewares
101
             * configuration may be corrupted as well, so the risk to dispatch
102
             * middlewares can not be taken.
103
             */
104
            if (false === $formObject->getConfigurationValidationResult()->hasErrors()) {
105
                /** @var MiddlewareState $middlewareFactory */
106
                $middlewareFactory = Core::instantiate(MiddlewareState::class, $formObject, $this->formzControllerContext);
107
108
                $middlewareFactory->run();
109
            }
110
        }
111
    }
112
113
    /**
114
     * Will check if the request result contains error; if errors are found, the
115
     * request is forwarded to the referring request, with the arguments of the
116
     * current request.
117
     */
118
    protected function manageRequestResult()
119
    {
120
        $request = $this->formzControllerContext->getRequest();
121
        $result = $request->getOriginalRequestMappingResults();
122
        $this->request->setOriginalRequestMappingResults($result);
123
124
        if ($result->hasErrors()) {
125
            $this->forwardToReferrer();
126
        }
127
    }
128
129
    /**
130
     * Forwards the request to the referrer request. It will also fill the
131
     * arguments of the action with the one from the source request.
132
     */
133
    protected function forwardToReferrer()
134
    {
135
        $request = $this->formzControllerContext->getRequest();
136
        $arguments = $request->getArguments();
137
        $referringRequest = $request->getReferringRequest();
138
        $this->formzControllerContext->setRequest($referringRequest);
0 ignored issues
show
Bug introduced by
It seems like $referringRequest defined by $request->getReferringRequest() on line 137 can be null; however, Romm\Formz\Controller\Fo...erContext::setRequest() 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...
139
140
        foreach ($arguments as $name => $value) {
141
            $referringRequest->setArgument($name, $value);
142
        }
143
    }
144
145
    /**
146
     * Loops on the request arguments, and pick up each one that is a form
147
     * instance (it implements `FormInterface`).
148
     *
149
     * @return FormObject[]
150
     */
151
    protected function getRequestForms()
152
    {
153
        if (empty($this->formArguments)) {
154
            /** @var Argument $argument */
155
            foreach ($this->formzControllerContext->getArguments() as $argument) {
156
                $type = $argument->getDataType();
157
158
                if (class_exists($type)
159
                    && in_array(FormInterface::class, class_implements($type))
160
                ) {
161
                    $formClassName = $argument->getDataType();
162
                    $formName = $argument->getName();
163
164
                    $formObject = $this->formObjectFactory->getInstanceFromClassName($formClassName, $formName);
165
                    $this->formArguments[$formName] = $formObject;
166
                }
167
            }
168
        }
169
170
        return $this->formArguments;
171
    }
172
173
    /**
174
     * @todo
175
     *
176
     * @return array
177
     */
178
    protected function getRequestData()
179
    {
180
        $requestData = [];
181
182
        if ($this->request->hasArgument('formz')) {
183
            $requestData = $this->request->getArgument('formz');
184
            $requestData = $this->hashService->validateAndStripHmac($requestData);
185
            $requestData = unserialize(base64_decode($requestData));
186
        }
187
188
        return $requestData;
189
    }
190
191
    /**
192
     * @param RedirectException $redirectException
193
     */
194
    protected function redirectFromException(RedirectException $redirectException)
195
    {
196
        $this->redirect(
197
            $redirectException->getActionName(),
198
            $redirectException->getControllerName(),
199
            $redirectException->getExtensionName(),
200
            $redirectException->getArguments(),
201
            $redirectException->getPageUid(),
202
            $redirectException->getDelay(),
203
            $redirectException->getStatusCode()
204
        );
205
    }
206
207
    /**
208
     * @param FormzControllerContext $formzControllerContext
209
     */
210
    public function injectFormzControllerContext(FormzControllerContext $formzControllerContext)
211
    {
212
        $this->formzControllerContext = $formzControllerContext;
213
    }
214
215
    /**
216
     * @param HashService $hashService
217
     */
218
    public function injectHashService(HashService $hashService)
219
    {
220
        $this->hashService = $hashService;
221
    }
222
223
    /**
224
     * @param FormObjectFactory $formObjectFactory
225
     */
226
    public function injectFormObjectFactory(FormObjectFactory $formObjectFactory)
227
    {
228
        $this->formObjectFactory = $formObjectFactory;
229
    }
230
}
231