Laravel Tutorials

Fluent Rule Builders for All Laravel Validation Rules

Published
Fluent Rule Builders for All Laravel Validation Rules image

Many Laravel validation rules are written as strings, with parameters after a colon split by commas. A rule like required_without:email works, but your editor cannot autocomplete it, and a misspelled rule name only fails when the validator runs.

The Rule class already had builders for rules like in, unique, exists, enum, date, email, and file. Laravel 13.36 adds one for every rule that was still string-only.

Before and After

Here is a profile form validated with string rules:

$request->validate([
'email' => 'required_without:phone|email',
'phone' => 'required_without:email',
'website' => 'nullable|url:https',
'device_id' => 'uuid:4',
'tags.*' => 'distinct:ignore_case',
'password' => 'required|confirmed',
'timezone' => 'timezone:per_country,US',
]);

The same rules with the new builders:

use Illuminate\Validation\Rule;
 
$request->validate([
'email' => [Rule::requiredWithout('phone'), 'email'],
'phone' => [Rule::requiredWithout('email')],
'website' => [Rule::nullable(), Rule::url()->protocols(['https'])],
'device_id' => [Rule::uuid()->version(4)],
'tags.*' => [Rule::distinct()->ignoreCase()],
'password' => [Rule::required(), Rule::confirmed()],
'timezone' => [Rule::timezone(['per_country', 'US'])],
]);

String rules still work, and you can mix both styles in the same array.

Rules Without Parameters

These return the rule as a plain string, so Rule::required() is the string required. The full list of these include:

  • accepted()
  • activeUrl()
  • bail()
  • base64()
  • boolean()
  • declined()
  • exclude()
  • filled()
  • hexColor()
  • json()
  • list()
  • macAddress()
  • missing()
  • nullable()
  • present()
  • prohibited()
  • required()
  • sometimes()
  • ulid()

Passing true to Rule::boolean() returns boolean:strict, which accepts only true and false.

Rules That Take Fields or Values

These take the other field names, keys, or values as arguments, either as an array or as separate arguments:

Rule::requiredWith('first_name', 'last_name');
Rule::requiredWith(['first_name', 'last_name']);
 
Rule::acceptedIf('plan', 'pro');
Rule::prohibits('coupon_code');
Rule::requiredArrayKeys('street', 'city', 'postcode');

Here is the full set of rules:

  • acceptedIf()
  • declinedIf()
  • excludeWith()
  • excludeWithout()
  • inArray()
  • inArrayKeys()
  • missingIf()
  • missingUnless()
  • missingWith()
  • missingWithAll()
  • notRegex()
  • presentIf()
  • presentUnless()
  • presentWith()
  • presentWithAll()
  • prohibitedIfAccepted()
  • prohibitedIfDeclined()
  • prohibits()
  • regex()
  • requiredArrayKeys()
  • requiredIfAccepted()
  • requiredIfDeclined()
  • requiredWith()
  • requiredWithAll()
  • requiredWithout()
  • requiredWithoutAll()
  • timezone()

Rules With Options

These return an object with methods for the rule's options:

Rule::url()->protocols(['https']); // url:https
Rule::uuid()->version(7); // uuid:7
Rule::ip()->version(6); // ipv6
Rule::distinct()->strict()->ignoreCase(); // distinct:strict,ignore_case
Rule::confirmed()->customField('repeat_pass'); // confirmed:repeat_pass
Rule::currentPassword()->guard('admin'); // current_password:admin

The version() method on Rule::ip() accepts 4 or 6 and throws an InvalidArgumentException for any other number. On Rule::uuid(), version() also accepts the strings 'nil' and 'max'.

The fluent date builder gets an equals() method in the same release, which adds a date_equals rule:

Rule::date()->equals('2026-12-31');
Rule::date()->equals(today());

Values With Commas

The string format splits parameters on commas. Suppose an accepted_if rule should apply when the plan field is Team, Annual:

'terms' => 'accepted_if:plan,Team, Annual',

The validator reads this as two values, Team and Annual, and the rule never matches Team, Annual.

The builders that take fields or values implement a new ParameterizedRule contract. Its toArray() method returns the rule name and its parameters as an array, and the validator uses that array directly instead of parsing a string. The value keeps its comma:

'terms' => [Rule::acceptedIf('plan', 'Team, Annual')],

This also covers quotes, pipes, and backslashes in values, and field or key names that contain commas, such as an array key for Rule::requiredArrayKeys().

Non-string values are converted to the strings the string format would use, so true, false, and null become 'true', 'false', and 'null':

Rule::presentIf('is_company', true); // present_if:is_company,true

If you cast a builder to a string, for example to log it, you get the string format with quotes around any value that contains a comma or a double quote.

A Form Request Example

A checkout form request might mix existing builders with the new ones:

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
 
class CheckoutRequest extends FormRequest
{
public function rules(): array
{
return [
'plan' => [Rule::required(), Rule::in(['starter', 'Team, Annual'])],
'terms' => [Rule::acceptedIf('plan', 'Team, Annual')],
'company_name' => [Rule::requiredIfAccepted('is_business')],
'vat_number' => [Rule::nullable(), Rule::requiredWith('company_name')],
'billing' => [Rule::required(), Rule::requiredArrayKeys('street', 'city', 'postcode')],
'coupon_code' => [Rule::nullable(), Rule::prohibits('gift_card')],
'website' => [Rule::nullable(), Rule::url()->protocols(['https'])],
'emails.*' => [Rule::distinct()->ignoreCase(), 'email'],
];
}
}

Further Reading

Eric (@ericmp33) contributed the rule builders in #61833.

Paul Redmond photo

Staff writer at Laravel News. Full stack web developer and author.

Sponsored

masteringlaravel logo
Laravel Code Review

Get expert guidance in a few days with a Laravel code review

Visit Laravel Code Review

The latest

View all →
Laravel URL AI Transformer: Extract Structured Data From URLs image

Laravel URL AI Transformer: Extract Structured Data From URLs

Read article
Rule Builders for Every Validation Rule in Laravel 13.36 image

Rule Builders for Every Validation Rule in Laravel 13.36

Read article
PHP News: A New Site for PHP Releases, RFCs, and Packages image

PHP News: A New Site for PHP Releases, RFCs, and Packages

Read article
Pause Polling in Background Tabs in Inertia.js v3.9 image

Pause Polling in Background Tabs in Inertia.js v3.9

Read article
Look What You Helped Me Build image

Look What You Helped Me Build

Read article
BashBox: A Sandboxed Bash Interpreter for AI Agents in PHP image

BashBox: A Sandboxed Bash Interpreter for AI Agents in PHP

Read article