Completed
Push — feature/version-2 ( 3ca533...64e802 )
by Romain
01:41
created

AbstractFormValidator::afterValidationProcess()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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