Symfony2/Doctrine - validation constraint which re

2019-04-12 11:04发布

问题:

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

回答1:

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?

  1. Define a simple constraint
  2. Override validatedBy() method to return validator "name" (return 'my_validator';)
  3. 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.

  1. In your constraint class define the target of that constraint (property / class):

    class MyConstraint ... {
        ...
    
        public function targets() {
            return self::CLASS_CONSTRAINT;
        }
    }
    
  2. Annotate validated class instead of property:

    @Assert/MyConstraint(...)
    class MyClass {
        private $firstName;
        private $lastName;
    
        @Assert/Email
        private $email;
    
        ...
    }
    
  3. 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
        }
    }
    


回答2:

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';
}