Tuesday, October 26, 2010

Symfony Tutorials: Using sfValidatorCallback

Many times when you're validating forms in symfony you need to do more than what the standard validators allow, and since you're lazy you don't feel like creating your own custom validator. sfValidatorCallback to the rescue!

sfValidatorCallback allows you to define your own validation function to be used for a given form field. It also allows you to scrub the data in any way you see fit. We'll look at both uses.
A Psudo-example

Since you can use the callback validator for literally anything you want, here's a simple example of how to use a function in your model to validate a field on the form for that model object

In MyObjectForm.class.php:

1.public function configure() {
2. ...
3. $this->widgetSchema['some_text_field'] =
4. new sfWidgetFormTextArea(array('required'=>false));
5.
6. $this->validatorSchema['some_text_field'] = new sfValidatorCallback(
7. array('callback'=>
8. array($this->getObject(), 'someTextFieldValidatorHook')
9. )
10. );
11. ...
12. }


Here we see that we're setting the validator for some_text_field to our call back. The first parameter to the callback takes our options. For these we need to pass a callback, which takes the same parameters as PHP's call_user_func. Since we want to call a method in our base model object, we'll use an array as the first parameter to pass our object and the method we want to call. $this->getObject(); returns the model object of the form, and someTextFieldValidatorHook is what we want to call.

So, in MyObject.php, in your model folder:

1. public function someTextFieldValidatorhook($validator, $value) {
2.
3. //test $value, set $pass if its ok
4.
5. if($pass) {
6. return $value;
7. }
8.
9. else {
10.
11. $message = "I can write whatever I want here based on the results ".
12. "of my test. The point is that this field didn't validate though";
13.
14. throw new sfValidatorError($validator, $message);
15.
16. }
17.
18. }


We can see here that the magic is throwing the exception when your test fails. The exception bubbles up and is caught by the form stuff on a higher level to render the error message to the user as you would expect.

Now, there are are a few things to keep in mind:

* sfValidatorError can take a message code and error messages as its second and third parameters. However, most of the time you use the call back, you'll want to generate the error message internally, since its dependant on the test you just wrote. Still, remember that you can respond with canned error messages if you want.
* Your data hasn't been saved yet, so you really have no notion of what the other fields are unless you grab the request object and look at them.
* You can make your validation method static if you want, but sometimes its helpful to have the old values of your current object, or you may have expanded your model object to do things beyond the standard get/set stuff.

Is This Cool?

Some may argue that this kind of validation doesn't belong in your model object, and a separate validator object should be created. I can see that point, and I think I mostly agree with it, but there are exceptions to every rule. Sometimes this simple approach is the correct one, and it can streamline your development.

Still, you should keep in mind that your validation function is going to throw a validator exception, so indicate that you'll need to catch it in your documentation if the test fails, or name the method something to show that it should only be used as a hook to the validator, as I've done with someTextFieldValidatorHook.
Scrubbing

One last benefit of the validator is that it gives you a good way to scrub your data before you save it. Since your callback function (someTextFieldValidatorHook in our case) takes the value in to verify it and returns it at the end if the test passed, you can technically change it to whatever you want. Some possible ideas are:

1. Removing HTML
2. Converting text links to actual links (bad example as you should probably do this on output)
3. Formatting Phone Numbers
4. Etc, etc

That's It

Hope you found this useful. Feel free to share how you've used the callback validator in your applications.



You can find the original post here : http://www.pbtg.com/blogs/jim/tag/symfony

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.