Search code examples
validationsymfonyassert

Assert Expression validation not working at attribute level in Symfony 2.4


I am trying to validate an attribute at a field level by the @Assert\Expression (http://symfony.com/doc/2.4/reference/constraints/Expression.html).

It works at a class level with this code:

/**
 * Foo
 * 
 * @ORM\Table(name="foo")
 * @ORM\HasLifecycleCallbacks()
 * @UniqueEntity("slug")
 * @Assert\Expression(
 *     "this.getPriceFor2PaxStandard() != null or (this.getPriceFor2PaxStandard() == null and !this.isPriceForAccLevelRequired('standard'))",
 *     message="The price for 2 pax standard is required",
 *     groups={"agency_tripEdit_finalsave"}
 * )
 * 
 */
class Foo implements ISpellcheckerLocaleProvider, ProcessStatusAware, DataTransformer
{

but if I use the same code (which should be fine) at attribute level is not working:

/**
     * @var decimal
     *
     * @ORM\Column(name="price_for_2_pax_standard", type="decimal", precision=16, scale=4, nullable=true)
     * @Assert\Expression(
     *     "this.getPriceFor2PaxStandard() != null or (this.getPriceFor2PaxStandard() == null and !this.isPriceForAccLevelRequired('standard'))",
     *     message="The price for 2 pax standard is required",
     *     groups={"agency_tripEdit_finalsave"}
     * )
     */
    private $priceFor2PaxStandard;

In addition, does not work either if I use value instead of this.getPriceFor2PaxStandard() when using the asseriont as a attribute level.

Any hint would be appreciated :-)


Solution

  • It is a bug in symfony. If you look at the code for the ExpressionValidator you can see it skips validating if the value is null or an empty string. This is useful for some other constraints but pointless in the ExpressionValidator. I have just submitted a pull request to fix it. The easiest way around this at the moment would be to swap to a callback validator.

    <?php
    
    namespace Symfony\Component\Validator\Constraints;
    
    use Symfony\Component\Validator\Constraint;
    use Symfony\Component\Validator\Exception\UnexpectedTypeException;
    
    class ExpressionValidator extends ConstraintValidator
    {
        public function validate($value, Constraint $constraint)
        {
            if (!$constraint instanceof Expression) {
                throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Expression');
            }
    
            if (null === $value || '' === $value) {
                return;
            }
    
            //...
        }
    
        //...
    
    }