Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

A Custom Validator

A Custom Validator

~16 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

The built-in constraints don't ALWAYS suffice – a CUSTOM validator here checks whether a project's name ALREADY exists.

Creating the constraint class

docker compose exec php bin/console make:validator UniqueProjectName
api/src/Validator/UniqueProjectName.php
<?php

declare(strict_types=1);

namespace App\Validator;

use Symfony\Component\Validator\Constraint;

#[\Attribute]
final class UniqueProjectName extends Constraint
{
    public string $message = 'A project named "{{ value }}" already exists.';
}

Implementing the validator

api/src/Validator/UniqueProjectNameValidator.php
<?php

declare(strict_types=1);

namespace App\Validator;

use App\Repository\ProjectRepository;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

final class UniqueProjectNameValidator extends ConstraintValidator
{
    public function __construct(
        private readonly ProjectRepository $projectRepository,
    ) {
    }

    public function validate(mixed $value, Constraint $constraint): void
    {
        if (!$constraint instanceof UniqueProjectName) {
            return;
        }

        if (null === $value || '' === $value) {
            return;
        }

        $existing = $this->projectRepository->findOneBy(['name' => $value]);

        if (null !== $existing) {
            $this->context->buildViolation($constraint->message)
                ->setParameter('{{ value }}', $value)
                ->addViolation();
        }
    }
}

EXACTLY the same Constraint/ConstraintValidator pair principle as in the Symfony course (chapter 26) – dependency injection works NORMALLY inside the validator, ProjectRepository gets injected AUTOMATICALLY.

Applying the validator

use App\Validator\UniqueProjectName;

#[ORM\Column(length: 255)]
#[Assert\NotBlank]
#[UniqueProjectName]
#[Groups(['project:read', 'project:write'])]
private string $name = '';

Testing the behavior

curl -k -X POST https://localhost/api/projects \
  -H 'Content-Type: application/json' \
  -d '{"name": "Website Relaunch"}'
{
  "violations": [
    {"propertyPath": "name", "message": "A project named \"Website Relaunch\" already exists."}
  ]
}

Tipp: Symfony ALSO offers a ready-made #[UniqueEntity] constraint for EXACTLY this case – this chapter deliberately shows the MANUAL approach, since it demonstrates HOW arbitrary CUSTOM business rules (not just uniqueness) can be implemented as a validator.