Completed
Push — wip/steps ( 4fedf8...da6492 )
by Romain
02:41
created

FormController::processFormAction()   D

Complexity

Conditions 9
Paths 30

Size

Total Lines 32
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 32
rs 4.909
c 1
b 0
f 0
cc 9
eloc 21
nc 30
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 Throwable;
26
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
27
use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
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
     * Main action used to dispatch the request properly, depending on FormZ
46
     * configuration.
47
     *
48
     * The request is based on the previously called controller action, and is
49
     * used to list which forms are handled (every argument of the action method
50
     * that implements the interface `FormInterface`).
51
     *
52
     * Middlewares will be called for each form argument, and may modify the
53
     * request, which is then dispatched again with modified data.
54
     *
55
     * @throws Exception
56
     */
57
    public function processFormAction()
58
    {
59
        $exception = null;
60
61
        try {
62
            $this->invokeMiddlewares();
63
            $this->manageRequestResult();
64
        } catch (Exception $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
65
        } catch (Throwable $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
Bug introduced by
The class Throwable does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
66
        }
67
68
        $this->persistForms();
69
70
        if ($exception) {
71
            if ($exception instanceof StopPropagationException) {
72
                if ($exception instanceof RedirectException) {
73
                    $this->redirectFromException($exception);
74
                } elseif (false === $exception instanceof ForwardException) {
75
                    $this->resetSubstepsLevel();
76
                    $this->forwardToReferrer();
77
                }
78
            } elseif ($this->processor->hasExceptionCallback()
79
                && false === $exception instanceof StopActionException
80
            ) {
81
                call_user_func($this->processor->getExceptionCallback(), $exception);
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
     * @todo
114
     */
115
    protected function resetSubstepsLevel()
116
    {
117
        foreach ($this->processor->getRequestForms() as $formObject) {
118
            $stepService = FormObjectFactory::get()->getStepService($formObject);
119
            $stepService->setSubstepsLevel(1);
120
        }
121
    }
122
123
    /**
124
     * Will check if the request result contains error; if errors are found, the
125
     * request is forwarded to the referring request, with the arguments of the
126
     * current request.
127
     */
128
    protected function manageRequestResult()
129
    {
130
        $result = $this->processor->getRequest()->getOriginalRequestMappingResults();
131
        $this->request->setOriginalRequestMappingResults($result);
132
133
        if ($result->hasErrors()) {
134
            $this->forwardToReferrer();
135
        }
136
    }
137
138
    /**
139
     * Loops on every form of this request, and persists each one.
140
     */
141
    protected function persistForms()
142
    {
143
        foreach ($this->processor->getRequestForms() as $formObject) {
144
            if ($formObject->hasForm()
145
                && ($formObject->isPersistent()
146
                    || $formObject->formWasSubmitted()
147
                )
148
            ) {
149
                $formObject->getPersistenceManager()->save();
150
151
                if ($formObject->isPersistent()) {
152
                    $formObject->getFormMetadata()->persist();
153
                }
154
            }
155
        }
156
    }
157
158
    /**
159
     * Forwards the request to the original request that led to this controller.
160
     *
161
     * @throws StopActionException
162
     */
163
    protected function continueRequest()
164
    {
165
        $this->request->setDispatched(false);
166
        $request = $this->processor->getRequest();
167
168
        $this->request->setPluginName($request->getPluginName());
169
        $this->request->setControllerVendorName($request->getControllerVendorName());
170
        $this->request->setControllerExtensionName($request->getControllerExtensionName());
171
        $this->request->setControllerName($request->getControllerName());
172
        $this->request->setControllerActionName($request->getControllerActionName());
173
        $this->request->setArguments($this->processor->getRequest()->getArguments());
174
175
        throw new StopActionException;
176
    }
177
178
    /**
179
     * Forwards to the referrer request. It will also fill the arguments of the
180
     * action with the ones from the source request.
181
     *
182
     * @throws StopActionException
183
     */
184
    protected function forwardToReferrer()
185
    {
186
        $originalRequest = $this->processor->getRequest();
187
        $referringRequest = $originalRequest->getReferringRequest();
188
189
        if ($referringRequest) {
190
            $this->request->setDispatched(false);
191
192
            $this->request->setControllerVendorName($referringRequest->getControllerVendorName());
193
            $this->request->setControllerExtensionName($referringRequest->getControllerExtensionName());
194
            $this->request->setControllerName($referringRequest->getControllerName());
195
            $this->request->setControllerActionName($referringRequest->getControllerActionName());
196
            $this->request->setArguments($this->processor->getRequest()->getArguments());
197
            throw new StopActionException;
198
        } else {
199
            /**
200
             * @todo ?
201
             * @see \TYPO3\CMS\Extbase\Mvc\Controller\ActionController::forwardToReferringRequest()
202
             */
203
        }
204
205
    }
206
207
    /**
208
     * @param RedirectException $redirectException
209
     */
210
    protected function redirectFromException(RedirectException $redirectException)
211
    {
212
        $this->uriBuilder->setRequest($this->processor->getRequest());
213
214
        $this->redirect(
215
            $redirectException->getActionName(),
216
            $redirectException->getControllerName(),
217
            $redirectException->getExtensionName(),
218
            $redirectException->getArguments(),
219
            $redirectException->getPageUid(),
220
            $redirectException->getDelay(),
221
            $redirectException->getStatusCode()
222
        );
223
    }
224
225
    /**
226
     * @param ControllerProcessor $processor
227
     */
228
    public function injectProcessor(ControllerProcessor $processor)
229
    {
230
        $this->processor = $processor;
231
    }
232
}
233