Conditional validator in Symfony, another approach
November 5th, 2008 by Carlos BarrosToday morning I was reading the Symfony blog, more specifically A week of symfony #96 and then I came across a tutorial talking about conditional validators.This is very usefull, I find myself using this technique very often, so I decided to write about another techinique I use sometimes to implement a conditional validation, but for a different scenario. Imagine the following: you have a contact form where the users specify how they want to be contacted, email or phone, throught a select box. Then you have two input boxes where the users can enter both email and phone. If the user opts to be contacted via email, email field becomes mandatory and phone number optional, and the opposite happens if the user opts to be contacted via phone. So, how to implement such a form in symfony?
A normal form would look like this:
lib/form/ContactForm.class.php:
class ContactForm extends sfForm { public function configure() { $this->setWidgets(array( 'method' => new sfWidgetFormSelect(array('choices'=>array('phone'=>'Phone','email'=>'Email'))), 'email' => new sfWidgetFormInput(), 'phone' => new sfWidgetFormInput(), 'msg' => new sfWidgetFormTextarea(), )); $this->setValidators(array( 'method' => new sfValidatorChoice(array( 'choices'=>array('phone','email'), )), 'email' => new sfValidatorEmail(array( 'required'=>true, ),array( 'required'=>'Please enter your email address', 'invalid'=>'Invalid email address' )), 'phone' => new sfValidatorString(array( 'required'=>true, ),array( 'required'=>'Please enter your phone number', )), 'msg' => new sfValidatorString(array( 'required'=>true, ),array( 'required'=>'Please enter your message', )), )); $this->widgetSchema->setLabels(array( 'email' => 'Email:', 'phone' => 'Phone:', 'method' => 'Contact type:', 'msg' => 'Message:', )); $this->widgetSchema->setNameFormat('contact[%s]'); $this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema); }
The problem with this form is the fact that both phone and email are ALWAYS mandatory, regardless of the value of method. So, what we need is a way to intercept method’s value and update validators. So, what we need is intercept the bind method in order to check method’s value:
lib/form/ContactForm.class.php:
public function bind(array $taintedValues = null, array $taintedFiles = null) { if(@$taintedValues["method"] == 'phone') $this->validatorSchema["email"]->setOption('required',false); else $this->validatorSchema["phone"]->setOption('required',false); return parent::bind($taintedValues,$taintedFiles); }
As can be seen, we create our own bind method, overriding parent one, and before calling the actual bind method, we inspect the values sent by the user and if method is phone, we remove the required option from email validator, otherwise we remove the required option from phone validator and finally call parent method.
The resulting form can be seen here!




