Completed
Push — tmp ( 61b6a8 )
by Romain
02:27
created

AbstractFormValidator::validateGhost()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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