Completed
Push — feature/middleware ( 864c18 )
by Romain
03:21
created

AbstractFormValidator::callAfterFieldValidationMethod()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 2
eloc 4
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\Validation\Validator\Form;
15
16
use Romm\Formz\Core\Core;
17
use Romm\Formz\Error\FormResult;
18
use Romm\Formz\Exceptions\InvalidArgumentTypeException;
19
use Romm\Formz\Form\Definition\Field\Field;
20
use Romm\Formz\Form\FormInterface;
21
use Romm\Formz\Form\FormObject\FormObject;
22
use Romm\Formz\Form\FormObject\FormObjectFactory;
23
use Romm\Formz\Form\FormObject\FormObjectProxy;
24
use Romm\Formz\Service\FormService;
25
use Romm\Formz\Validation\Validator\Form\DataObject\FormValidatorDataObject;
26
use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator as ExtbaseAbstractValidator;
27
28
/**
29
 * This is the abstract form validator, which must be inherited by any custom
30
 * form validator in order to work properly.
31
 *
32
 * Please note that a default form validator already exists if you need a form
33
 * which does not require any particular action: `DefaultFormValidator`.
34
 *
35
 * A form validator should be called to validate any form instance (which is a
36
 * child of `AbstractForm`). Usually, this is used in controller actions to
37
 * validate a form sent by the user. Example:
38
 *
39
 * /**
40
 *  * Action called when the Example form is submitted.
41
 *  *
42
 *  * @param $exForm
43
 *  * @validate $exForm Romm.Formz:Form\DefaultFormValidator
44
 *  * /
45
 *  public function submitFormAction(ExampleForm $exForm) { ... }
46
 *
47
 *******************************************************************************
48
 *
49
 * You may use you own custom form validator in order to be able to use the
50
 * following features:
51
 *
52
 * - Pre-validation custom process:
53
 *   By extending the method `beforeValidationProcess()`, you are able to handle
54
 *   anything you want just before the form validation begins to loop on every
55
 *   field. This can be used for instance to (de)activate the validation of
56
 *   certain fields under very specific circumstances.
57
 *
58
 * - In real time custom process:
59
 *   After each field went trough a validation process, a magic method is called
60
 *   to allow very low level custom process. The magic method name looks like:
61
 *   "{lowerCamelCaseFieldName}Validated". For instance, when the "email" field
62
 *   just went trough the validation process, the method `emailValidated()` is
63
 *   called.
64
 *
65
 * - Post-validation custom process:
66
 *   After the validation was done on every field of the form, this method is
67
 *   called to allow you high level process. For instance, let's assume your
68
 *   form is used to calculate a price estimation depending on information
69
 *   submitted in the form; when the form went trough the validation process and
70
 *   got no error, you can run the price estimation, and if any error occurs you
71
 *   are still able to add an error to `$this->result` (in a controller you do
72
 *   not have access to it anymore).
73
 */
