Completed
Push — wip/steps ( 4a4cf9...a11a0b )
by Romain
02:37
created

FormController::forwardToReferrer()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 12
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\Controller\Processor\ControllerProcessor;
18
use Romm\Formz\Core\Core;
19
use Romm\Formz\Form\FormObject\FormObject;
20
use Romm\Formz\Form\FormObject\FormObjectFactory;
21
use Romm\Formz\Middleware\Processor\MiddlewareProcessor;
22
use Romm\Formz\Middleware\Request\Exception\ForwardException;
23
use Romm\Formz\Middleware\Request\Exception\RedirectException;
24
use Romm\Formz\Middleware\Request\Exception\StopPropagationException;
25
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
26
use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
27
use TYPO3\CMS\Extbase\Mvc\Web\Request;
28
29
/**
30
 * This is the main form controller, which is called before a controller action
31
 * with at least form argument is called.
32
 *
33
 * It will process the argument form(s), for instance by calling all its
34
 * middlewares. It allows manipulating the request, and information about the
35
 * form, before the actual action is called.
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
        $this->persistForms();
75
76
        if ($exception instanceof Exception) {
77
            if ($exception instanceof StopPropagationException) {
78
                if ($exception instanceof RedirectException) {
79
                    $this->redirectFromException($exception);
80
                } elseif (false === $exception instanceof ForwardException) {
81
                    $this->resetSubstepsLevel();
82
                    $this->forwardToReferrer();
83
                }
84
            } else {
85
                throw $exception;
86
            }
87
        }
88
89
        $this->continueRequest();
90
    }
91
92
    /**
93
     * @param FormObject $formObject
94
     */
95
    public function formObjectErrorAction(FormObject $formObject)
96
    {
97
        $this->view->assign('formObject', $formObject);
98
    }
99
100
    /**
101
     * Will fetch every form argument for this request, and dispatch every
102
     * middleware that was registered in its TypoScript configuration.
103
     */
104
    protected function invokeMiddlewares()
105
    {
106
        foreach ($this->processor->getRequestForms() as $formObject) {
107
            /** @var MiddlewareProcessor $middlewareProcessor */
108
            $middlewareProcessor = Core::instantiate(MiddlewareProcessor::class, $formObject, $this->processor);
109
110
            $middlewareProcessor->run();
111
        }
112
    }
113
114
    /**
115
     * @todo
116
     */
117
    protected function resetSubstepsLevel()
118
    {
119
        foreach ($this->processor->getRequestForms() as $formObject) {
120
            $stepService = FormObjectFactory::get()->getStepService($formObject);
121
            $stepService->setSubstepsLevel(1);
122
        }
123
    }
124
125
    /**
126
     * Will check if the request result contains error; if errors are found, the
127
     * request is forwarded to the referring request, with the arguments of the
128
     * current request.
129
     */
130
    protected function manageRequestResult()
131
    {
132
        $result = $this->processor->getRequest()->getOriginalRequestMappingResults();
133
        $this->request->setOriginalRequestMappingResults($result);
134
135
        if ($result->hasErrors()) {
136
            $this->forwardToReferrer();
137
        }
138
    }
139
140
    /**
141
     * Loops on every form of this request, and persists each one.
142
     */
143
    protected function persistForms()
144
    {
145
        foreach ($this->processor->getRequestForms() as $formObject) {
146
            if ($formObject->hasForm()
147
                && ($formObject->isPersistent()
148
                    || $formObject->formWasSubmitted()
149
                )
150
            ) {
151
                $formObject->getPersistenceManager()->save();
152
153
                if ($formObject->isPersistent()) {
154
                    $formObject->getFormMetadata()->persist();
155
                }
156
            }
157
        }
158
    }
159
160
    /**
161
     * Forwards the request to the original request that led to this controller.
162
     *
163
     * @throws StopActionException
164
     */
165
    protected function continueRequest()
166
    {
167
        $this->request->setDispatched(false);
168
        $request = $this->processor->getRequest();
169
170
        $this->request->setPluginName($request->getPluginName());
171
        $this->request->setControllerVendorName($request->getControllerVendorName());
172
        $this->request->setControllerExtensionName($request->getControllerExtensionName());
173
        $this->request->setControllerName($request->getControllerName());
174
        $this->request->setControllerActionName($request->getControllerActionName());
175
        $this->request->setArguments($this->processor->getRequest()->getArguments());
176
177
        throw new StopActionException;
178
    }
179
180
    /**
181
     * Forwards to the referrer request. It will also fill the arguments of the
182
     * action with the ones from the source request.
183
     *
184
     * @throws StopActionException
185
     */
186
    protected function forwardToReferrer()
187
    {
188
        $referringRequest = $this->originalRequest->getReferringRequest();
189
190
        if ($referringRequest) {
191
            $this->request->setDispatched(false);
192
            $this->request->setOriginalRequest($this->originalRequest);
193
194
            $this->request->setControllerVendorName($referringRequest->getControllerVendorName());
195
            $this->request->setControllerExtensionName($referringRequest->getControllerExtensionName());
196
            $this->request->setControllerName($referringRequest->getControllerName());
197
            $this->request->setControllerActionName($referringRequest->getControllerActionName());
198
            $this->request->setArguments($this->processor->getRequest()->getArguments());
199
        } else {
200
            // @todo ?
201
        }
202
203
        throw new StopActionException;
204
    }
205
206
    /**
207
     * @param RedirectException $redirectException
208
     */
209
    protected function redirectFromException(RedirectException $redirectException)
210
    {
211
        $this->uriBuilder->setRequest($this->processor->getRequest());
212
213
        $this->redirect(
214
            $redirectException->getActionName(),
215
            $redirectException->getControllerName(),
216
            $redirectException->getExtensionName(),
217
            $redirectException->getArguments(),
218
            $redirectException->getPageUid(),
219
            $redirectException->getDelay(),
220
            $redirectException->getStatusCode()
221
        );
222
    }
223
224
    /**
225
     * @param ControllerProcessor $processor
226
     */
227
    public function injectProcessor(ControllerProcessor $processor)
228
    {
229
        $this->processor = $processor;
230
    }
231
}
232