symfony-validation — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited symfony-validation (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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): JsonResponseWhere: 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:
validation-layers.md - Full examples for each layer, custom constraints, #[ExtendsValidationFor], groups, pre-6.3 fallback~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.