fix(12-05): match Laravel's in and not_in rules on array values
A 162-case truth table recorded from WinterCMS's validator (the vendored winter/storm Factory, Laravel 9) found three divergences, all on arrays: - in compared array elements loosely; Laravel uses array_diff, an exact string comparison, so ["1.0"] is not in 1,2; - not_in failed when any element was listed; Laravel's validateNotIn is !validateIn, so an array passes unless every element is listed; - not_in failed an array without the array rule; Laravel passes it. validate_rules_test.go keeps the whole table (accepted, array keys, boolean, numeric, integer, in/not_in, sizes by type, regex, dates and comparisons, url, presence, nested and map wildcards, bail and order).
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -700,6 +701,11 @@ func inList(s string, list []string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// validateIn is Laravel's validateIn. An array value needs the array rule
|
||||
// and no nested element, and then, like count(array_diff($value,
|
||||
// $parameters)) === 0, every element's string form must equal a parameter
|
||||
// exactly. A scalar compares like in_array((string) $value, $parameters),
|
||||
// where two numeric strings compare as numbers.
|
||||
func (v *requestValidator) validateIn(attr string, value any, params []string) bool {
|
||||
if _, isArr := arrayLen(value); isArr {
|
||||
if !v.hasRule(attr, "array") {
|
||||
@@ -709,8 +715,10 @@ func (v *requestValidator) validateIn(attr string, value any, params []string) b
|
||||
if _, nested := arrayLen(ch.value); nested {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for _, ch := range children(value) {
|
||||
s, ok := phpScalarString(ch.value)
|
||||
if !ok || !inList(s, params) {
|
||||
if !ok || !slices.Contains(params, s) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -720,21 +728,11 @@ func (v *requestValidator) validateIn(attr string, value any, params []string) b
|
||||
return ok && inList(s, params)
|
||||
}
|
||||
|
||||
// validateNotIn is Laravel's validateNotIn: the negation of validateIn, so
|
||||
// an array passes unless every element is listed, and an array without the
|
||||
// array rule always passes.
|
||||
func (v *requestValidator) validateNotIn(attr string, value any, params []string) bool {
|
||||
if _, isArr := arrayLen(value); isArr {
|
||||
if !v.hasRule(attr, "array") {
|
||||
return false
|
||||
}
|
||||
for _, ch := range children(value) {
|
||||
s, ok := phpScalarString(ch.value)
|
||||
if ok && inList(s, params) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
s, ok := phpScalarString(value)
|
||||
return ok && !inList(s, params)
|
||||
return !v.validateIn(attr, value, params)
|
||||
}
|
||||
|
||||
// exists is Laravel's exists:table,column presence check. It counts rows
|
||||
|
||||
Reference in New Issue
Block a user