Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony Custom Validation Constraint pass parameter

I have a custom validation constraint to check if an entered book name in a form is unique. I cannot use @Unique, because that would also validate the current value of the book and will always throw a validation error, even if I didn't want to change the book name.

(If there is a way to ignore the current value, I would love to hear it, but still I'd like to know how to pass a custom object to a custom validator :) )

So I wrote this for the name property of the book entity:

 /**
 * @ORM\Entity
 * @UniqueEntity("name", groups={"Creation"})
 */
 public class Book {

  /* 
  * @var string
  * @ORM\Column(type="string", unique = true)
  * @CustomAssert\UniqueBookName(groups={"Editmode"})
  */
  protected $name;

 }

For that to work, I need the current book name that I want to validate in the UniqueBookName Validator class.

How can I pass now the current book name to my validator class in this line:

@CustomAssert\UniqueBookName(groups={"Editmode"})

I know how to pass parameters in here with:

 @CustomAssert\UniqueBookName(exampleProperty="name", groups={"Editmode"})

but how can I pass as e.g. exampleProperty the real value of the current book name, not the string "name"?

Regards


Update for answer:

My Class Constraint:

 /**
 *@CustomAssert\UniqueBookName(nameProperty="name", groups={"Editmode"})
 */
 class Book{
  // Property as you described
 }

My Validator classes:

class UniqueBookName extends Constraint{

 public $message = 'book.edit.name';
 public $nameProperty;

 public function getDefaultOption()
 {
     return 'nameProperty';
 }

 public function getRequiredOptions()
 {
     return array('nameProperty');
 }

 public function validatedBy()
 {
     return 'bookName_validator';
 }


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

}

And the corresponding validators "validate"-Method:

 public function validate($value, Constraint $constraint)
  {
   // here, in $constraint I only see the String Value "name", not the current value I want.
  }
like image 717
nova.cp Avatar asked Mar 17 '26 20:03

nova.cp


1 Answers

I like to attach the a virtual resource to the form as a way to accomplish these kinds of validations.

When you construct your Book model, simply assign it a new property with an instance of the book record. Then, you can apply your validator as a class constraint (instead of property based) so you can have access to the entire model.

$book = new Book(); 
$book->oldBook = $repository->fetchBook($id); 
$form ...

As a good practice to make this model as reusable as possible, I additionally specify the properties names as parameters to the constraint. Using property accessor, you can then retrieve the values. Almost exactly like the UniqueEntity class validator is specifying "name" property.

/**
 * @ORM\Entity
 * @CustomAssert\UniqueBookName(bookProperty="oldBook", bookNameProperty="name", groups={"Editmode"})
 * @UniqueEntity("name", groups={"Creation"})
 */
 public class Book {

  /* 
  * @var string
  * @ORM\Column(type="string", unique = true)
  */
  protected $name;

 }
like image 91
John Cartwright Avatar answered Mar 20 '26 11:03

John Cartwright



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!