Last active
August 29, 2015 14:13
-
-
Save webdevilopers/7dbf2f072ab394e1311b to your computer and use it in GitHub Desktop.
How to use Symfony2 Validation Constraint Callback with validation groups to validate a single property
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Acme\AppBundle\Entity; | |
use Doctrine\ORM\Mapping as ORM; | |
use Symfony\Component\Validator\Constraints as Assert; | |
use Symfony\Component\Validator\Context\ExecutionContextInterface; | |
/** | |
* PriceQuoteRequest | |
* | |
* @ORM\Table(name="pricequote") | |
* @ORM\Entity | |
* | |
* @Assert\Callback(methods={"isGutterValid"}, groups={"flow_dormerRequest_step2"}) | |
*/ | |
class PriceQuoteRequest | |
{ | |
/** | |
* @var integer $dormerInnerHeight | |
* | |
* @ORM\Column(name="h", type="float") | |
* @Assert\NotBlank(groups={"flow_dormerRequest_step2"}) | |
* @Assert\Range(min="80", max="1000", groups={"flow_dormerRequest_step2"}) | |
*/ | |
public $dormerInnerHeight; | |
/** | |
* @var boolean $dormerGutter | |
* | |
* @ORM\Column(name="gutter", type="boolean") | |
* | |
* @Assert\Type(type="boolean", groups={"flow_dormerRequest_step2"}) | |
* Assert\Callback(methods={"isGutterValid"}, groups={"flow_dormerRequest_step2"}) | |
*/ | |
public $dormerGutter; | |
/** | |
* @ORM\OneToOne(targetEntity="Acme\AppBundle\Entity\GutterMaterial") | |
* | |
* Assert\Type(type="Acme\AppBundle\Entity\GutterMaterial", groups={"flow_dormerRequest_step2"}) | |
*/ | |
public $dormerGutterMaterial; | |
/** | |
* | |
* @param ExecutionContextInterface $context | |
* | |
* Assert\Callback(groups={"flow_dormerRequest_step2"}) | |
*/ | |
public function isGutterValid(ExecutionContextInterface $context) | |
{ | |
if ($this->getDormerGutter() === true && $this->getDormerGutterMaterial() === null) { | |
$context->buildViolation('Gutter checked but no Material selected.') | |
->atPath('dormerGutter') | |
->addViolation(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Acme\AppBundle\Tests\Entity; | |
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; | |
use Symfony\Component\Validator\Validation; | |
class RequestFunctionalTest extends KernelTestCase | |
{ | |
/** | |
* @var \Doctrine\ORM\EntityManager | |
*/ | |
private $em; | |
/** | |
* {@inheritDoc} | |
*/ | |
public function setUp() | |
{ | |
self::bootKernel(); | |
$this->em = static::$kernel->getContainer() | |
->get('doctrine') | |
->getManager() | |
; | |
} | |
public function testDormerGutterValidator() | |
{ | |
$priceQuoteRequest = new PriceQuoteRequest(); | |
$priceQuoteRequest->setDormerGutter(true); | |
// Validating on single property will not call "isGutterValid" Callback, exptected only 1 error otherwise | |
// $violationList = $this->getValidator()->validateProperty($priceQuoteRequest, 'dormerGutter', array('flow_dormerRequest_step2')); | |
// Validating full object will call "isGutterValid" but return all errors resp. > 1 | |
$violationList = $this->getValidator()->validate($priceQuoteRequest, array('flow_dormerRequest_step2')); | |
dump($violationList); | |
$this->assertEquals(1, count($violationList)); | |
} | |
} |
The question on stackoverflow:
http://stackoverflow.com/questions/28071496/how-to-use-symfony2-validation-constraint-callback-with-validation-groups-to-val
A smart workaround if I will HAVE TO use the validate
method instead of validateProperty
is to reduce the number of expected errors by using a custom validation group:
/**
* PriceQuoteRequest
*
* @ORM\Table(name="pricequote")
* @ORM\Entity
*
* @Assert\Callback(methods={"isGutterValid"}, groups={"dormerGutter"})
*/
And change the call in the Test class:
$violationList = $this->getValidator()->validate($priceQuoteRequest, array('dormerGutter'));
Thanks @bjo3rnf !
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If
DormerGutter
is set to true (resp. checked in form) aDormerGutterMaterial
has to be selected.The
isGutterValid
method is supposed to check this and otherwise point the violation to theDormerGutter
field:The Test sets the
DormerGutter
totrue
but selects noDormerGutterMaterial
.Validating on the property
DormerGutter
I expect to get that 1 error returned by theisGutterValid
Callback.Instead it will return 0 errors because calling
validateProperty
on a single property DOES NOT CALL the "global" Callback for the entire object resp. class.Instead I can validate the complete object. This will indeed call the
isGutterValid
method.It will return at least 2 errors since this also validates all the other properties e.g.
dormerInnerHeight
Unfortunately - in my use case - I only want that 1 error returned.
Is there a way to point a Callback to a single property only enabling me to call the validateProperty method and still fire the Callback?
The alternative / workaround will of course be the usage of the
Expression
Constraint:Ps.: All validation groups are successfully linked to
flow_dormerRequest_step2
.