Completed
Push — wip/steps ( a8ec08...593c83 )
by Romain
02:14
created

FormController::manageRequestResult()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
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\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
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
     * Main action used to dispatch the request properly, depending on FormZ
45
     * configuration.
46
     *
47
     * The request is based on the previously called controller action, and is
48
     * used to list which forms are handled (every argument of the action method
49
     * that implements the interface `FormInterface`).
50
     *
51
     * Middlewares will be called for each form argument, and may modify the
52
     * request, which is then dispatched again with modified data.
53
     *
54
     * @throws Exception
55
     */
56
    public function processFormAction()
57
    {
58
        try {
59
            $this->invokeMiddlewares();
60
            $this->manageRequestResult();
61
        } catch (Exception $exception) {
62
            if ($exception instanceof StopPropagationException) {
63
                if ($exception instanceof RedirectException) {
64
                    $this->redirectFromException($exception);
65
                } elseif (false === $exception instanceof ForwardException) {
66
                    $this->resetSubstepsLevel();
67
                    $this->forwardToReferrer();
68
                }
69
            } elseif ($this->processor->hasExceptionCallback()
70
                && false === $exception instanceof StopActionException
71
            ) {
72
                call_user_func($this->processor->getExceptionCallback(), $exception);
73
            } else {
74
                throw $exception;
75
            }
76
        } finally {
77
            $this->persistForms();
78
        }
79
80
        $this->continueRequest();
81
    }
82
83
    /**
84
     * @param FormObject $formObject
85
     */
86
    public function formObjectErrorAction(FormObject $formObject)
87
    {
88
        $this->view->assign('formObject', $formObject);
89
    }
90
91
    /**
92
     * Will fetch every form argument for this request, and dispatch every
93
     * middleware that was registered in its TypoScript configuration.
94
     */
95
    protected function invokeMiddlewares()
96
    {
97
        foreach ($this->processor->getRequestForms() as $formObject) {
98
            /** @var MiddlewareProcessor $middlewareProcessor */
99
            $middlewareProcessor = Core::instantiate(MiddlewareProcessor::class, $formObject, $this->processor);
100
101
            $middlewareProcessor->run();
102
        }
103
    }
104
105
    /**
106
     * @todo
107
     */
108
    protected function resetSubstepsLevel()
109
    {
110
        foreach ($this->processor->getRequestForms() as $formObject) {
111
            $stepService = FormObjectFactory::get()->getStepService($formObject);
112
            $stepService->setSubstepsLevel(1);
113
        }
114
    }
115
116
    /**
117
     * Will check if the request result contains error; if errors are found, the
118
     * request is forwarded to the referring request, with the arguments of the
119
     * current request.
120
     */
121
    protected function manageRequestResult()
122
    {
123
        $result = $this->processor->getRequest()->getOriginalRequestMappingResults();
124
        $this->request->setOriginalRequestMappingResults($result);
125
126
        if ($result->hasErrors()) {
127
            $this->forwardToReferrer();
128
        }
129
    }
130
131
    /**
132
     * Loops on every form of this request, and persists each one.
133
     */
134
    protected function persistForms()
135
    {
136
        foreach ($this->processor->getRequestForms() as $formObject) {
137
            if ($formObject->hasForm()
138
                && ($formObject->isPersistent()
139
                    || $formObject->formWasSubmitted()
140
                )
141
            ) {
142
                $formObject->getPersistenceManager()->save();
143
144
                if ($formObject->isPersistent()) {
145
                    $formObject->getFormMetadata()->persist();
146
                }
147
            }
148
        }
149
    }
150
151
    /**
152
     * Forwards the request to the original request that led to this controller.
153
     *
154
     * @throws StopActionException
155
     */
156
    protected function continueRequest()
157
    {
158
        $this->request->setDispatched(false);
159
        $request = $this->processor->getRequest();
160
161
        $this->request->setPluginName($request->getPluginName());
162
        $this->request->setControllerVendorName($request->getControllerVendorName());
163
        $this->request->setControllerExtensionName($request->getControllerExtensionName());
164
        $this->request->setControllerName($request->getControllerName());
165
        $this->request->setControllerActionName($request->getControllerActionName());
166
        $this->request->setArguments($this->processor->getRequest()->getArguments());
167
168
        throw new StopActionException;
169
    }
170
171
    /**
172
     * Forwards to the referrer request. It will also fill the arguments of the
173
     * action with the ones from the source request.
174
     *
175
     * @throws StopActionException
176
     */
177
    protected function forwardToReferrer()
178
    {
179
        /*
180
         * If the original request is filled, a forward to referrer has already
181
         * been done.
182
         */
183
        if ($this->request->getOriginalRequest()) {
184
            return;
185
        }
186
187
        $referringRequest = $this->processor->getRequest()->getReferringRequest();
188
189
        if ($referringRequest) {
190
            $originalRequest = clone $this->request;
191
            $this->request->setDispatched(false);
192
193
            $this->request->setControllerVendorName($referringRequest->getControllerVendorName());
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->setOriginalRequest($originalRequest);
199
            throw new StopActionException;
200
        } else {
201
            /**
202
             * @todo ?
203
             * @see \TYPO3\CMS\Extbase\Mvc\Controller\ActionController::forwardToReferringRequest()
204
             */
205
        }
206
207
    }
208
209
    /**
210
     * @param RedirectException $redirectException
211
     */
212
    protected function redirectFromException(RedirectException $redirectException)
213
    {
214
        $this->uriBuilder->setRequest($this->processor->getRequest());
215
216
        $this->redirect(
217
            $redirectException->getActionName(),
218
            $redirectException->getControllerName(),
219
            $redirectException->getExtensionName(),
220
            $redirectException->getArguments(),
221
            $redirectException->getPageUid(),
222
            $redirectException->getDelay(),
223
            $redirectException->getStatusCode()
224
        );
225
    }
226
227
    /**
228
     * @param ControllerProcessor $processor
229
     */
230
    public function injectProcessor(ControllerProcessor $processor)
231
    {
232
        $this->processor = $processor;
233
    }
234
}
235