Skip to content

Fluent API

The Fluent API provides a per-field, chainable interface for defining validation rules. It offers full IDE autocomplete support, making it easy to discover and apply validation rules.

The Fluent API centers around the field() method, which returns a FieldBuilder instance for the specified field. From there, you can chain any validation rule as a method call, with your IDE suggesting available options as you type.

Start with field() to target a field, then chain validation methods:

use Frostybee\Valicomb\Validator;
$v = new Validator($_POST);
$v->field('email')
->required()
->email()
->lengthMax(254);
if ($v->validate()) {
echo "Valid!";
}

When validating multiple fields, each call to field() starts a new chain for that field. This keeps your validation rules readable and organized.

Use separate field() calls for each field - this keeps your code clean and scannable:

$v->field('email')
->required()
->email();
$v->field('password')
->required()
->lengthMin(8);
$v->field('age')
->required()
->integer()
->min(18);

The field() method returns a FieldBuilder, not the Validator. If you need to call Validator methods like validate() at the end of a chain, use end() to switch back.

Use end() when you need to return to the Validator instance to continue with other methods:

$v->field('price')
->required()
->numeric()
->positive()
->end() // Return to Validator
->field('quantity')
->required()
->integer()
->min(1)
->end() // Return to Validator
->validate();

You can also use end() to mix with other syntaxes in a single chain:

$v->field('discount_code')
->optional()
->alphaNum()
->length(8)
->end()
->forFields([
'shipping_date' => ['required', 'date', 'future'],
])
->validate();

When validating forms, you might want to stop as soon as the first error is found rather than collecting all errors. This improves performance and can provide a better user experience in some scenarios.

By default, all rules are checked and all errors collected. Enable stopOnFirstFail() for better performance when you only need to know if validation failed:

$v = new Validator($_POST);
$v->stopOnFirstFail(true);
$v->field('email')->required()->email();
$v->field('password')->required()->lengthMin(8);
$v->field('age')->required()->integer()->min(18);
$v->validate(); // Stops as soon as first rule fails

See Core Concepts for more details.


Error messages are more helpful when they speak the user’s language. The Fluent API makes it easy to customize both the error messages and the field names that appear in them.

Add message() after any rule to customize its error message:

$v->field('email')
->required()->message('We need your email address')
->email()->message('Please enter a valid email');

Use label() to set human-readable names for error messages:

$v->field('dob')
->label('Date of Birth')
->required()
->date()
->past();
// Error: "Date of Birth is required" instead of "Dob is required"

While the Fluent API provides direct methods for all built-in rules, sometimes you need to apply a custom validation or use a rule with specific parameters. The rule() method gives you full flexibility within the fluent chain.

Use rule() to add named rules or custom callables:

$v->field('username')
->rule('lengthBetween', 3, 20);
$v->field('coupon')
->optional()
->rule(fn($field, $value) => in_array($value, $validCoupons))
->message('Invalid coupon code');

You don’t have to choose just one approach. The Fluent API works seamlessly alongside forFields() and rules(), letting you use the best syntax for each situation within the same validator.

The Fluent API can be combined with other syntaxes in the same validator:

$v = new Validator($_POST);
// Use forFields() for simple fields
$v->forFields([
'name' => ['required', ['lengthBetween', 2, 50]],
]);
// Use Fluent API for fields needing custom messages
$v->field('email')
->required()->message('Email is required for account recovery')
->email()->message('Please enter a valid email address');
$v->field('password')
->required()
->lengthMin(8)->message('Password must be at least 8 characters')
->passwordStrength(3)->message('Password is too weak');

When you need to validate multiple records with the same rules (like batch processing or API endpoints), you can define the validation once and reuse it. The withData() method creates a fresh validator instance with your rules applied to new data.

Define validation rules once with the Fluent API, then apply them to multiple datasets using withData():

// Define rules once
$productValidator = new Validator([]);
$productValidator->field('price')
->required()
->numeric()
->positive();
$productValidator->field('quantity')
->required()
->integer()
->min(1);
// Validate different products
$v1 = $productValidator->withData(['price' => 29.99, 'quantity' => 5]);
$v1->validate(); // true
$v2 = $productValidator->withData(['price' => -10, 'quantity' => 0]);
$v2->validate(); // false

See Core Concepts for more details on this pattern.


