| @@ -1,9 +1,8 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | |
| 3 | 3 | namespace FluentForm\App\Services\Parser; |
| 4 | 4 | |
| 5 | -use FluentForm\App\Services\ConditionAssesor; | |
| 6 | 5 | use FluentForm\Framework\Helpers\ArrayHelper as Arr; |
| 7 | 6 | |
| 8 | 7 | class Validations |
| 9 | 8 | { |
| @@ -55,8 +54,21 @@ | ||
| 55 | 54 | */ |
| 56 | 55 | protected $messages = []; |
| 57 | 56 | |
| 58 | 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 | + /** | |
| 59 | 71 | * The validation extractor constructor. |
| 60 | 72 | * |
| 61 | 73 | * @param array $formFields |
| 62 | 74 | * @param array $formData |
| @@ -74,30 +86,30 @@ | ||
| 74 | 86 | */ |
| 75 | 87 | public function get() |
| 76 | 88 | { |
| 77 | 89 | foreach ($this->fields as $fieldName => $field) { |
| 78 | - /* | |
| 79 | - * todo: isApplicable has some issue for radio / checkbox $applicable getting false | |
| 80 | - * even it's required! | |
| 81 | - */ | |
| 82 | - $applicable = $this->setFieldAccessor($fieldName)->isApplicable($field); | |
| 90 | + $this->setFieldAccessor($fieldName); | |
| 83 | 91 | |
| 84 | - if ($applicable) { | |
| 85 | - $fieldValue = $this->getFieldValue(); | |
| 92 | + $fieldValue = $this->getFieldValue(); | |
| 86 | 93 | |
| 87 | - $rules = (array) $field['rules']; | |
| 94 | + $rules = (array) $field['rules']; | |
| 88 | 95 | |
| 89 | - $hasRequiredRule = Arr::get($rules, 'required.value'); | |
| 96 | + $hasRequiredRule = Arr::get($rules, 'required.value'); | |
| 90 | 97 | |
| 91 | - // If the field is a repeater we'll set some settings here. | |
| 92 | - $this->setRepeater($fieldName, $field); | |
| 98 | + // If the field is a repeater we'll set some settings here. | |
| 99 | + $this->setRepeater($fieldName, $field); | |
| 93 | 100 | |
| 94 | - foreach ($rules as $ruleName => $rule) { | |
| 95 | - if ($this->shouldNotSkipThisRule($rule, $fieldValue, $hasRequiredRule)) { | |
| 96 | - $this->prepareValidations($fieldName, $ruleName, $rule); | |
| 97 | - } | |
| 101 | + foreach ($rules as $ruleName => $rule) { | |
| 102 | + if (in_array($ruleName, $this->rulesHandledElsewhere, true)) { | |
| 103 | + continue; | |
| 98 | 104 | } |
| 105 | + | |
| 106 | + if ($this->shouldNotSkipThisRule($rule, $fieldValue, $hasRequiredRule)) { | |
| 107 | + $this->prepareValidations($fieldName, $ruleName, $rule); | |
| 108 | + } | |
| 99 | 109 | } |
| 110 | + | |
| 111 | + $this->ensureStringTypeForSizeRules($fieldName, $rules); | |
| 100 | 112 | } |
| 101 | 113 | |
| 102 | 114 | |
| 103 | 115 | return [$this->rules, $this->messages]; |
| @@ -117,29 +129,8 @@ | ||
| 117 | 129 | return $this; |
| 118 | 130 | } |
| 119 | 131 | |
| 120 | 132 | /** |
| 121 | - * Determines if the field is applicable for extracting validations. | |
| 122 | - * | |
| 123 | - * @param array $field | |
| 124 | - * @return boolean | |
| 125 | - */ | |
| 126 | - protected function isApplicable($field) | |
| 127 | - { | |
| 128 | - // We need to evaluate if this field should be used to validate | |
| 129 | - // the form data because it's possible that this field ain't | |
| 130 | - // even present in the form data or it has conditional | |
| 131 | - // logics that dictates it's presence in the rules. | |
| 132 | - | |
| 133 | - // NOTE: Previous code by Arif | |
| 134 | - return Arr::has( | |
| 135 | - $this->inputs, $this->accessor | |
| 136 | - ) && ConditionAssesor::evaluate( | |
| 137 | - $field, $this->inputs | |
| 138 | - ); | |
| 139 | - } | |
| 140 | - | |
| 141 | - /** | |
| 142 | 133 | * Get the field value from the form data. |
| 143 | 134 | * |
| 144 | 135 | * @return mixed |
| 145 | 136 | */ |
| @@ -163,15 +154,15 @@ | ||
| 163 | 154 | if ($isRepeater) { |
| 164 | 155 | $attribute = Arr::get($field, 'attributes.name'); |
| 165 | 156 | $length = isset($attribute[0]) ? count($attribute[0]) : 0; |
| 166 | 157 | $this->repeater = [ |
| 167 | - 'status' => $isRepeater, | |
| 158 | + 'status' => true, | |
| 168 | 159 | 'attribute' => $attribute, |
| 169 | 160 | 'length' => $length, |
| 170 | 161 | 'rule' => rtrim($fieldName, '.*') |
| 171 | 162 | ]; |
| 172 | 163 | } else { |
| 173 | - $this->repeater['status'] = $isRepeater; | |
| 164 | + $this->repeater['status'] = false; | |
| 174 | 165 | } |
| 175 | 166 | |
| 176 | 167 | return $this; |
| 177 | 168 | } |
| @@ -248,6 +239,31 @@ | ||
| 248 | 239 | implode(',', array_filter(array_values(str_replace('|', ',', $rule['value'])))) : |
| 249 | 240 | $rule['value']; |
| 250 | 241 | |
| 251 | 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 | + } | |
| 252 | 268 | } |
| 253 | 269 | } |