Completed
Push — middleware-wip ( 1bcdac...ffd957 )
by Romain
02:46
created

FormController::manageRequestResult()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 9
rs 9.6666
c 1
b 0
f 0
cc 2
eloc 5
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 Exception;
17
use Romm\Formz\Core\Core;
18
use Romm\Formz\Form\FormObject\FormObject;
19
use Romm\Formz\Middleware\Request\Exception\ForwardException;
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\Exception\StopActionException;
25
use TYPO3\CMS\Extbase\Mvc\Web\Request;
26
27
/**
28
 * This is the main form controller, which is called before a controller action
29
 * with at least form argument is called.
30
 *
31
 * It will process the argument form(s), for instance by calling all its
32
 * middlewares. It allows manipulating the request, and information about the
33
 * form, before the actual action is called.
34
 */
35
class FormController extends ActionController
36
{
37
    /**
38
     * @var ControllerState
39
     */
40
    protected $state;
41
42
    /**
43
     * @var Request
44
     */
45
    protected $originalRequest;
46
47
    /**
48
     * Main action used to dispatch the request properly, depending on FormZ
49
     * configuration.
50
     *
51
     * The request is based on the previously called controller action, and is
52
     * used to list which forms are handled (every argument of the action method
53
     * that implements the interface `FormInterface`).
54
     *
55
     * Middlewares will be called for each form argument, and may modify the
56
     * request, which is then dispatched again with modified data.
57
     *
58
     * @param Request $originalRequest
59
     * @throws Exception
60
     */
61
    public function processFormAction(Request $originalRequest)
62
    {
63
        $exception = null;
64
        $this->originalRequest = $originalRequest;
65
66
        try {
67
            $this->invokeMiddlewares();
68
            $this->manageRequestResult();
69
        } catch (Exception $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
70
        }
71
72
        $this->commitMetadata();
73
74
        if ($exception instanceof Exception) {
75
            if ($exception instanceof RedirectException) {
76
                $this->redirectFromException($exception);
77
            } elseif (false === $exception instanceof ForwardException) {
78
                $this->forwardToReferrer();
79
            } elseif (false === $exception instanceof StopPropagationException) {
80
                throw $exception;
81
            }
82
        }
83
84
        $this->continueRequest();
85
    }
86
87
    /**
88
     * @param FormObject $formObject
89
     */
90
    public function formObjectErrorAction(FormObject $formObject)
91
    {
92
        $this->view->assign('formObject', $formObject);
93
    }
94
95
    /**
96
     * Will fetch every form argument for this request, and dispatch every
97
     * middleware that was registered in its TypoScript configuration.
98
     */
99
    protected function invokeMiddlewares()
100
    {
101
        foreach ($this->state->getRequestForms() as $formObject) {
102
            /** @var MiddlewareState $middlewareState */
103
            $middlewareState = Core::instantiate(MiddlewareState::class, $formObject, $this->state);
104
105
            $middlewareState->run();
106
        }
107
    }
108
109
    /**
110
     * Will check if the request result contains error; if errors are found, the
111
     * request is forwarded to the referring request, with the arguments of the
112
     * current request.
113
     */
114
    protected function manageRequestResult()
115
    {
116
        $result = $this->state->getRequest()->getOriginalRequestMappingResults();
117
        $this->request->setOriginalRequestMappingResults($result);
118
119
        if ($result->hasErrors()) {
120
            $this->forwardToReferrer();
121
        }
122
    }
123
124
    /**
125
     * Loops on every form of this request, and commits the metadata in database
126
     * for each one.
127
     */
128
    protected function commitMetadata()
129
    {
130
        foreach ($this->state->getRequestForms() as $formObject) {
131
            if ($formObject->hasForm()
132
                && $formObject->getPersistenceManager()->formIsPersistent()
133
            ) {
134
                $formObject->getMetadata()->commit();
135
            }
136
        }
137
    }
138
139
    /**
140
     * Forwards the request to the original request that led to this controller.
141
     *
142
     * @throws StopActionException
143
     */
144
    protected function continueRequest()
145
    {
146
        $this->request->setDispatched(false);
147
        $request = $this->state->getRequest();
148
149
        $this->request->setPluginName($request->getPluginName());
150
        $this->request->setControllerVendorName($request->getControllerVendorName());
151
        $this->request->setControllerExtensionName($request->getControllerExtensionName());
152
        $this->request->setControllerName($request->getControllerName());
153
        $this->request->setControllerActionName($request->getControllerActionName());
154
        $this->request->setArguments($this->state->getRequest()->getArguments());
155
156
        throw new StopActionException;
157
    }
158
159
    /**
160
     * Forwards to the referrer request. It will also fill the arguments of the
161
     * action with the ones from the source request.
162
     *
163
     * @throws StopActionException
164
     */
165
    protected function forwardToReferrer()
166
    {
167
        $referringRequest = $this->originalRequest->getReferringRequest();
168
169
        if ($referringRequest) {
170
            $this->request->setDispatched(false);
171
            $this->request->setOriginalRequest($this->originalRequest);
172
173
            $this->request->setControllerVendorName($referringRequest->getControllerVendorName());
174
            $this->request->setControllerExtensionName($referringRequest->getControllerExtensionName());
175
            $this->request->setControllerName($referringRequest->getControllerName());
176
            $this->request->setControllerActionName($referringRequest->getControllerActionName());
177
            $this->request->setArguments($this->state->getRequest()->getArguments());
178
        } else {
179
            // @todo ?
180
        }
181
182
        throw new StopActionException;
183
    }
184
185
    /**
186
     * @param RedirectException $redirectException
187
     */
188
    protected function redirectFromException(RedirectException $redirectException)
189
    {
190
        $this->redirect(
191
            $redirectException->getActionName(),
192
            $redirectException->getControllerName(),
193
            $redirectException->getExtensionName(),
194
            $redirectException->getArguments(),
195
            $redirectException->getPageUid(),
196
            $redirectException->getDelay(),
197
            $redirectException->getStatusCode()
198
        );
199
    }
200
201
    /**
202
     * @param ControllerState $state
203
     */
204
    public function injectState(ControllerState $state)
205
    {
206
        $this->state = $state;
207
    }
208
}
209