Skip to content

v1.31.0

Latest

Choose a tag to compare

@SanderMuller SanderMuller released this 04 Jul 21:24
Immutable release. Only release title and notes can be modified.

Two additions this release: the FluentSchema builder — an instance-based mirror
of the FluentRule factory that lets you drop the FluentRule:: prefix — and a fifth
automatic optimization, worker-global memoization of Laravel's rule-string parsing.
Both are backward-compatible; existing rules() methods and call sites are unchanged.

Added

  • FluentSchema builder. Define a schema(FluentSchema $rules) method on a form
    request and chain field starters off the injected $rules builder instead of
    repeating the FluentRule:: prefix on every line. When a request defines both
    schema() and rules(), schema() wins — detection keys off the
    FluentSchema-typed parameter, so an unrelated schema() method is never hijacked.
    For inline use, RuleSet::define(fn (FluentSchema $rules) => [...]) builds a
    RuleSet from the same builder. FluentSchema exposes typed delegates for every
    FluentRule factory (single source of truth on FluentRule) and forwards macros,
    and mirrors the schema(JsonSchema) shape Laravel's AI SDK uses for structured
    output.

  • MemoizingValidator. A Validator subclass that memoizes
    ValidationRuleParser::parse() for string rules in a bounded, worker-global static.
    Laravel re-parses each string rule on every internal probe — and, on a validator
    reused across array items, once per item; the memo collapses those repeats to a
    single hash lookup. OptimizedValidator now extends it, so the residual slow path
    of the optimized entry points (HasFluentRules, FluentValidator,
    RuleSet::validate(), HasFluentValidation) picks it up automatically. Output stays
    byte-identical to Laravel; only string rules are cached. The cache is soft-capped and
    reset on overflow, and holds only rule-string → parse-result pairs (never request
    data), so it stays Octane-safe.

Performance

  • Per-item slow-rule validation reuses parsed rules across an array.
    RuleSet::validate() and HasFluentRules route per-item slow-rule validators
    through MemoizingValidator, so a large array whose items fall through to Laravel
    (custom Rule objects, cross-field references) parses each rule string once for the
    whole array rather than re-parsing per item. The gain is largest on conditional-heavy
    and slow-rule-heavy payloads; simple fast-checkable arrays are unaffected — they
    already bypass Laravel entirely.
  • Custom validator resolvers are preserved. When an application registers a custom
    Validator::resolver(), the per-item path uses that validator unchanged, so any
    resolver-provided behaviour continues to apply.

Internal

  • Extracted the factory-state reflection copy shared by the optimized validator paths
    into ValidatorStateCopier, and taught it to carry wildcard implicitAttributes so
    nested-wildcard expansion metadata pairs with the copied rules.

What's Changed

  • chore(deps): bump actions/checkout from 6 to 7 by @dependabot[bot] in #18

Full Changelog: 1.30.1...1.31.0


Benchmark results

Scenario Optimizations Native Laravel Optimized Speedup
Product import — 500 items, simple rules Wildcard, fast-check 232.4ms 3.4ms ~69x
Nested order lines — 1000 orders × 5 line items Wildcard, fast-check (nested) 2885.6ms 21.9ms ~132x
Event scheduling — 100 items, field-ref dates Wildcard, partial fast-check 33.3ms 1.0ms ~32x
Article submission — 50 items, custom Rule objects Wildcard only 10.7ms 3.0ms ~4x
Conditional import — 100 items, 47 conditional fields Wildcard, pre-evaluation 3449.9ms 51.5ms ~67x
Login form — 3 fields, no wildcards Fast-check (flat) 0.2ms 0.0ms ~15x