Another idea for using models with forms

Tags:

Matthew Weier O’Phinney wrote about using Zend_Form with models. His approach puts a form inside a model, which then uses the form to validate itself.

While this idea is not bad, I find it being upside down – I think the form should use the model to validate itself, not the other way around.

But how would you utilize a model class to validate a form? I think there are two feasible ways to do so: A global model for a form, and a model-based validator class…

A global model for a form

This approach would basically tell a form “use this model to validate yourself”, or…

$form = new SomeForm();
$model = new SomeModel();
$form->setModel($model);
if($form->isValid($_POST))
{
  //something happens here
}

So in other words, you would set a model to a form, and when you call isValid, the form uses the model to validate itself.

This would depend on the model’s being built in a certain way, though: The model’s fields should be writable using setSomething(value) methods, and those methods should throw exceptions if the value passed to them was invalid. This is so that the form can collect the exceptions’ messages, and display them to the user, in a similar way as validator error messages are displayed – this time the validator just was the model.

You may notice a similarity between this and the modelform stuff I’ve been working on before. Indeed, the modelform class could be adapted for this, but this isn’t the same – the modelform generates a whole form based on the metadata for a model, but this would simply attempt to validate the form.

Finally, since this approach would use setters on the model instance we pass, the instance would get automatically filled with the values from the form for you if the form is valid.

A model based validator

This approach is basically the first but chopped into smaller pieces. Instead of assigning a model to the form, we’d assign a model to a validator, and tell it which method it should validate against.

$model = new SomeModel();
$validator = new CU_Validate_Model($model, 'foo');

then, you could assign the validator to a form field like any other validator, or use it as a stand-alone one. When the isValid method gets called, it would try to use setFoo method of the model, and catch any messages from an exception the model might throw.

This approach would require a bit more code when implementing a form, as you would need to define each field’s validator separately. However, it would also be more flexible, as you could have fields in your form that don’t get validated using the model, or you could even mix multiple models into the same form’s validation logic.

With this approach, you would also get model instances with the data from the form in case it’s valid.

In closing

I think both of these methods could be useful depending on the case. One might consider a minor flaw that they both require the model to perform in a specific way for it to work: use setSomething, and throw exceptions with invalid values. I don’t think that’s a flaw, though, since I think we can say that that kind of behavior is actually good for a model to have.

Both of these also add no additional dependencies to the model itself. They could also be used without zend_form, or zend framework – you would just need to implement it in a bit different way.

Since these are just ideas, there’s no code for you to consume. I may implement some of this later, or if you decide to go for it, feel free to share your code.

More on models:
The problems faced by a common model interface in frameworks
Food for thought: utilizing models in MVC
Decoupling models from the database: Data Access Object pattern in PHP