Completed
Push — master ( 3e70d8...0fa5e9 )
by
unknown
03:54
created

FieldsValidationJavaScriptAssetHandler::handleValidationConfiguration()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
/*
3
 * 2016 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\AssetHandler\JavaScript;
15
16
use Romm\Formz\Configuration\Form\Field\Field;
17
use Romm\Formz\Configuration\Form\Field\Validation\Validation;
18
use Romm\Formz\Core\Core;
19
use Romm\Formz\Validation\Validator\AbstractValidator;
20
use TYPO3\CMS\Core\Utility\GeneralUtility;
21
22
/**
23
 * This asset handler generates the JavaScript code which will initialize the
24
 * validation rules for every field of the form.
25
 *
26
 * First, call the function `process()`, then:
27
 *  - To get the generated JavaScript code: `getJavaScriptCode()`.
28
 *  - To get the list of files which must be included in order to make the form
29
 *    run correctly: `getJavaScriptValidationFiles()`
30
 */
31
class FieldsValidationJavaScriptAssetHandler extends AbstractJavaScriptAssetHandler
32
{
33
34
    /**
35
     * @var string
36
     */
37
    protected $javaScriptCode;
38
39
    /**
40
     * @var array
41
     */
42
    protected $javaScriptValidationFiles = [];
43
44
    /**
45
     * Main function of this asset handler. See class description.
46
     *
47
     * @return $this
48
     */
49
    public function process()
50
    {
51
        $this->javaScriptValidationFiles = [];
52
        $fieldsJavaScriptCode = [];
53
        $formConfiguration = $this->getFormObject()->getConfiguration();
54
55
        foreach ($formConfiguration->getFields() as $field) {
56
            $fieldsJavaScriptCode[] = $this->processField($field);
57
        }
58
59
        $formName = GeneralUtility::quoteJSvalue($this->getFormObject()->getName());
60
        $fieldsJavaScriptCode = implode(CRLF, $fieldsJavaScriptCode);
61
62
        $this->javaScriptCode = <<<JS
63
(function() {
64
    Formz.Form.get(
65
        $formName,
66
        function(form) {
67
            var field = null;
68
69
$fieldsJavaScriptCode
70
        }
71
    );
72
})();
73
JS;
74
75
        return $this;
76
    }
77
78
    /**
79
     * Will run the process for the given field. You can get back the result
80
     * with the functions `getJavaScriptValidationFiles()` and
81
     * `getJavaScriptCode()`.
82
     *
83
     * @param Field $field
84
     * @return string
85
     */
86
    protected function processField($field)
87
    {
88
        $javaScriptCode = [];
89
        $fieldName = $field->getFieldName();
90
91
        foreach ($field->getValidation() as $validationName => $validationConfiguration) {
0 ignored issues
show
Bug introduced by
The expression $field->getValidation() of type object<Romm\Formz\Config...Validation\Validation>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
92
            /** @var AbstractValidator $validatorClassName */
93
            $validatorClassName = $validationConfiguration->getClassName();
94
95
            if (in_array(AbstractValidator::class, class_parents($validatorClassName))) {
96
                // Adding the validator JavaScript validation files to the list.
97
                $this->javaScriptValidationFiles = array_merge($this->javaScriptValidationFiles, $validatorClassName::getJavaScriptValidationFiles());
98
                $javaScriptCode[] = (string)$this->getInlineJavaScriptValidationCode($field, $validationName, $validationConfiguration);
99
            }
100
        }
101
102
        $javaScriptCode = implode(CRLF, $javaScriptCode);
103
        $javaScriptFieldName = GeneralUtility::quoteJSvalue($fieldName);
104
105
        return <<<JS
106
            /***************************
107
            * Field: "$fieldName"
108
            ****************************/
109
            field = form.getFieldByName($javaScriptFieldName);
110
111
            if (null !== field) {
112
$javaScriptCode
113
            }
114
115
JS;
116
    }
117
118
    /**
119
     * Generates the JavaScript code to add a validation rule to a field.
120
     *
121
     * @param Field      $field
122
     * @param string     $validationName         The name of the validation rule.
123
     * @param Validation $validatorConfiguration Contains the current validator configuration.
124
     * @return string
125
     */
126
    protected function getInlineJavaScriptValidationCode(Field $field, $validationName, Validation $validatorConfiguration)
127
    {
128
        $javaScriptValidationName = GeneralUtility::quoteJSvalue($validationName);
129
        $validatorName = addslashes($validatorConfiguration->getClassName());
130
        $validatorConfigurationFinal = $this->getValidationConfiguration($field, $validationName, $validatorConfiguration);
131
        $validatorConfigurationFinal = $this->handleValidationConfiguration($validatorConfigurationFinal);
132
133
        return <<<JS
134
                /*
135
                 * Validation rule "$validationName"
136
                 */
137
                field.addValidation($javaScriptValidationName, '$validatorName', $validatorConfigurationFinal);
138
139
JS;
140
    }
141
142
    /**
143
     * This function is here to help unit tests mocking.
144
     *
145
     * @param string $jsonValidationConfiguration
146
     * @return string
147
     */
148
    protected function handleValidationConfiguration($jsonValidationConfiguration)
149
    {
150
        return $jsonValidationConfiguration;
151
    }
152
153
    /**
154
     * Returns a JSON array containing the validation configuration needed by
155
     * JavaScript.
156
     *
157
     * @param Field      $field
158
     * @param string     $validationName
159
     * @param Validation $validatorConfiguration
160
     * @return string
161
     */
162
    protected function getValidationConfiguration(Field $field, $validationName, Validation $validatorConfiguration)
163
    {
164
        $acceptsEmptyValues = $this
165
            ->getDummyValidator()
166
            ->cloneValidator($validatorConfiguration->getClassName())
167
            ->acceptsEmptyValues();
168
169
        /** @var FormzLocalizationJavaScriptAssetHandler $formzLocalizationJavaScriptAssetHandler */
170
        $formzLocalizationJavaScriptAssetHandler = $this->assetHandlerFactory->getAssetHandler(FormzLocalizationJavaScriptAssetHandler::class);
171
172
        $messages = $formzLocalizationJavaScriptAssetHandler->getTranslationKeysForFieldValidation($field, $validationName);
173
174
        return Core::get()->arrayToJavaScriptJson([
175
            'options'            => $validatorConfiguration->getOptions(),
176
            'messages'           => $messages,
177
            'settings'           => $validatorConfiguration->toArray(),
178
            'acceptsEmptyValues' => $acceptsEmptyValues
179
        ]);
180
    }
181
182
    /**
183
     * @return string
184
     */
185
    public function getJavaScriptCode()
186
    {
187
        return (string)$this->javaScriptCode;
188
    }
189
190
    /**
191
     * @return array
192
     */
193
    public function getJavaScriptValidationFiles()
194
    {
195
        return array_unique($this->javaScriptValidationFiles);
196
    }
197
}
198