Class Attribute-based request validator for PHP (works for all PHP apps or any library/frameworks).
- composer require phpspa/validator
<?php
use PhpSPA\Validator\Attributes\Email;
use PhpSPA\Validator\Attributes\MinLength;
use PhpSPA\Validator\Attributes\Validatable;
use PhpSPA\Validator\Validator;
#[Validatable]
final class CreateUserDto
{
#[Email]
public ?string $email = null; // Optional field
#[MinLength(8)]
public string $password; // Required field
}
$result = Validator::from($req->json(), CreateUserDto::class);
if (!$result->isValid()) {
return $res->validationError($result->errors()); // Return error if request payload isn't valid
}
/** @var CreateUserDto $dto */ // !!! Comment is important for IDE autocompletion
$dto = $result->data();
$email = $dto->email; // Optional field (nullable)
$password = $dto->password;// PhpSPA Request helpers
Validator::from($req->json(), CreateUserDto::class);
Validator::from($req->urlQuery(), CreateUserDto::class);
Validator::from($req->get(), CreateUserDto::class);
Validator::from($req->post(), CreateUserDto::class);
// Raw PHP or other frameworks
Validator::from($_POST, CreateUserDto::class);
Validator::from(['email' => 'me@example.com'], CreateUserDto::class);
// Laravel Request
Validator::from($request->all(), CreateUserDto::class);<?php
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Model;
use PhpSPA\Validator\Attributes\Boolean;
use PhpSPA\Validator\Attributes\MinLength;
use PhpSPA\Validator\Attributes\Validatable;
use PhpSPA\Validator\Validator;
// --- YOUR LARAVEL MODEL SCHEMA ---
#[Validatable]
final class User extends Model
{
#[MinLength(2, message: 'Name must be at least 2 chars')]
public string $name = 'user';
#[Boolean]
public string $isAdmin;
}
// --- YOUR CONTROLLER IMPLEMENTATION ---
final class UserController
{
public function store(Request $request)
{
$result = Validator::from($request->all(), User::class);
if (!$result->isValid()) {
return response()->json([
'message' => $result->message(),
'errors' => $result->errors(),
], 422);
}
/** @var User $user */
$user = $result->data();
return response()->json([
'message' => 'Validated',
'data' => $user,
]);
}
}- Classes must be marked with
#[Validatable]to be validated. - Optional fields should be declared nullable (e.g.,
?string). - Access optional fields with null-safe or null coalescing.
- Fields with a default value are treated as optional; fields without a default value are required.
- Use
#[Required(message: "...")]when you want a custom required-field message. - Base error message comes from
#[Message](default: "Invalid request payload"), add the attribute to the class itself. - Payload can come from pure PHP
$_POST, PhpSPARequest, LaravelRequest, SymfonyRequest, or any array/object. - DTO property names map to request payload keys (e.g.,
$emailvalidatesemail).
#[Validatable](class): Marks the class as validatable.#[Message(string $message = 'Invalid request payload')](class): Base error message.#[Required(string $message = 'This field is required.')]: Custom required-field message (required is inferred when no default value exists).#[RequiredIf(string $field, mixed $value, string $message = 'This field is required.')]: Required when another field equals a value.#[Email(string $message = 'Invalid email address.')]#[MinLength(int $value, string $message = 'Must be at least {value} characters.')]#[MaxLength(int $value, string $message = 'Must be at most {value} characters.')]#[Length(int $min, int $max, string $message = 'Length must be between {min} and {max}.')]#[Min(int|float $value, string $message = 'Must be at least {value}.')]#[Max(int|float $value, string $message = 'Must be at most {value}.')]#[Between(int|float $min, int|float $max, string $message = 'Must be between {min} and {max}.')]#[Regex(string $pattern, string $message = 'Invalid format.')]#[Url(string $message = 'Invalid URL.')]#[Uuid(string $message = 'Invalid UUID.')]#[Enum(array $values, string $message = 'Value must be one of: {values}.')]#[Boolean(string $message = 'Must be a boolean.')]#[Numeric(string $message = 'Must be numeric.')]#[Date(string $message = 'Invalid date.')]#[Timestamp(string $message = 'Invalid timestamp.')]#[Alpha(string $message = 'Must contain only letters.')]#[AlphaNum(string $message = 'Must contain only letters and numbers.')]#[AllowedCharacters(string $characters, int $limit = PHP_INT_MAX, string $message = 'Contains invalid characters.')]: Restricts allowed characters and their maximum occurrences. Can be combined with other attributes for additional filtering.#[Lowercase(string $message = 'Must be lowercase.')]#[Uppercase(string $message = 'Must be uppercase.')]#[Ip(string $message = 'Invalid IP address.')]#[Phone(string $message = 'Invalid phone number.')]#[Json(string $message = 'Invalid JSON.')]#[IsArray(string $message = 'Must be an array.')]#[MinItems(int $value, string $message = 'Must contain at least {value} items.')]#[MaxItems(int $value, string $message = 'Must contain at most {value} items.')]#[ValidatableType(class-string<object> $class, bool $each = false, string $message = 'Invalid nested payload.')]: Validate nested objects or arrays of objects.
By the PhpSPA framework.
// Example: Combine AlphaNum and AllowedCharacters to allow only a-z, A-Z, 0-9, and dash
use PhpSPA\Validator\Attributes\AlphaNum;
use PhpSPA\Validator\Attributes\AllowedCharacters;
use PhpSPA\Validator\Attributes\Validatable;
#[Validatable]
final class ProductCodeDto
{
#[AlphaNum]
#[AllowedCharacters('a-zA-Z0-9-')]
public string $code;
}
// This will only allow codes like 'A1B2-C3', but not 'A1B2_C3' (underscore is not allowed)
// Example: Username allowing alphanumeric and underscore
use PhpSPA\Validator\Attributes\AlphaNum;
use PhpSPA\Validator\Attributes\AllowedCharacters;
use PhpSPA\Validator\Attributes\Validatable;
#[Validatable]
final class UsernameDto
{
#[AlphaNum]
#[AllowedCharacters('_')]
public string $username;
}
// Accepts: user_1, my_name, test123
// Rejects: user-name, my.name, test@123
// Example: Combine Numeric and AllowedCharacters with limits
use PhpSPA\Validator\Attributes\Numeric;
use PhpSPA\Validator\Attributes\AllowedCharacters;
use PhpSPA\Validator\Attributes\Validatable;
#[Validatable]
final class PriceDto
{
#[Numeric]
#[AllowedCharacters('.', 1)] // Allow at most one dot
#[AllowedCharacters('_', 3)] // Allow at most three underscores
public string $price;
}
// This will accept:
// - "123.45"
// - "123_45"
// - "123_4.5"
// But reject:
// - "123..45" (more than one dot)
// - "123____45" (more than three underscores)