I have an entity ArticlePattern
, which has a property pattern
(string). I need to access the database to check if pattern is correct. So I would like to define a method ArticlePattern::isPatternValid()
and add a constraint (using Doctrine's annotation) which would check if isPatternValid is true during validation by Validator object.
From what I have read here and there it is not a good idea, to make an entity depended on service container, which mean I cannot access the doctrine service from inside ArticlePattern::isPatternValid().
So how can I make a custom validation constraint which need an access to the database? How do you deal with such situations which I think is very common seeing so many questions about accessing a service container from an entity class.
EDIT:
Ok, thanks guys, so the answer is a Custom Validation Constraint
A validator object can be:
- A simple object, that has no connection to the framework environment at all.
- A service (in the context of dependency injection container) which could do absolutley anything as long as it impements
Symfony\Component\Validator\ConstraintValidatorInterface
So what do you have to do?
- Define a simple constraint
- Override
validatedBy()
method to return validator "name" (return 'my_validator';
)
Define a simple service in DIC:
<service id="project.validator.my" class="Project\Constraints\MyValidator">
<!-- service definition here -->
<!-- the service has to be tagged -->
<tag name="validator.constraint_validator" alias="my_validator" />
</service>
EDIT
You've asked about multiple properties validation. In such a case you could create a validator that is related to the object rather to the property of the object.
In your constraint class define the target of that constraint (property / class):
class MyConstraint ... {
...
public function targets() {
return self::CLASS_CONSTRAINT;
}
}
Annotate validated class instead of property:
@Assert/MyConstraint(...)
class MyClass {
private $firstName;
private $lastName;
@Assert/Email
private $email;
...
}
The validator itself looks pretty much the same as in case of validating a property:
class MyValidator extends ConstraintValidator {
public function isValid($value, Constraint $constraint) {
// $value is an object rather a property
}
}
Your constraint should override the base validatedBy()
method and return the id of the constraint validator service in your container.
public function validatedBy()
{
return 'my_pattern_validator';
}