74
abstract class AbstractFormValidator extends ExtbaseAbstractValidator implements FormValidatorInterface
75
{
76
    /**
77
     * @inheritdoc
78
     */
79
    protected $supportedOptions = [
80
        'name'  => ['', 'Name of the form.', 'string'],
81
        'dummy' => [false, 'Dummy mode?', 'bool']
82
    ];
83
84
    /**
85
     * @var FormResult
86
     */
87
    protected $result;
88
89
    /**
90
     * @var FormInterface
91
     */
92
    protected $form;
93
94
    /**
95
     * @var FormObject
96
     */
97
    protected $formObject;
98
99
    /**
100
     * @var FormValidatorExecutor
101
     */
102
    private $formValidatorExecutor;
103
104
    /**
105
     * @var FormValidatorDataObject
106
     */
107
    protected $dataObject;
108
109
    /**
110
     * Initializes all class variables.
111
     *
112
     * @param FormInterface $form
113
     * @throws InvalidArgumentTypeException
114
     */
115
    protected function initializeValidator($form)
116
    {
117
        if (false === $form instanceof FormInterface) {
118
            throw InvalidArgumentTypeException::validatingWrongFormType(get_class($form));
119
        }
120
121
        $this->form = $form;
122
        $this->formObject = $this->getFormObject();
123
        $this->formValidatorExecutor = $this->getFormValidatorExecutor();
124
        $this->result = $this->formObject->getFormResult();
125
126
        $this->getDataObject()->addFieldValidationCallback(function (Field $field) {
127
            $this->afterFieldValidation($field);
128
        });
129
    }
130
131
    /**
132
     * Checks the given form instance, and launches the validation if it is a
133
     * correct form.
134
     *
135
     * @param FormInterface $form The form instance to be validated.
136
     * @return FormResult
137
     */
138
    public function validate($form)
139
    {
140
        $this->initializeValidator($form);
141
142
        if (true !== $this->options['dummy']) {
143
            $proxy = $this->getProxy($form);
144
            $proxy->markFormAsValidated();
145
            $proxy->markFormAsSubmitted();
146
        }
147
148
        $this->isValid($form);
149
150
        return $this->result;
151
    }
152
153
    /**
154
     * Runs the whole validation workflow.
155
     *
156
     * @param FormInterface $form
157
     */
158
    final public function isValid($form)
159
    {
160
        $this->formValidatorExecutor->applyBehaviours();
161
        $this->formValidatorExecutor->checkFieldsActivation();
162
163
        $this->beforeValidationProcess();
164
165
        $this->formValidatorExecutor->validateFields();
166
167
        $this->afterValidationProcess();
168
169
        if ($this->result->hasErrors()) {
170
            // Storing the form for possible third party further usage.
171
            FormService::addFormWithErrors($form);
172
        }
173
    }
174
175
    /**
176
     * Override this function in your child class to handle some pre-validation
177
     * process.
178
     */
179
    protected function beforeValidationProcess()
180
    {
181
    }
182
183
    /**
184
     * Override this function in your child class to handle some post-validation
185
     * process.
186
     */
187
    protected function afterValidationProcess()
188
    {
189
    }
190
191
    /**
192
     * After each field has been validated, a matching method can be called if
193
     * it exists in the child class.
194
     *
195
     * The syntax is `{lowerCamelCaseFieldName}Validated()`.
196
     *
197
     * Example: for field `firstName` - `firstNameValidated()`.
198
     *
199
     * @param Field $field
200
     */
201
    protected function afterFieldValidation(Field $field)
202
    {
203
        $functionName = lcfirst($field->getName() . 'Validated');
204
205
        if (method_exists($this, $functionName)) {
206
            call_user_func([$this, $functionName]);
207
        }
208
    }
209
210
    /**
211
     * @return FormValidatorExecutor
212
     */
213
    protected function getFormValidatorExecutor()
214
    {
215
        /** @var FormValidatorExecutor $formValidatorExecutor */
216
        $formValidatorExecutor = Core::instantiate(FormValidatorExecutor::class, $this->formObject, $this->getDataObject());
217
218
        return $formValidatorExecutor;
219
    }
220
221
    /**
222
     * @return FormObject
223
     */
224
    protected function getFormObject()
225
    {
226
        return FormObjectFactory::get()->registerAndGetFormInstance($this->form, $this->options['name']);
227
    }
228
229
    /**
230
     * @param FormInterface $form
231
     * @return FormObjectProxy
232
     */
233
    protected function getProxy(FormInterface $form)
234
    {
235
        return FormObjectFactory::get()->getProxy($form);
236
    }
237
238
    /**
239
     * @return FormValidatorDataObject
240
     */
241
    public function getDataObject()
242
    {
243
        if (null === $this->dataObject) {
244
            $this->dataObject = Core::instantiate(FormValidatorDataObject::class);
245
        }
246
247
        return $this->dataObject;
248
    }
249
}
250