symfony-api-response
Symfony REST API response standard {result, error, extra, status}: thin controllers, #[MapRequestPayload] / #[MapQueryString]…
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]
Claude Code
$ npx -y skills add aligundogdu/symfony-hexagonal-skill --skill symfony-validation --agent claude-code
Codex
$ npx skills add aligundogdu/symfony-hexagonal-skill --skill symfony-validation -a codex -y
Cursor
$ npx skills add aligundogdu/symfony-hexagonal-skill --skill symfony-validation -a cursor -y
Gemini CLI
$ npx skills add aligundogdu/symfony-hexagonal-skill --skill symfony-validation -a gemini-cli -y
GitHub Copilot
$ npx skills add aligundogdu/symfony-hexagonal-skill --skill symfony-validation -a github-copilot -y
OpenCode
$ npx skills add aligundogdu/symfony-hexagonal-skill --skill symfony-validation -a opencode -y
Windsurf
$ npx skills add aligundogdu/symfony-hexagonal-skill --skill symfony-validation -a windsurf -y
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"
You are an expert in multi-layer validation within Symfony hexagonal architecture.
| 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 |
**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**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.
**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);
}
// ...
}
}See `references/` for detailed guides:
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).
Symfony REST API response standard {result, error, extra, status}: thin controllers, #[MapRequestPayload] / #[MapQueryString]…
Symfony CQRS with Messenger: commands, queries, handlers, command.bus / query.bus / event.bus configuration, typed bus wrappers,…
Doctrine persistence for Symfony hexagonal architecture (ORM 2.x/3.x, DBAL 3/4, DoctrineBundle 2/3): repository adapters, XML…
Symfony DDD domain modeling in pure PHP: entities, aggregates, value objects, domain events, domain exceptions, ID generation…
Symfony hexagonal architecture (ports & adapters) setup for Symfony 6.4 LTS, 7.4 LTS and 8.x: project structure, module…
Symfony Messenger async processing and Symfony Scheduler instead of cron: transports, routing (#[AsMessage] 7.2+), retry with…
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.