Myxa logo

Myxa

Version: 1.0.6

A lightweight, AI-powered PHP framework for teams that want to build modern systems fast without giving up clarity, performance, or developer joy.

Myxa is designed around recent PHP practices: strict typing, explicit structure, container-driven architecture, fast backend execution, and a developer experience that feels approachable whether you stay server-rendered or grow into a hybrid frontend.

Documentation

Validation

Validation is built into the framework and already registered by the app through FrameworkServiceProvider.

Myxa uses a fluent validation API:

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

That keeps rules explicit while avoiding string rule lists such as 'required|email|max:255'.

Quick Example

For typical request validation, create a validator from $request->all(), define the expected fields, call validate(), then use the validated data:

use Myxa\Http\Request;
use Myxa\Http\Response;
use Myxa\Support\Facades\Validator;

final class UserController
{
    public function store(Request $request, Response $response): Response
    {
        $validator = Validator::make($request->all());

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

        $validated = $validator->validate();

        return $response->json([
            'user' => [
                'name' => $validated['name'],
                'email' => $validated['email'],
            ],
        ], 201);
    }
}

The app exception flow already handles ValidationException, so you usually do not need a local try/catch around validate().

Checking Manually

Use fails() when you want to keep full control over the error response:

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

Use validate() when you want the app exception flow to handle validation errors:

$validated = $validator->validate();

Common Fluent Rules

Presence and nullability:

  • required()
  • nullable()

Types and format:

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

Size:

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

The min() and max() meaning depends on the value type:

  • strings use length
  • arrays use item count
  • numeric values use the numeric value itself

Nested Fields and Array Items

The validator supports nested array validation through field segments.

In app code, that means:

  • use dot paths for nested fields such as user.email
  • use * wildcards for array items such as user.roles.*

Example:

$validator = Validator::make([
    'user' => [
        'name' => 'Jane',
        'email' => 'jane@example.com',
        'roles' => ['admin', 'editor'],
    ],
]);

$validator->field('user.name')->required()->string()->min(2)->max(50);
$validator->field('user.email')->required()->string()->email()->max(255);
$validator->field('user.roles')->required()->array()->min(1);
$validator->field('user.roles.*')->required()->string()->min(3);

$validated = $validator->validate();

The validated output keeps the nested shape:

[
    'user' => [
        'name' => 'Jane',
        'email' => 'jane@example.com',
        'roles' => ['admin', 'editor'],
    ],
]

When wildcard validation fails, the error keys point to the concrete array item:

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

That makes nested request payloads much more practical to validate without flattening the input first.

Exists Validation

exists() can validate against several sources:

  • a SQL model class
  • a Mongo model class
  • an array of allowed values
  • a custom callback

Examples:

use App\Models\User;

$validator->field('user_id')->required()->integer()->exists(User::class);
$validator->field('email')->required()->string()->exists(User::class, 'email');
$validator->field('role')->required()->exists(['admin', 'editor']);
$validator->field('code')->exists(
    static fn (mixed $value): bool => in_array($value, ['A', 'B'], true),
);

Custom Messages

Every rule can accept a custom message.

String example:

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

Callback example:

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

Validated Output

The validated result only includes configured fields that are present in the input.

$validator = Validator::make([
    'name' => 'Jane',
    'email' => 'jane@example.com',
    'ignored' => 'value',
]);

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

$validated = $validator->validate();

Result:

[
    'name' => 'Jane',
    'email' => 'jane@example.com',
]

Nested configured fields are rebuilt into nested validated output rather than returned as flat dot-key arrays.

Error Format

errors() returns field-grouped messages:

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

That shape is easy to return from JSON APIs or map into server-rendered forms.

When To Use fails() vs validate()

Use fails() when:

  • you want to keep full control of the response
  • you want to render a form again with structured errors
  • you do not want exceptions in the normal flow

Use validate() when:

  • you want a short fail-fast path
  • you want the app exception flow to handle ValidationException
  • the controller action is simple and API-oriented

Laravel Comparison

If you come from Laravel, the closest translation is:

  • Laravel rule strings -> Myxa fluent field chains
  • Laravel nested rule keys like user.email or tags.* -> the same dot-path style in Myxa
  • Laravel validated() -> Myxa validated() or validate()
  • Laravel form requests -> explicit validator setup inside your action or service

Related Guides