DannyP1
DannyP1

Reputation: 25

How to validate some custom constraint in symfony 5

I have Item entity class, and I must validate it. I have condition that price must be less than 1000. And if price is less than 5, and stock is less 10 it is wrong too. So for first condition I use LessThan Constraint, but what should I do for the second condition?

class Item {
   /**
     * @ORM\Column(type="float")
     * @Assert\LessThan(self::ITEM_MAX_PRICE)
     */
    private float $price;

   /**
     * @ORM\Column(type="integer")
     */
    private int $stock;

}

How can I validate this both property's with second condition?

Upvotes: 1

Views: 2957

Answers (4)

Jared Farrish
Jared Farrish

Reputation: 49238

I would use a custom validator. Here's an example from one of my projects (3.4).

Three files:

<?php // src/AppBundle/Validator/Constraint/HasValidDimensions.php

namespace AppBundle\Validator\Constraint;

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 */
class HasValidDimensions extends Constraint
{
    public $invalidWidth = 'Invalid width dimension.';
    public $invalidHeight = 'Invalid height dimension.';

    public function getTargets()
    {
        return self::CLASS_CONSTRAINT;
    }
}

Note the use of CLASS_CONSTRAINT. Now, the actual validator gives me access to the different parts (in this case it's a command validator):

<?php // src/AppBundle/Validator/Constraint/HasValidDimensionsValidator.php

namespace AppBundle\Validator\Constraint;

use AppBundle\Message\Command\PageTemplate\SetPageTemplateDimensions;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

/**
 * @Annotation
 */
class HasValidDimensionsValidator extends ConstraintValidator
{
    public function validate($setPageTemplateDimensions, Constraint $constraint): void
    {
        /* @var SetPageTemplateDimensions $setPageTemplateDimensions */
        /* @var HasValidDimensions $constraint */

        $pageTemplate = $setPageTemplateDimensions->getPageTemplate();

        if ($setPageTemplateDimensions->getWidth() > $pageTemplate->getWidthReal()) {
            $this->context
                ->buildViolation($constraint->invalidWidth)
                ->addViolation()
            ;
        }

        if ($setPageTemplateDimensions->getHeight() > $pageTemplate->getHeightReal()) {
            $this->context
                ->buildViolation($constraint->invalidHeight)
                ->addViolation()
            ;
        }
    }
}

Then use the validator on the class:

<?php // src/AppBundle/Message/Command/PageTemplate/SetPageTemplateDimensions.php

namespace AppBundle\Message\Command\PageTemplate;

use AppBundle\Validator\Constraint as AppAssert;

/**
 * @AppAssert\HasValidDimensions()
 */
class SetPageTemplateDimensions implements TenantOwnedInterface
{

Upvotes: 2

l13
l13

Reputation: 529

May be it is good and will be useful to use Group sequence. In this case first will be check is price is less than and only if the first is true will be checked another two assertion Something like that:

   /** 
 * @Assert\GroupSequence({"Item", "Strict"}) 
 */
class Item
{

   /** 
     * @ORM\Column(type="float")         
     * @Assert\LessThan(self::ITEM_MAX_PRICE) 
     * @Assert\GreaterThan(value=5, groups={"Strict"})
     */ 
     private float $price; 

   /** 
     * @Assert\GreaterThan(value=10, groups={"Strict"})
     * @ORM\Column(type="integer") 
     */ 
     private int $stock;
}

Upvotes: 0

Mcsky
Mcsky

Reputation: 1445

Unfortunately Symfony don't provide a build-in constraint to validate multiples properties between them (not so easy to do and maintain btw).

I suggest you to have a look to Callback constraint which allow flexibility to validate your entity.

But if your validation logic is growing I suggest you to do a custom validator. It's a service so you can inject services and test it easily.

Upvotes: 1

Related Questions