3

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.
  }

1 Answer 1

2

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;

 }
Sign up to request clarification or add additional context in comments.

8 Comments

Hey John, thanks for your answer. I created the class constraint and for testing I only wanted to pass the current nameProperty, so no "whole book". The problem I get is that within the "bookNameProperty", I just see the string "name", but not the actual name value. I update my question with my current code, maybe you can have a look at it :)
The value "name" is the property path to your model. Please read the link I posted above called property accessor. You pass this path and your model to the accessor, and it will return the value for you.
Ah ok, sorry :) I'll have a look, thanks! I tried one hour to figure out how the "UniqueEntity" constraint works, so I think property accessors should be the solution.
I don't understand how this should work John. I always end up by having plain Strings within my validate() Method. From within my FormHandler, i call: $errors = $this->validator->validate($book, array('Default', 'Editmode')); Before that, I added the new "oldBook" to the $book. I also installed via composer the property accessor, but within my validate() Method, I don't have access to the $book.
I followed along this example: gist.github.com/stof/d21838b00d08858ae6bb But still, calling "$constraint->bookProperty" - bookProperty is a string of "oldBook" ..
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.