Skip to content

v1.30.1

Latest

Choose a tag to compare

@SanderMuller SanderMuller released this 18 Jun 15:24
· 2 commits to main since this release
Immutable release. Only release title and notes can be modified.
7e97746

Closes the gap between the optimized validation paths and native Laravel on
conditional rules, and — most importantly — makes 1.30.0's conditional
pre-evaluation actually reach the fluent ->excludeUnless() API. All five fixes
are pinned to native Laravel by parity tests. Surfaced from a production
JSON-import use case profiling large conditional wildcard arrays.

Performance

Fluent ->excludeUnless() / ->excludeIf() now pre-evaluate

1.30.0 added conditional pre-evaluation but only recognised the array-tuple rule
form ([['exclude_unless', 'items.*.type', 'chapter'], …]). The fluent
->excludeUnless() API — and any plain string rule — compiles to the string
form (exclude_unless:items.*.type,chapter), which the three pre-evaluation
sites skipped, so an excludeUnless-heavy ruleset stayed fully expanded and
quadratic. A shared extractor now parses tuple, string, and pipe-joined forms,
so the optimization reaches the idiomatic API and nested children() rules
keyed off the parent item's wildcard type. On a 100-item, 20-conditional-field
import this turns a quadratic curve linear.

Fixed

Conditional dependent-value coercion matches native

exclude_unless/exclude_if (and required_if/required_unless on the
per-item path) compared the dependent value with a string cast, diverging from
Laravel when the value needed coercion. A shared matcher now reproduces
Laravel's rules: a null dependent against null, a boolean-declared
dependent submitted as the raw string '0'/'1' against true/false, and
numeric-string loose matching. Verdicts and the validated() payload now match
native across the tuple, string, fluent, and enum-valued forms.

exclude_if is inactive when its dependent field is absent

Mirroring native Laravel's existence short-circuit, exclude_if no longer
excludes a field when the referenced dependent key is missing from the payload
(an explicitly null dependent still excludes). Previously a missing dependent
could silently drop a field and suppress its validation.

Regex rules containing a pipe survive compilation

A regex:/^(foo|bar)$/ rule written through the fluent API was corrupted when
the compiled rules were pipe-joined into a single string (Laravel's parser then
split the pattern on its |). Compilation now keeps the array form whenever a
rule token contains a literal |, so the pattern reaches Laravel intact.

Every exclude condition on a field is evaluated

A field carrying more than one exclude_* rule had only its first condition
honoured on the per-item path; all of them are now evaluated (the field is
excluded if any fires), matching native. Tuple-form required_if /
required_unless on a field that also carries an exclude rule are no longer
dropped during exclude reduction.

Internal

  • Extracted two shared collaborators — ConditionalValueMatcher (Laravel-parity
    dependent-value coercion) and ExcludeConditionExtractor (tuple/string form
    recognition) — so preExcludeRules, ConditionalEvaluationPhase, and
    ItemRuleCompiler evaluate conditionals identically.
  • Added parity regression tests covering the coercion grid, string-form pruning
    (flat, nested children, enum values), regex-with-pipe, the existence guard,
    and multi-condition / required-tuple survival.

Full Changelog: 1.30.0...1.30.1


Benchmark results

Scenario Optimizations Native Laravel Optimized Speedup
Product import — 500 items, simple rules Wildcard, fast-check 224.9ms 3.2ms ~69x
Nested order lines — 1000 orders × 5 line items Wildcard, fast-check (nested) 2839.9ms 18.2ms ~156x
Event scheduling — 100 items, field-ref dates Wildcard, partial fast-check 32.2ms 1.0ms ~32x
Article submission — 50 items, custom Rule objects Wildcard only 10.4ms 3.3ms ~3x
Conditional import — 100 items, 47 conditional fields Wildcard, pre-evaluation 3606.6ms 70.2ms ~51x
Login form — 3 fields, no wildcards Fast-check (flat) 0.2ms 0.0ms ~16x