Completed
Push — middleware-wip ( a395c5...d52214 )
by Romain
03:54
created

FormController::injectProcessor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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