I create a UniqueEmail constraint and validator. The validator injects the UserRepository and checks if the email already exists. I apply it to the entity with the UniqueEmail attribute and it works in forms and API validation automatically.
A custom constraint needs two classes: a Constraint class (defines the annotation/attribute and error message) and a ConstraintValidator class (contains the validation logic). The constraint is applied to entity properties or form fields via attributes. When validation runs, the framework maps the constraint to its validator, calls validate(), and the validator adds violations via the execution context. Strong candidates explain: class-level constraints for multi-field validation, using dependency injection in validators (e.g., injecting a repository to check uniqueness), the Payload property for severity levels, and constraint groups for applying different validation rules in different contexts.
Tests practical validation experience. Candidates who cram all validation into controllers or form event listeners miss the reusable constraint system. Those who can inject services into validators and use constraint groups handle real-world validation complexity.