Here’s a real-world registration form showing how the Fluent API handles multiple fields with custom messages, labels, and various validation rules working together.

use Frostybee\Valicomb\Validator;
$v = new Validator($_POST);
$v->field('username')
->label('Username')
->required()
->alphaNum()->message('Username can only contain letters and numbers')
->lengthBetween(3, 20)
->notIn(['admin', 'root', 'system'])->message('This username is reserved');
$v->field('email')
->label('Email Address')
->required()
->email()
->lengthMax(254);
$v->field('password')
->label('Password')
->required()
->lengthMin(8)
->passwordStrength(['min' => 8, 'uppercase' => 1, 'number' => 1]);
$v->field('password_confirm')
->label('Password Confirmation')
->required()
->equals('password')->message('Passwords do not match');
$v->field('age')
->label('Age')
->required()
->integer()
->between(13, 120);
$v->field('website')
->optional()
->url();
$v->field('terms')
->accepted()->message('You must accept the terms of service');
if ($v->validate()) {
// Process registration
} else {
$errors = $v->errors();
}

Below is a quick reference of all methods available on the FieldBuilder class. Each validation method returns $this, allowing you to chain as many rules as needed. For detailed usage and examples, follow the links to the rule-specific documentation.

MethodDescription
field(string $name)Switch to validating a different field
rule(string|callable $rule, mixed ...$params)Add a custom or named rule
message(string $msg)Set custom error message for the last rule
label(string $label)Set human-readable field label
end()Return to the Validator instance
MethodDescription
required(bool $allowEmpty = false)Field must be present and not empty
optional()Only validate if field is present
nullable()Allow null values, skip other rules if null
requiredWith(string|array $fields, bool $strict = false)Required if other field(s) are present
requiredWithout(string|array $fields, bool $strict = false)Required if other field(s) are absent

See Conditional Rules for details.

MethodDescription
alpha()Alphabetic characters only
alphaNum()Alphanumeric characters only
ascii()ASCII characters only
slug()URL slug format (a-z, 0-9, -, _)
contains(string $str, bool $strict = false)Contains substring
regex(string $pattern)Matches regex pattern
startsWith(string|array $prefix, bool $caseSensitive = false)Starts with prefix
endsWith(string|array $suffix, bool $caseSensitive = false)Ends with suffix
uuid(?int $version = null)Valid UUID (optionally specific version)
passwordStrength(int|array $config)Password strength requirements

See String Rules for details.

MethodDescription
length(int $len)Exact length
lengthBetween(int $min, int $max)Length within range
lengthMin(int $min)Minimum length
lengthMax(int $max)Maximum length

See Length Rules for details.

MethodDescription
numeric()Must be numeric
integer(bool $strict = false)Must be integer
min(int|float $min)Minimum value
max(int|float $max)Maximum value
between(int|float $min, int|float $max)Value within range
boolean()Must be boolean
positive()Must be positive number
decimalPlaces(int $places)Specific decimal places

See Numeric Rules for details.

MethodDescription
date()Valid date
dateFormat(string $format)Matches date format
dateBefore(string $date)Before specific date
dateAfter(string $date)After specific date
past()Date in the past
future()Date in the future

See Date Rules for details.

MethodDescription
ip()Valid IP address
ipv4()Valid IPv4 address
ipv6()Valid IPv6 address
email()Valid email address
emailDNS()Valid email with DNS verification
url()Valid URL
urlActive()Valid URL that is reachable
urlStrict()Valid URL with strict checking
phone(?string $country = null)Valid phone number

See Network Rules for details.

MethodDescription
array()Must be an array
in(array $values)Value is in allowed list
notIn(array $values)Value is not in disallowed list
listContains(mixed $value, bool $strict = false)Array contains value
subset(array $values)Array is subset of allowed values
containsUnique()Array contains unique values
arrayHasKeys(array $keys)Array has required keys

See Array Rules for details.

MethodDescription
equals(string $otherField)Must equal another field’s value
different(string $otherField)Must differ from another field’s value
accepted()Must be accepted (true, “yes”, “on”, “1”)

See Comparison Rules for details.

MethodDescription
instanceOf(string $class)Must be instance of class
creditCard(string|array|null $type = null, ?array $allowedTypes = null)Valid credit card number

See Type Rules for details.