Completed
Push — feature/middleware-tmp ( 8f1e4d )
by Romain
01:57
created

FormController::processFormAction()   B

Complexity

Conditions 6
Paths 15

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 8.439
c 0
b 0
f 0
cc 6
eloc 16
nc 15
nop 1
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 Exception;
17
use Romm\Formz\Controller\Processor\ControllerProcessor;
18
use Romm\Formz\Core\Core;
19
use Romm\Formz\Form\FormObject\FormObject;
20
use Romm\Formz\Middleware\Processor\MiddlewareProcessor;
21
use Romm\Formz\Middleware\Request\Exception\ForwardException;
22
use Romm\Formz\Middleware\Request\Exception\RedirectException;
23
use Romm\Formz\Middleware\Request\Exception\StopPropagationException;
24
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
25
use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
26
use TYPO3\CMS\Extbase\Mvc\Web\Request;
27
28
/**
29
 * This is the main form controller, it will be called between a request
30
 * dispatching and a controller action.
31
 *
32
 * It will process the current action being called, and analyze every parameter
33
 * of the method that is a form instance. For each form, all its registered
34
 * middlewares will be called, allowing manipulation of the request, the form
35
 * validation, and more.
36
 */
37
class FormController extends ActionController
38
{
39
    /**
40
     * @var ControllerProcessor
41
     */
42
    protected $processor;
43
44
    /**
45
     * @var Request
46
     */
47
    protected $originalRequest;
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
     * @param Request $originalRequest
61
     * @throws Exception
62
     */
63
    public function processFormAction(Request $originalRequest)
64
    {
65
        $exception = null;
66
        $this->originalRequest = $originalRequest;
67
68
        try {
69
            $this->invokeMiddlewares();
70
            $this->manageRequestResult();
71
        } catch (Exception $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
72
        }
73
74
        if ($exception instanceof Exception) {
75
            if ($exception instanceof StopPropagationException) {
76
                if ($exception instanceof RedirectException) {
77
                    $this->redirectFromException($exception);
78
                } elseif (false === $exception instanceof ForwardException) {
79
                    $this->forwardToReferrer();
80
                }
81
            } else {
82
                throw $exception;
83
            }
84
        }
85
86
        $this->continueRequest();
87
    }
88
89
    /**
90
     * @param FormObject $formObject
91
     */
92
    public function formObjectErrorAction(FormObject $formObject)
93
    {
94
        $this->view->assign('formObject', $formObject);
95
    }
96
97
    /**
98
     * Will fetch every form argument for this request, and dispatch every
99
     * middleware registered in its definition.
100
     */
101
    protected function invokeMiddlewares()
102
    {
103
        foreach ($this->processor->getRequestForms() as $formObject) {
104
            /** @var MiddlewareProcessor $middlewareProcessor */
105
            $middlewareProcessor = Core::instantiate(MiddlewareProcessor::class, $formObject, $this->processor);
106
107
            $middlewareProcessor->run();
108
        }
109
    }
110
111
    /**
112
     * Will check if the request result contains error; if errors are found, the
113
     * request is forwarded to the referring request, with the arguments of the
114
     * current request.
115
     */
116
    protected function manageRequestResult()
117
    {
118
        $result = $this->processor->getRequest()->getOriginalRequestMappingResults();
119
        $this->request->setOriginalRequestMappingResults($result);
120
121
        if ($result->hasErrors()) {
122
            $this->forwardToReferrer();
123
        }
124
    }
125
126
    /**
127
     * Forwards the request to the original request that led to this controller.
128
     *
129
     * @throws StopActionException
130
     */
131
    protected function continueRequest()
132
    {
133
        $this->request->setDispatched(false);
134
        $request = $this->processor->getRequest();
135
136
        $this->request->setPluginName($request->getPluginName());
137
        $this->request->setControllerVendorName($request->getControllerVendorName());
138
        $this->request->setControllerExtensionName($request->getControllerExtensionName());
139
        $this->request->setControllerName($request->getControllerName());
140
        $this->request->setControllerActionName($request->getControllerActionName());
141
        $this->request->setArguments($this->processor->getRequest()->getArguments());
142
143
        throw new StopActionException;
144
    }
145
146
    /**
147
     * Forwards to the referrer request. It will also fill the arguments of the
148
     * action with the ones from the source request.
149
     *
150
     * @throws StopActionException
151
     */
152
    protected function forwardToReferrer()
153
    {
154
        $referringRequest = $this->originalRequest->getReferringRequest();
155
156
        if ($referringRequest) {
157
            $this->request->setDispatched(false);
158
            $this->request->setOriginalRequest($this->originalRequest);
159
160
            $this->request->setControllerVendorName($referringRequest->getControllerVendorName());
161
            $this->request->setControllerExtensionName($referringRequest->getControllerExtensionName());
162
            $this->request->setControllerName($referringRequest->getControllerName());
163
            $this->request->setControllerActionName($referringRequest->getControllerActionName());
164
            $this->request->setArguments($this->processor->getRequest()->getArguments());
165
        } else {
166
            // @todo ?
167
        }
168
169
        throw new StopActionException;
170
    }
171
172
    /**
173
     * If an exception of type `RedirectException` was thrown, the request is
174
     * forwarded, using the arguments sent to the exception.
175
     *
176
     * @param RedirectException $redirectException
177
     */
178
    protected function redirectFromException(RedirectException $redirectException)
179
    {
180
        $this->uriBuilder->setRequest($this->processor->getRequest());
181
182
        $this->redirect(
183
            $redirectException->getActionName(),
184
            $redirectException->getControllerName(),
185
            $redirectException->getExtensionName(),
186
            $redirectException->getArguments(),
187
            $redirectException->getPageUid(),
188
            $redirectException->getDelay(),
189
            $redirectException->getStatusCode()
190
        );
191
    }
192
193
    /**
194
     * @param ControllerProcessor $processor
195
     */
196
    public function injectProcessor(ControllerProcessor $processor)
197
    {
198
        $this->processor = $processor;
199
    }
200
}
201