PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.13
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.13
6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 All 196 releases
fluentform / app / Services / Parser / Validations.php

Validations.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.13, at app/Services/Parser/Validations.php

270 lines 7.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentForm\App\Services\Parser;
4
5 use FluentForm\Framework\Helpers\ArrayHelper as Arr;
6
7 class Validations
8 {
9 /**
10 * Form fields that were defined when the form was created.
11 *
12 * @var array
13 */
14 protected $fields;
15
16 /**
17 * Form inputs that were submited by the user.
18 *
19 * @var array
20 */
21 protected $inputs;
22
23 /**
24 * The current field accessor of the fields' iteration.
25 *
26 * @var string
27 */
28 protected $accessor;
29
30 /**
31 * The repeater field settings. It is being set if the
32 * field in iteration is indeed a repeater field.
33 *
34 * @var array
35 */
36 protected $repeater = [
37 'status' => false,
38 'attribute' => '',
39 'length' => 0,
40 'rule' => ''
41 ];
42
43 /**
44 * The extracted validation rules.
45 *
46 * @var array
47 */
48 protected $rules = [];
49
50 /**
51 * The extracted validation messages.
52 *
53 * @var array
54 */
55 protected $messages = [];
56
57 /**
58 * Rules the validator has no method for.
59 *
60 * Selection limits are counted against the field's own options in
61 * Helper::validateSelectionLimits(), which runs later in the submission with
62 * the raw field settings in hand — the only place the configured (or global)
63 * message for the breach can be resolved. Emitting them here too would lean
64 * on the validator silently ignoring rules it does not recognise.
65 *
66 * @var array
67 */
68 protected $rulesHandledElsewhere = ['min_selection', 'max_selection'];
69
70 /**
71 * The validation extractor constructor.
72 *
73 * @param array $formFields
74 * @param array $formData
75 */
76 public function __construct($formFields = [], $formData = [])
77 {
78 $this->fields = $formFields;
79 $this->inputs = $formData;
80 }
81
82 /**
83 * Get the extracted validation rules and messages.
84 *
85 * @return array
86 */
87 public function get()
88 {
89 foreach ($this->fields as $fieldName => $field) {
90 $this->setFieldAccessor($fieldName);
91
92 $fieldValue = $this->getFieldValue();
93
94 $rules = (array) $field['rules'];
95
96 $hasRequiredRule = Arr::get($rules, 'required.value');
97
98 // If the field is a repeater we'll set some settings here.
99 $this->setRepeater($fieldName, $field);
100
101 foreach ($rules as $ruleName => $rule) {
102 if (in_array($ruleName, $this->rulesHandledElsewhere, true)) {
103 continue;
104 }
105
106 if ($this->shouldNotSkipThisRule($rule, $fieldValue, $hasRequiredRule)) {
107 $this->prepareValidations($fieldName, $ruleName, $rule);
108 }
109 }
110
111 $this->ensureStringTypeForSizeRules($fieldName, $rules);
112 }
113
114
115 return [$this->rules, $this->messages];
116 }
117
118 /**
119 * Set the field accessor by replacing the `[]`, `*` by `.`
120 * so that dot notation can be used to access the inputs.
121 *
122 * @param string $fieldName
123 * @return $this
124 */
125 protected function setFieldAccessor($fieldName)
126 {
127 $this->accessor = rtrim(str_replace(['[', ']', '*'], ['.'], $fieldName), '.');
128
129 return $this;
130 }
131
132 /**
133 * Get the field value from the form data.
134 *
135 * @return mixed
136 */
137 protected function getFieldValue()
138 {
139 return Arr::get($this->inputs, $this->accessor);
140 }
141
142 /**
143 * Set the repeater settings if the field in
144 * iteration is indeed a repeater field.
145 *
146 * @param string $fieldName
147 * @param array $field
148 * @return $this
149 */
150 protected function setRepeater($fieldName, $field)
151 {
152 $isRepeater = Arr::get($field, 'element') === 'input_repeat' || Arr::get($field, 'element') == 'repeater_field';
153
154 if ($isRepeater) {
155 $attribute = Arr::get($field, 'attributes.name');
156 $length = isset($attribute[0]) ? count($attribute[0]) : 0;
157 $this->repeater = [
158 'status' => true,
159 'attribute' => $attribute,
160 'length' => $length,
161 'rule' => rtrim($fieldName, '.*')
162 ];
163 } else {
164 $this->repeater['status'] = false;
165 }
166
167 return $this;
168 }
169
170 /**
171 * Determines if the iteration should skip this rule or not.
172 *
173 * @param array $rule
174 * @return boolean
175 */
176 protected function shouldNotSkipThisRule($rule, $fieldValue, $hasRequiredRule)
177 {
178 // If the rule is enabled and the field is not empty and
179 // it does have at least one required rule then we
180 // should validate it for other rules. Else, we
181 // will skip this rule meaning enabling empty
182 // submission for this field.
183 return $rule['value'] && !($fieldValue === '' && !$hasRequiredRule);
184 }
185
186 /**
187 * Prepare the validation extraction.
188 *
189 * @param string $fieldName
190 * @param string $ruleName
191 * @param array $rule
192 */
193 protected function prepareValidations($fieldName, $ruleName, $rule)
194 {
195 $logic = $this->getLogic($ruleName, $rule);
196
197 if ($this->repeater['status']) {
198 for ($i = 0; $i < $this->repeater['length']; $i++) {
199 // We need to modify the field name for repeater field.
200 $fieldName = $this->repeater['rule'].'['.$i.']';
201
202 $this->setValidations($fieldName, $ruleName, $rule, $logic);
203 }
204 } else {
205 $this->setValidations($fieldName, $ruleName, $rule, $logic);
206 }
207 }
208
209 /**
210 * Set the validation rules & messages
211 *
212 * @param string $fieldName
213 * @param string $ruleName
214 * @param array $rule
215 * @param string $logic
216 */
217 protected function setValidations($fieldName, $ruleName, $rule, $logic)
218 {
219 // if there is already a rule for this field we need to
220 // concat current rule to it. else assign current rule.
221 $this->rules[$fieldName] = isset($this->rules[$fieldName]) ?
222 $this->rules[$fieldName].'|'.$logic : $logic;
223
224 $this->messages[$fieldName.'.'.$ruleName] = $rule['message'];
225 }
226
227 /**
228 * Get the logic name for the current rule.
229 *
230 * @param string $ruleName
231 * @param array $rule
232 * @return string
233 */
234 protected function getLogic($ruleName, $rule)
235 {
236 // The file type input has rule values in an array. For
237 // that we are taking arrays into consideration.
238 $ruleValue = is_array($rule['value']) ?
239 implode(',', array_filter(array_values(str_replace('|', ',', $rule['value'])))) :
240 $rule['value'];
241
242 return $ruleName.':'.$ruleValue;
243 }
244
245 /**
246 * Ensure fields with max/min rules but no numeric rule
247 * are treated as strings for character-length validation.
248 *
249 * Without this, the WPFluent validator treats numeric-looking
250 * input (e.g. phone "123456") as a number and compares the
251 * numeric value against max/min instead of string length.
252 *
253 * @param string $fieldName
254 * @param array $rules
255 */
256 protected function ensureStringTypeForSizeRules($fieldName, $rules)
257 {
258 if (!isset($this->rules[$fieldName])) {
259 return;
260 }
261
262 $hasSizeRule = !empty($rules['max']['value']) || !empty($rules['min']['value']);
263 $hasNumericRule = !empty($rules['numeric']['value']);
264
265 if ($hasSizeRule && !$hasNumericRule && !is_array($this->getFieldValue())) {
266 $this->rules[$fieldName] = 'string|' . $this->rules[$fieldName];
267 }
268 }
269 }
270