Skip to content
Development
Skill

/symfony-validation

Symfony 3-layer validation in hexagonal architecture: Presentation request DTOs with #[MapRequestPayload], Application command validation via Messenger validation middleware, Domain invariants in value objects; custom constraints with named arguments, #[ExtendsValidationFor]

From plugin
symfony-hexagonal
3510 skills2 agents1 hook

Claude Code

$ npx -y skills add aligundogdu/symfony-hexagonal-skill --skill symfony-validation --agent claude-code

SKILL.md

symfony-validation.SKILL.md
name: symfony-validation
description: "Symfony 3-layer validation in hexagonal architecture: Presentation request DTOs with #[MapRequestPayload], Application command validation via Messenger validation middleware, Domain invariants in value objects; custom constraints with named arguments, #[ExtendsValidationFor] (7.4+), validation groups. Use when: validation, validator, constraint, DTO validation, input validation, invariant, assert, validation group, custom constraint"

Symfony Validation

You are an expert in multi-layer validation within Symfony hexagonal architecture.

When to Activate

  • User needs input validation
  • User asks about validation strategies
  • User needs custom constraints
  • User mentions DTO validation or domain invariants

Version Notes

| Feature | Requires | Fallback | |---|---|---| | `#[MapRequestPayload]` / `#[MapQueryString]` auto-validation | Symfony 6.3 | manual `ValidatorInterface::validate()` | | Named-argument constraints `Length(min: 2)` | all versions; **arrays removed in 8.0** | - | | Custom constraint with named-argument constructor | required for 8.0 (arrays deprecated 7.3) | same code works on 6.4 | | `#[ExtendsValidationFor(Target::class)]` | Symfony 7.4 | validate a Request DTO / Command instead | | `When(..., otherwise: [...])` | Symfony 7.3 | two constraints with groups |

3-Layer Validation Strategy

Layer 1: Presentation (Input Validation)

**Where**: Request DTOs in `Presentation/{Module}/API/Request/` **What**: Format validation: is the input well-formed? **How**: Constraints on the DTO + `#[MapRequestPayload]` (422 on failure)

namespace App\Presentation\User\API\Request;

use Symfony\Component\Validator\Constraints as Assert;

final readonly class RegisterUserRequest
{
    public function __construct(
        #[Assert\NotBlank]
        #[Assert\Email]
        public string $email = '',

        #[Assert\NotBlank]
        #[Assert\Length(min: 2, max: 100)]
        public string $name = '',

        #[Assert\NotBlank]
        #[Assert\Length(min: 8)]
        #[Assert\Regex(pattern: '/[A-Z]/', message: 'Must contain uppercase')]
        #[Assert\Regex(pattern: '/[0-9]/', message: 'Must contain a number')]
        public string $password = '',
    ) {
    }
}

// Controller
public function register(#[MapRequestPayload] RegisterUserRequest $request): JsonResponse

Layer 2: Application (Command Validation)

**Where**: Command/Query classes, validated by the Messenger `validation` middleware **What**: Use-case pre-checks: are the values acceptable for this use case (including checks that need ports, e.g. uniqueness)? **How**: Symfony Validator constraints on command properties

final readonly class RegisterUser
{
    public function __construct(
        #[Assert\NotBlank]
        #[Assert\Email]
        #[UniqueEmail]
        public string $email,

        #[Assert\NotBlank]
        public string $name,

        #[Assert\NotBlank]
        public string $plainPassword,
    ) {
    }
}

The `validation` middleware validates before handler execution and throws `Messenger\Exception\ValidationFailedException` (mapped to 422 by `ApiExceptionSubscriber`). Commands dispatched from CLI, Scheduler or other handlers are validated too, which is why this layer exists even with Layer 1.

Layer 3: Domain (Invariants)

**Where**: Entity constructors/factories, value objects, business methods **What**: Business invariants: is the operation valid in domain context? **How**: Pure PHP checks, throw domain exceptions (no `#[Assert]` attributes in Domain)

// Value object self-validates
final readonly class Email
{
    public function __construct(public string $value)
    {
        if (filter_var($value, FILTER_VALIDATE_EMAIL) === false) {
            throw InvalidEmailException::forValue($value);
        }
    }
}

// Entity protects invariants
final class Order
{
    public function cancel(string $reason, \DateTimeImmutable $now): void
    {
        if (!$this->status->canTransitionTo(OrderStatus::CANCELLED)) {
            throw InvalidOrderTransitionException::from($this->id->value, $this->status, OrderStatus::CANCELLED);
        }
        // ...
    }
}

References

See `references/` for detailed guides:

  • `validation-layers.md` - Full examples for each layer, custom constraints, `#[ExtendsValidationFor]`, groups, pre-6.3 fallback
Read more
@aligundogdu
Ships withsymfony-hexagonal

A Claude Code plugin that enforces hexagonal architecture (ports & adapters) in Symfony projects. Works with both new projects (full scaffolding) and existing projects (progressive, module-by-module refactoring).

3510 skills2 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
35
Star history of aligundogdu/symfony-hexagonal-skill on GitHub, a chart by star-history.com

Other skills on symfony-hexagonal.

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills2w309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react5d252k
@facebook@facebookInstall Skill

Questions about symfony-validation.

Which coding agents can use symfony-validation?
symfony-validation installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.