Completed
Push — middleware-wip ( d468d0...25f95c )
by Romain
03:01
created

FormController::manageRequest()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 17
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\Exception\RedirectException;
21
use Romm\Formz\Middleware\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->manageRequest();
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
     * @todo
121
     */
122
    protected function manageRequest()
123
    {
124
        $request = $this->formzControllerContext->getRequest();
125
        $result = $request->getOriginalRequestMappingResults();
126
        $this->controllerContext->getRequest()->setOriginalRequestMappingResults($result);
127
128
        if ($result->hasErrors()) {
129
            $arguments = $request->getArguments();
130
            $referringRequest = $request->getReferringRequest();
131
            $this->formzControllerContext->setRequest($referringRequest);
0 ignored issues
show
Bug introduced by
It seems like $referringRequest defined by $request->getReferringRequest() on line 130 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...
132
133
            foreach ($arguments as $name => $value) {
134
                /** @var Argument $argument */
135
                $referringRequest->setArgument($name, $value);
136
            }
137
        }
138
    }
139
140
    /**
141
     * Loops on the request arguments, and pick up each one that is a form
142
     * instance (it implements `FormInterface`).
143
     *
144
     * @return FormObject[]
145
     */
146
    protected function getRequestForms()
147
    {
148
        if (empty($this->formArguments)) {
149
            /** @var Argument $argument */
150
            foreach ($this->formzControllerContext->getArguments() as $argument) {
151
                $type = $argument->getDataType();
152
153
                if (class_exists($type)
154
                    && in_array(FormInterface::class, class_implements($type))
155
                ) {
156
                    $formClassName = $argument->getDataType();
157
                    $formName = $argument->getName();
158
159
                    $formObject = $this->formObjectFactory->getInstanceFromClassName($formClassName, $formName);
160
                    $this->formArguments[$formName] = $formObject;
161
                }
162
            }
163
        }
164
165
        return $this->formArguments;
166
    }
167
168
    /**
169
     * @todo
170
     *
171
     * @return array
172
     */
173
    protected function getRequestData()
174
    {
175
        $requestData = [];
176
177
        if ($this->request->hasArgument('formz')) {
178
            $requestData = $this->request->getArgument('formz');
179
            $requestData = $this->hashService->validateAndStripHmac($requestData);
180
            $requestData = unserialize(base64_decode($requestData));
181
        }
182
183
        return $requestData;
184
    }
185
186
    /**
187
     * @param FormzControllerContext $formzControllerContext
188
     */
189
    public function injectFormzControllerContext(FormzControllerContext $formzControllerContext)
190
    {
191
        $this->formzControllerContext = $formzControllerContext;
192
    }
193
194
    /**
195
     * @param HashService $hashService
196
     */
197
    public function injectHashService(HashService $hashService)
198
    {
199
        $this->hashService = $hashService;
200
    }
201
202
    /**
203
     * @param FormObjectFactory $formObjectFactory
204
     */
205
    public function injectFormObjectFactory(FormObjectFactory $formObjectFactory)
206
    {
207
        $this->formObjectFactory = $formObjectFactory;
208
    }
209
}
210