Completed
Push — middleware-wip ( 357c0d...3d734d )
by Romain
02:39
created

FormController::processFormAction()   A

Complexity

Conditions 4
Paths 7

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 0
loc 20
rs 9.2
c 2
b 0
f 0
cc 4
eloc 13
nc 7
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 Romm\Formz\Core\Core;
17
use Romm\Formz\Form\FormObject;
18
use Romm\Formz\Middleware\Request\Exception\ForwardException;
19
use Romm\Formz\Middleware\Request\Exception\RedirectException;
20
use Romm\Formz\Middleware\Request\Exception\StopPropagationException;
21
use Romm\Formz\Middleware\State\MiddlewareState;
22
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
23
use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
24
use TYPO3\CMS\Extbase\Mvc\Web\Request;
25
use TYPO3\CMS\Extbase\Security\Cryptography\HashService;
26
27
/**
28
 * This is the main form controller, which is called before a controller action
29
 * with at least form argument is called.
30
 *
31
 * It will process the argument form(s), for instance by calling all its
32
 * middlewares. It allows manipulating the request, and information about the
33
 * form, before the actual action is called.
34
 */
35
class FormController extends ActionController
36
{
37
    /**
38
     * @var ControllerState
39
     */
40
    protected $state;
41
42
    /**
43
     * @var Request
44
     */
45
    protected $originalRequest;
46
47
    /**
48
     * Main action used to dispatch the request properly, depending on FormZ
49
     * configuration.
50
     *
51
     * The request is based on the previously called controller action, and is
52
     * used to list which forms are handled (every argument of the action method
53
     * that implements the interface `FormInterface`).
54
     *
55
     * Middlewares will be called for each form argument, and may modify the
56
     * request, which is then dispatched again with modified data.
57
     *
58
     * @param Request $originalRequest
59
     */
60
    public function processFormAction(Request $originalRequest)
61
    {
62
        $tt = new \TYPO3\CMS\Core\TimeTracker\TimeTracker();
63
        $tt->start();
64
65
        $this->originalRequest = $originalRequest;
66
67
        try {
68
            $this->invokeMiddlewares();
69
            $this->manageRequestResult();
70
        } catch (StopPropagationException $exception) {
71
            if ($exception instanceof RedirectException) {
72
                $this->redirectFromException($exception);
73
            } elseif (false === $exception instanceof ForwardException) {
74
                $this->forwardToReferrer();
75
            }
76
        }
77
78
        $this->continueRequest();
79
    }
80
81
    /**
82
     * @param FormObject $formObject
83
     */
84
    public function formObjectErrorAction(FormObject $formObject)
85
    {
86
        $this->view->assign('formObject', $formObject);
87
    }
88
89
    /**
90
     * Will fetch every form argument for this request, and dispatch every
91
     * middleware that was registered in its TypoScript configuration.
92
     */
93
    protected function invokeMiddlewares()
94
    {
95
        foreach ($this->state->getRequestForms() as $formObject) {
96
            $formObject->reset();
97
98
            /** @var MiddlewareState $middlewareState */
99
            $middlewareState = Core::instantiate(MiddlewareState::class, $formObject, $this->state);
100
101
            $middlewareState->run();
102
        }
103
    }
104
105
    /**
106
     * Will check if the request result contains error; if errors are found, the
107
     * request is forwarded to the referring request, with the arguments of the
108
     * current request.
109
     */
110
    protected function manageRequestResult()
111
    {
112
        $result = $this->state->getRequest()->getOriginalRequestMappingResults();
113
        $this->request->setOriginalRequestMappingResults($result);
114
115
        if ($result->hasErrors()) {
116
            $this->forwardToReferrer();
117
        }
118
    }
119
120
    /**
121
     * Forwards the request to the original request that led to this controller.
122
     *
123
     * @throws StopActionException
124
     */
125
    protected function continueRequest()
126
    {
127
        $this->request->setDispatched(false);
128
129
        $this->request->setPluginName($this->originalRequest->getPluginName());
130
        $this->request->setControllerVendorName($this->originalRequest->getControllerVendorName());
131
        $this->request->setControllerExtensionName($this->originalRequest->getControllerExtensionName());
132
        $this->request->setControllerName($this->originalRequest->getControllerName());
133
        $this->request->setControllerActionName($this->originalRequest->getControllerActionName());
134
        $this->request->setArguments($this->state->getRequest()->getArguments());
135
136
        throw new StopActionException;
137
    }
138
139
    /**
140
     * Forwards to the referrer request. It will also fill the arguments of the
141
     * action with the ones from the source request.
142
     *
143
     * @throws StopActionException
144
     */
145
    protected function forwardToReferrer()
146
    {
147
        $referringRequest = $this->originalRequest->getReferringRequest();
148
149
        if ($referringRequest) {
150
            $this->request->setDispatched(false);
151
            $this->request->setOriginalRequest($this->originalRequest);
152
153
            $this->request->setControllerVendorName($referringRequest->getControllerVendorName());
154
            $this->request->setControllerExtensionName($referringRequest->getControllerExtensionName());
155
            $this->request->setControllerName($referringRequest->getControllerName());
156
            $this->request->setControllerActionName($referringRequest->getControllerActionName());
157
            $this->request->setArguments($this->state->getRequest()->getArguments());
158
        } else {
159
            // @todo ?
160
        }
161
162
        throw new StopActionException;
163
    }
164
165
    /**
166
     * @param RedirectException $redirectException
167
     */
168
    protected function redirectFromException(RedirectException $redirectException)
169
    {
170
        $this->redirect(
171
            $redirectException->getActionName(),
172
            $redirectException->getControllerName(),
173
            $redirectException->getExtensionName(),
174
            $redirectException->getArguments(),
175
            $redirectException->getPageUid(),
176
            $redirectException->getDelay(),
177
            $redirectException->getStatusCode()
178
        );
179
    }
180
181
    /**
182
     * @param ControllerState $state
183
     */
184
    public function injectState(ControllerState $state)
185
    {
186
        $this->state = $state;
187
    }
188
}
189