Completed
Push — middleware-wip ( 81ef54...a98a67 )
by Romain
03:50
created

FormController::checkFormSubmission()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 10
nc 2
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\FormInterface;
18
use Romm\Formz\Form\FormObject;
19
use Romm\Formz\Form\FormObjectFactory;
20
use Romm\Formz\Middleware\State\MiddlewareState;
21
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
22
use TYPO3\CMS\Extbase\Mvc\Controller\Argument;
23
use TYPO3\CMS\Extbase\Property\PropertyMapper;
24
use TYPO3\CMS\Extbase\Security\Cryptography\HashService;
25
26
class FormController extends ActionController
27
{
28
    /**
29
     * @var FormObject[]
30
     */
31
    protected $formArguments = [];
32
33
    /**
34
     * @var FormzControllerContext
35
     */
36
    protected $formzControllerContext;
37
38
    /**
39
     * @var HashService
40
     */
41
    protected $hashService;
42
43
    /**
44
     * @var FormObjectFactory
45
     */
46
    protected $formObjectFactory;
47
48
    /**
49
     * Main action used to dispatch the request properly, depending on FormZ
50
     * configuration.
51
     *
52
     * The request is based on the previously called controller action, and is
53
     * used to list which forms are handled (every argument of the action method
54
     * that implements the interface `FormInterface`).
55
     *
56
     * Middlewares will be called for each form argument, and may modify the
57
     * request, which is then dispatched again with modified data.
58
     */
59
    public function processFormAction()
60
    {
61
        $tt = new \TYPO3\CMS\Core\TimeTracker\TimeTracker();
62
        $tt->start();
63
64
        $request = $this->formzControllerContext->getRequest();
65
66
        $this->invokeMiddlewares();
67
68
        $this->formzControllerContext->setDispatched(true);
69
70
        $result = $request->getOriginalRequestMappingResults();
71
        $this->controllerContext->getRequest()->setOriginalRequestMappingResults($result);
72
73
        if ($result->hasErrors()) {
74
            $arguments = $request->getArguments();
75
            $request = $request->getReferringRequest();
76
77
            foreach ($arguments as $name => $value) {
78
                /** @var Argument $argument */
79
                $request->setArgument($name, $value);
80
            }
81
        }
82
83
        $this->forward(
84
            $request->getControllerActionName(),
85
            $request->getControllerName(),
86
            $request->getControllerExtensionName(),
87
            $request->getArguments()
88
        );
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->getRequestForms() as $formObject) {
98
            $formObject->reset();
99
            $this->checkFormSubmission($formObject);
100
101
            /*
102
             * If the configuration contains errors, then the middlewares
103
             * configuration may be corrupted as well, so the risk to dispatch
104
             * middlewares can not be taken.
105
             */
106
            if (false === $formObject->getConfigurationValidationResult()->hasErrors()) {
107
                /** @var MiddlewareState $middlewareFactory */
108
                $middlewareFactory = Core::instantiate(MiddlewareState::class, $formObject, $this->formzControllerContext);
109
110
                $middlewareFactory->run();
111
            }
112
        }
113
    }
114
115
    /**
116
     * Will check if the given form was submitted by the user. If it is found,
117
     * the form instance is injected in the form object.
118
     *
119
     * @param FormObject $formObject
120
     */
121
    protected function checkFormSubmission(FormObject $formObject)
122
    {
123
        $request = $this->formzControllerContext->getRequest();
124
        $formName = $formObject->getName();
125
126
        if ($request->getMethod() === 'POST'
127
            && $request->hasArgument($formName)
128
        ) {
129
            $formArray = $request->getArgument($formName);
130
            $argument = $this->formzControllerContext->getArguments()->getArgument($formName);
131
            $form = $argument->setValue($formArray)->getValue();
132
133
            $formObject->setForm($form);
134
            $formObject->markFormAsSubmitted();
135
        }
136
    }
137
138
    /**
139
     * @return FormObject[]
140
     */
141
    protected function getRequestForms()
142
    {
143
        if (empty($this->formArguments)) {
144
            /** @var Argument $argument */
145
            foreach ($this->formzControllerContext->getArguments() as $argument) {
146
                $type = $argument->getDataType();
147
148
                if (class_exists($type)
149
                    && in_array(FormInterface::class, class_implements($type))
150
                ) {
151
                    $formClassName = $argument->getDataType();
152
                    $formName = $argument->getName();
153
154
                    $formObject = $this->formObjectFactory->getInstanceFromClassName($formClassName, $formName);
155
                    $this->formArguments[$formName] = $formObject;
156
                }
157
            }
158
        }
159
160
        return $this->formArguments;
161
    }
162
163
    protected function aze()
164
    {
165
        $arguments = $this->formzControllerContext->getArguments();
166
167
        foreach ($arguments as $argument) {
168
            /** @var Argument $argument */
169
            if ($this->request->hasArgument($argument->getName())
170
                && true === class_exists($argument->getDataType())
171
                && true === in_array(FormInterface::class, class_implements($argument->getDataType()))
172
            ) {
173
                /** @var PropertyMapper $propertyMapper */
174
                $propertyMapper = Core::instantiate(PropertyMapper::class);
175
                $form = $propertyMapper->convert(
176
                    $this->request->getArgument($argument->getName()),
177
                    $argument->getDataType()
178
                );
179
                break;
180
            }
181
        }
182
183
        return $form;
0 ignored issues
show
Bug introduced by
The variable $form does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
184
    }
185
186
    /**
187
     * @todo
188
     *
189
     * @return array
190
     */
191
    protected function getRequestData()
192
    {
193
        $requestData = [];
194
195
        if ($this->request->hasArgument('formz')) {
196
            $requestData = $this->request->getArgument('formz');
197
            $requestData = $this->hashService->validateAndStripHmac($requestData);
198
            $requestData = unserialize(base64_decode($requestData));
199
        }
200
201
        return $requestData;
202
    }
203
204
    /**
205
     * @param FormzControllerContext $formzControllerContext
206
     */
207
    public function injectFormzControllerContext(FormzControllerContext $formzControllerContext)
208
    {
209
        $this->formzControllerContext = $formzControllerContext;
210
    }
211
212
    /**
213
     * @param HashService $hashService
214
     */
215
    public function injectHashService(HashService $hashService)
216
    {
217
        $this->hashService = $hashService;
218
    }
219
220
    /**
221
     * @param FormObjectFactory $formObjectFactory
222
     */
223
    public function injectFormObjectFactory(FormObjectFactory $formObjectFactory)
224
    {
225
        $this->formObjectFactory = $formObjectFactory;
226
    }
227
}
228