Completed
Push — middleware-wip ( 25f95c...951ea4 )
by Romain
03:02
created

FormController::manageRequestResult()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 10
nc 3
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->redirect(
71
                    $exception->getActionName(),
72
                    $exception->getControllerName(),
73
                    $exception->getExtensionName(),
74
                    $exception->getArguments(),
75
                    $exception->getPageUid(),
76
                    $exception->getDelay(),
77
                    $exception->getStatusCode()
78
                );
79
            }
80
        }
81
82
        $this->formzControllerContext->setDispatched(true);
83
84
        $request = $this->formzControllerContext->getRequest();
85
86
        $this->request->setControllerVendorName($this->formzControllerContext->getVendorName());
87
88
        $this->forward(
89
            $request->getControllerActionName(),
90
            $request->getControllerName(),
91
            $request->getControllerExtensionName(),
92
            $request->getArguments()
93
        );
94
    }
95
96
    /**
97
     * Will fetch every form argument for this request, and dispatch every
98
     * middleware that was registered in its TypoScript configuration.
99
     */
100
    protected function invokeMiddlewares()
101
    {
102
        foreach ($this->getRequestForms() as $formObject) {
103
            $formObject->reset();
104
105
            /*
106
             * If the configuration contains errors, then the middlewares
107
             * configuration may be corrupted as well, so the risk to dispatch
108
             * middlewares can not be taken.
109
             */
110
            if (false === $formObject->getConfigurationValidationResult()->hasErrors()) {
111
                /** @var MiddlewareState $middlewareFactory */
112
                $middlewareFactory = Core::instantiate(MiddlewareState::class, $formObject, $this->formzControllerContext);
113
114
                $middlewareFactory->run();
115
            }
116
        }
117
    }
118
119
    /**
120
     * Will check if the request result contains error; if errors are found, the
121
     * request is forwarded to the referring request, with the arguments of the
122
     * current request.
123
     */
124
    protected function manageRequestResult()
125
    {
126
        $request = $this->formzControllerContext->getRequest();
127
        $result = $request->getOriginalRequestMappingResults();
128
        $this->request->setOriginalRequestMappingResults($result);
129
130
        if ($result->hasErrors()) {
131
            $arguments = $request->getArguments();
132
            $referringRequest = $request->getReferringRequest();
133
            $this->formzControllerContext->setRequest($referringRequest);
0 ignored issues
show
Bug introduced by
It seems like $referringRequest defined by $request->getReferringRequest() on line 132 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...
134
135
            foreach ($arguments as $name => $value) {
136
                $referringRequest->setArgument($name, $value);
137
            }
138
        }
139
    }
140
141
    /**
142
     * Loops on the request arguments, and pick up each one that is a form
143
     * instance (it implements `FormInterface`).
144
     *
145
     * @return FormObject[]
146
     */
147
    protected function getRequestForms()
148
    {
149
        if (empty($this->formArguments)) {
150
            /** @var Argument $argument */
151
            foreach ($this->formzControllerContext->getArguments() as $argument) {
152
                $type = $argument->getDataType();
153
154
                if (class_exists($type)
155
                    && in_array(FormInterface::class, class_implements($type))
156
                ) {
157
                    $formClassName = $argument->getDataType();
158
                    $formName = $argument->getName();
159
160
                    $formObject = $this->formObjectFactory->getInstanceFromClassName($formClassName, $formName);
161
                    $this->formArguments[$formName] = $formObject;
162
                }
163
            }
164
        }
165
166
        return $this->formArguments;
167
    }
168
169
    /**
170
     * @todo
171
     *
172
     * @return array
173
     */
174
    protected function getRequestData()
175
    {
176
        $requestData = [];
177
178
        if ($this->request->hasArgument('formz')) {
179
            $requestData = $this->request->getArgument('formz');
180
            $requestData = $this->hashService->validateAndStripHmac($requestData);
181
            $requestData = unserialize(base64_decode($requestData));
182
        }
183
184
        return $requestData;
185
    }
186
187
    /**
188
     * @param FormzControllerContext $formzControllerContext
189
     */
190
    public function injectFormzControllerContext(FormzControllerContext $formzControllerContext)
191
    {
192
        $this->formzControllerContext = $formzControllerContext;
193
    }
194
195
    /**
196
     * @param HashService $hashService
197
     */
198
    public function injectHashService(HashService $hashService)
199
    {
200
        $this->hashService = $hashService;
201
    }
202
203
    /**
204
     * @param FormObjectFactory $formObjectFactory
205
     */
206
    public function injectFormObjectFactory(FormObjectFactory $formObjectFactory)
207
    {
208
        $this->formObjectFactory = $formObjectFactory;
209
    }
210
}
211