Completed
Push — feature/middleware ( 180b74...67e214 )
by Romain
04:26
created

FormController::forwardToReferrer()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 29
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 29
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 15
nc 3
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\Middleware\Processor\MiddlewareProcessor;
21
use Romm\Formz\Middleware\Request\Exception\ForwardException;
22
use Romm\Formz\Middleware\Request\Exception\RedirectException;
23
use Romm\Formz\Middleware\Request\Exception\StopPropagationException;
24
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
25
use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
26
27
/**
28
 * This is the main form controller, it will be called between a request
29
 * dispatching and a controller action.
30
 *
31
 * It will process the current action being called, and analyze every parameter
32
 * of the method that is a form instance. For each form, all its registered
33
 * middlewares will be called, allowing manipulation of the request, the form
34
 * validation, and more.
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->forwardToReferrer();
67
                }
68
            } else {
69
                throw $exception;
70
            }
71
        }
72
73
        $this->continueRequest();
74
    }
75
76
    /**
77
     * @param FormObject $formObject
78
     */
79
    public function formObjectErrorAction(FormObject $formObject)
80
    {
81
        $this->view->assign('formObject', $formObject);
82
    }
83
84
    /**
85
     * Will fetch every form argument for this request, and dispatch every
86
     * middleware registered in its definition.
87
     */
88
    protected function invokeMiddlewares()
89
    {
90
        foreach ($this->processor->getRequestForms() as $formObject) {
91
            /** @var MiddlewareProcessor $middlewareProcessor */
92
            $middlewareProcessor = Core::instantiate(MiddlewareProcessor::class, $formObject, $this->processor);
93
94
            $middlewareProcessor->run();
95
        }
96
    }
97
98
    /**
99
     * Will check if the request result contains error; if errors are found, the
100
     * request is forwarded to the referring request, with the arguments of the
101
     * current request.
102
     */
103
    protected function manageRequestResult()
104
    {
105
        $result = $this->processor->getRequest()->getOriginalRequestMappingResults();
106
        $this->request->setOriginalRequestMappingResults($result);
107
108
        if ($result->hasErrors()) {
109
            $this->forwardToReferrer();
110
        }
111
    }
112
113
    /**
114
     * Forwards the request to the original request that led to this controller.
115
     *
116
     * @throws StopActionException
117
     */
118
    protected function continueRequest()
119
    {
120
        $this->request->setDispatched(false);
121
        $originalRequest = $this->processor->getRequest();
122
123
        $this->request->setPluginName($originalRequest->getPluginName());
124
        $this->request->setControllerVendorName($originalRequest->getControllerVendorName());
125
        $this->request->setControllerExtensionName($originalRequest->getControllerExtensionName());
126
        $this->request->setControllerName($originalRequest->getControllerName());
127
        $this->request->setControllerActionName($originalRequest->getControllerActionName());
128
        $this->request->setArguments($this->processor->getRequest()->getArguments());
129
130
        throw new StopActionException;
131
    }
132
133
    /**
134
     * Forwards to the referrer request. It will also fill the arguments of the
135
     * action with the ones from the source request.
136
     *
137
     * @throws StopActionException
138
     */
139
    protected function forwardToReferrer()
140
    {
141
        /*
142
         * If the original request is filled, a forward to referrer has already
143
         * been done.
144
         */
145
        if ($this->request->getOriginalRequest()) {
146
            return;
147
        }
148
149
        $referringRequest = $this->processor->getRequest()->getReferringRequest();
150
151
        if ($referringRequest) {
152
            $originalRequest = clone $this->request;
153
            $this->request->setDispatched(false);
154
155
            $this->request->setControllerVendorName($referringRequest->getControllerVendorName());
156
            $this->request->setControllerVendorName($referringRequest->getControllerVendorName());
157
            $this->request->setControllerExtensionName($referringRequest->getControllerExtensionName());
158
            $this->request->setControllerName($referringRequest->getControllerName());
159
            $this->request->setControllerActionName($referringRequest->getControllerActionName());
160
            $this->request->setOriginalRequest($originalRequest);
161
162
            throw new StopActionException;
163
        } else {
164
            // @todo
165
            // @see \TYPO3\CMS\Extbase\Mvc\Controller\ActionController::forwardToReferringRequest()
166
        }
167
    }
168
169
    /**
170
     * If an exception of type `RedirectException` was thrown, the request is
171
     * forwarded, using the arguments sent to the exception.
172
     *
173
     * @param RedirectException $redirectException
174
     */
175
    protected function redirectFromException(RedirectException $redirectException)
176
    {
177
        $this->uriBuilder->setRequest($this->processor->getRequest());
178
179
        $this->redirect(
180
            $redirectException->getActionName(),
181
            $redirectException->getControllerName(),
182
            $redirectException->getExtensionName(),
183
            $redirectException->getArguments(),
184
            $redirectException->getPageUid(),
185
            $redirectException->getDelay(),
186
            $redirectException->getStatusCode()
187
        );
188
    }
189
190
    /**
191
     * @param ControllerProcessor $processor
192
     */
193
    public function injectProcessor(ControllerProcessor $processor)
194
    {
195
        $this->processor = $processor;
196
    }
197
}
198