maddogg
in
November 6th, 2008 at 3:26
-
Really interesting method.
Will be really helpful for multipart forms
Daniel
in
November 6th, 2008 at 15:20
-
That was great, thank you.
As you are so firm with the new form framework and nobody even cared to answer my question in the forum, I’ll give it a try here.
The question is here: http://www.symfony-project.org/forum/index.php/t/16625/
I have widgets in many forms that have the same default options (years array in sfWidgetFormDate for example) and the form framework generates a base form that all base forms in the base/ directory inherit from. In the forms book there’s an example on how to set the default form formatter name for all these forms. But how can I preconfigure a widget in this class? It really is annoying to have this non-DRY boiler-plate code in all forms. Maybe you can help me.
Thanks for this awesome post! Cheers, Daniel
Éric Rogé
in
November 6th, 2008 at 16:22
-
Great, I had the same issue, and until now, the only way I’ve founded was to extend the doClean method with my own validatorSchema.
My only critic with your way is that the form won’t work if you embed it in anthor form.
PS: I think that instead in your bind method, you should use $this->validatorSchema->offsetUnset(‘phone’);
It will remove all the validators on the field, and not only the required one.
Carlos Barros
in
November 6th, 2008 at 16:48
-
Hi Daniel, I just replied to you thread, I hope this works for you.
Eric, thanks for your comments. Yes, it won’t work if you embed this form into another one, but it’s simple to make it work. For instance, if you embed this form into an "options" field of another form, you can just move the bind method into the parent form and change it a bit:
About you idea about un-setting the entire validator works fine too, but I didn’t to this because even though the field is not required, we still accept it and we should still validate it. In my example, if the user choose to be contacted by phone, but he says in the comments that if I couldn’t reach him by phone it’s fine to send an email, we still need to validate email field against sfValidatorEmail to ensure it’s a valid email address. But in case your action will simply "discard" the value, your idea works fine.
Thanks
Fredlab
in
November 6th, 2008 at 17:05
-
What a great tutorial and it is so simple. I will keep it in my bookmarks.
Can I ask your help for the following : http://groups.google.com/group/symfony-users/browse_thread/thread/5a46301bed193ce5?hl=en#
I tried to find a solution on how to use that helper. There are no example. I think this is the kind of example everyone is looking for.
Again, thanks for this tuto ! Regards, Frédéric.
Carlos Barros
in
November 6th, 2008 at 18:52
-
Hi Frederic,
Unfortunately I still didn’t install Symfony 1.2 here so I don’t have experience with this helper. But looking at the code, I’m afraid this helper won’t do what u want. My suggestion is to create the link by your own, using something like this:
<a href="<?=url_for('author/list') ? rel="nofollow">?filters[author_id]=<?=$author->getId()?>&filter=filter">articles</a>And then enable author_id (I’m assuming author_id is you column name) filter in the article view. I didn’t use link_to here because it does not allows to add URI parameters (well, I read that Symfony 1.2 allows this, but didn’t know how it works). Also, this link works with Symfony 1.1 admin generator, not sure it will work for 1.2 version.
Hope this helps
Daniel
in
November 6th, 2008 at 19:22
-
Thanks Carlos, your reply was very helpful!
Fredlab
in
November 9th, 2008 at 6:46
-
Carlos,
Thanks for your answers. I found an easy hack for 1.2 and thought it was a bug. See ticket http://trac.symfony-project.org/ticket/4871#comment:3 as well as Fabien answers.
I will try you idea to see if it works with 1.2
Thanks
Frédéric
rpsblog.com » A week of symfony #97 (3->9 november 2008) in November 9th, 2008 at 20:53-
[...] Conditional validator in Symfony, another approach [...]
Fred Böhni
in
December 16th, 2008 at 8:16
-
Works like a charm, thanks!
Adam
in
January 2nd, 2009 at 20:24
-
YES! I love you. This is perfect. You rock. Have my babies.
Kamil Adryjanek
in
January 19th, 2009 at 9:33
-
Really useful, Thanks.
blog.barros.ws » Using embedFormForEach in Symfony, Part II in January 31st, 2009 at 12:41-
[...] supply data only for 3, so it will throw an validation error. To avoid this, we need to implement a conditional validation. Remember on constructor we saved the variable ncars? We’ll use it here to remove removed [...]
Ricky
in
September 8th, 2009 at 6:15
-
Nice snippet, found it really useful.
Ended up modifying it a bit to suit my needs, but your original concept helped a lot!
Cheers
virtualize
in
October 15th, 2009 at 10:51
-
Thanks for this hint, saved me some troubles.
Marget Biery
in
February 27th, 2010 at 12:04
-
Hey web entrepreneurs ! You have great ideas and are looking for the best value coding company and/or looking for investors to help you fund your project? Just enter this place, I found it days ago, it seems to be in alpha but the concept seems really good ! <a href="http://www.codingate.com" rel="nofollow">CODINGATE</A> .
free nintendo points
in
March 7th, 2010 at 19:59
-
Amazing! Thank you! I always desired to produce in my site something like that. Should i quote portion of your post to my weblog?
diets to loose weight
in
March 8th, 2010 at 7:29
-
Ultimately, an issue that I am fervent about. I have looked for information of this topic for the last several hours. Your site is greatly treasured.
reverse phone number lookup
in
March 10th, 2010 at 14:34
-
People who are afraid of the world make no sense to me…