Skip to content

Latest commit

 

History

History
302 lines (219 loc) · 5.86 KB

File metadata and controls

302 lines (219 loc) · 5.86 KB

Validation

The validation layer uses a fluent API instead of Laravel-style rule strings.

Available facade:

  • Validator

What It Provides

The validation layer gives you:

  • ValidationManager to create validators
  • Validator to coordinate multiple fields
  • FieldValidator for fluent rule configuration per field
  • ValidationException for throw-on-failure workflows

Use ValidationManager Directly

use Myxa\Validation\ValidationManager;

$validator = (new ValidationManager())->make([
    'email' => 'john@example.com',
    'user_id' => 1,
]);

Then configure rules field by field:

$validator->field('email')
    ->required('Please provide an email address.')
    ->string()
    ->email()
    ->max(255);

$validator->field('user_id')
    ->required()
    ->integer();

Common Flow

$validator = (new ValidationManager())->make([
    'name' => 'John',
    'email' => 'john@example.com',
    'notes' => null,
]);

$validator->field('name')->required()->string()->min(2)->max(50);
$validator->field('email')->required()->string()->email()->max(255);
$validator->field('notes')->nullable()->string();

if ($validator->fails()) {
    $errors = $validator->errors();
} else {
    $validated = $validator->validated();
}

Or throw on failure:

$validated = $validator->validate();

Supported Fluent Rules

Presence and Nullability

  • required()
  • nullable()

Behavior:

  • missing fields fail only when required() is configured
  • nullable() allows an explicit null value
  • when a field is null and nullable() is set, the remaining rules for that field are skipped
  • nested fields can be targeted with dot paths such as user.email
  • array items can be targeted with * wildcards such as tags.*

Type and Format Rules

  • string()
  • integer()
  • numeric()
  • boolean()
  • array()
  • email()

Size Rules

  • min($value)
  • max($value)

The size meaning depends on the value type:

  • strings use string length
  • arrays use item count
  • numeric values use their numeric value

Nested Fields and Array Items

Use dot notation to validate nested input:

$validator = (new ValidationManager())->make([
    'user' => [
        'name' => 'John',
        'roles' => ['admin', 'editor'],
    ],
]);

$validator->field('user.name')->required()->string()->min(2);
$validator->field('user.roles')->required()->array()->min(1);

Use * to validate each array item:

$validator->field('user.roles.*')->required()->string()->min(3);

When wildcard validation fails, errors are keyed by the concrete item path:

[
    'user.roles.1' => [
        'The user.roles.1 field must be a string.',
    ],
]

Exists Validation

exists() can validate against several sources:

  • a SQL model class
  • a Mongo model class
  • an array of allowed values
  • a custom callable returning true or false

SQL Model Example

$validator->field('user_id')
    ->required()
    ->integer()
    ->exists(User::class);

You can also validate against a specific SQL model column:

$validator->field('email')
    ->required()
    ->string()
    ->exists(User::class, 'email');

Mongo Model Example

$validator->field('document_id')
    ->required()
    ->exists(UserDocument::class);

For Mongo models, exists() only supports the model primary key.

Allowed Values Example

$validator->field('role')->exists(['admin', 'editor']);

Custom Callback Example

$validator->field('code')->exists(
    static fn (mixed $value): bool => in_array($value, ['A', 'B'], true),
);

Custom Error Messages

Each rule accepts an optional custom message:

  • string message
  • callable message

String example:

$validator->field('name')->required('Name is mandatory.');

Callable example:

$validator->field('email')->email(
    static fn (mixed $value, string $field): string => sprintf(
        '%s "%s" is invalid.',
        $field,
        (string) $value,
    ),
);

Validated Output

validated() and validate() return only the configured fields that are present in the input data.

$validator = (new ValidationManager())->make([
    'name' => 'John',
    'email' => 'john@example.com',
    'ignored' => 'value',
]);

$validator->field('name')->required()->string();
$validator->field('email')->required()->string()->email();

$validated = $validator->validate();

Result:

[
    'name' => 'John',
    'email' => 'john@example.com',
]

Accessing Errors

if ($validator->fails()) {
    $errors = $validator->errors();
}

Error format:

[
    'email' => [
        'The email field must be a valid email address.',
    ],
]

Facade and Service Provider

In application code, register ValidationServiceProvider to expose the shared manager and initialize the facade:

use Myxa\Application;
use Myxa\Validation\ValidationServiceProvider;

$app = new Application();
$app->register(new ValidationServiceProvider());
$app->boot();

Then use the facade:

use Myxa\Support\Facades\Validator;

$validator = Validator::make([
    'name' => 'John',
    'email' => 'john@example.com',
]);

$validator->field('name')->required()->string();
$validator->field('email')->required()->string()->email();

Exception Handling

validate() throws ValidationException when validation fails:

use Myxa\Validation\Exceptions\ValidationException;

try {
    $validated = $validator->validate();
} catch (ValidationException $exception) {
    $errors = $exception->errors();
}

Notes

  • the API is fluent and field-oriented rather than string-rule oriented
  • passes() and fails() evaluate all configured fields and collect grouped errors
  • validate() throws, while validated() returns the validated subset after a successful validation pass
  • exists() supports SQL models, Mongo models, arrays of allowed values, and custom callables