Validation class
Moderator: General Moderators
- allspiritseve
- DevNet Resident
- Posts: 1174
- Joined: Thu Mar 06, 2008 8:23 am
- Location: Ann Arbor, MI (USA)
Validation class
I would like to write a custom validation class that I can quickly implement and build on for my projects. Originally I was going to place the logic in my data gateways, but I decided it would be better to abstract out the validation into its own class. I was thinking I could maybe model it in a testing style-- setUp and tearDown methods that validate all the data (required fields, etc) and then individual methods for each field. These methods could include assertions that are simple at first-- $this->assertTrue (...) and as I write more forms I can factor out more complex methods into a parent class: $this->assertValidEmail ('a@b.com'), etc. I could then pass this class into my gateway, and have it run when the save() method is called. Can anyone see any drawbacks to a system like this? Any feedback would be very much appreciated.
Thanks,
Cory
Thanks,
Cory
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Re: Validation class
Having a validation class is a good idea, however you intuition to put validation in the model was also correct. Use the validator object in the model if possible. Us a validator external to the model only when the model is essentially unknown -- e.g. CRUD. I prefer rule based validators, but you can build a find monolithic one.
(#10850)
Re: Validation class
Interesting. I've built my rule based validation class (or library) a while ago and it works fine, but I always pass it (actually my DI container doesarborint wrote:Having a validation class is a good idea, however you intuition to put validation in the model was also correct. Use the validator object in the model if possible. Us a validator external to the model only when the model is essentially unknown -- e.g. CRUD. I prefer rule based validators, but you can build a find monolithic one.
I figured the rule based approach (e.g. every rule is it's own objects) would make more sense. The reason is that different projects have different rules and I think having the rules in one, giant Validator would make for an explosion of rules. Nevertheless, I do think that approach could work well. When not having a lot of different rules, I'd say a monolithic approach would be fine. If you want a very reusable validator, which must be able to have rules generated on the fly, I'd go with the rule based approach.allspiritseve wrote:I would like to write a custom validation class that I can quickly implement and build on for my projects. Originally I was going to place the logic in my data gateways, but I decided it would be better to abstract out the validation into its own class. I was thinking I could maybe model it in a testing style-- setUp and tearDown methods that validate all the data (required fields, etc) and then individual methods for each field. These methods could include assertions that are simple at first-- $this->assertTrue (...) and as I write more forms I can factor out more complex methods into a parent class: $this->assertValidEmail ('a@b.com'), etc.
Btw, I remembered Troels Knak-Nielsen implementing a Validator object based on asserts: http://konstrukt.svn.sourceforge.net/vi ... iew=markup, perhaps it'll save you some work.
Like said, I pass it in to my object specific Data Mapper, and I like this approach. Nevertheless, I never really tried having validation in my domain objects, because it seems it's bad for reusability. Then again, who am Iallspiritseve wrote:I could then pass this class into my gateway, and have it run when the save() method is called. Can anyone see any drawbacks to a system like this? Any feedback would be very much appreciated.
Last edited by webaddict on Thu May 29, 2008 9:24 am, edited 1 time in total.
- allspiritseve
- DevNet Resident
- Posts: 1174
- Joined: Thu Mar 06, 2008 8:23 am
- Location: Ann Arbor, MI (USA)
Re: Validation class
It wouldn't be that monolithic, it could be as simple as $validator->assertTrue (!empty ($value))... just insert any true/false expression and you could validate just about anything. The process after that would be to take the common assertions between several validators, and place them in the class. I like what webaddict mentioned, the validator that kyberfabrikken wrote. I think that's a good example of what I'm going for.arborint wrote:I prefer rule based validators, but you can build a find monolithic one.
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Re: Validation class
I think the general argument is that the Model knows much more about the domain than the other parts of the app. If you have very reusable Models then they are probably DataSource objects with some of the logic in the Controller -- not really Models.webaddict wrote:Interesting. I've built my rule based validation class (or library) a while ago and it works fine, but I always pass it (actually my DI container does) to a Data Mapper, which calls the isValid method on the validation class. Why would you have to use the validator object in the model? I thought that it would be best not to, as validation rules can differ per use-case, or at least per project (reusable objects, that is). I'd love to hear arguments why my approach is silly, of which there is a good chance
![]()
For me there is difference between the Rules that determine whether a value is valid or not, and a Validator that runs Rules. You may be saying the same thing that I am. If your Valdiator has $validator->assertTrue () and $validator->assertEmail () and $validator->assertRegex() then it is monolithic and Rules can only be added by extending the class. If your Validator runs rules, like $validator->add(new RuleTrue()) and $validator->add(new RuleEmail()), then you can add any custom rules you want with simple composition.allspiritseve wrote:It wouldn't be that monolithic, it could be as simple as $validator->assertTrue (!empty ($value))... just insert any true/false expression and you could validate just about anything. The process after that would be to take the common assertions between several validators, and place them in the class. I like what webaddict mentioned, the validator that kyberfabrikken wrote. I think that's a good example of what I'm going for.
(#10850)
Re: Validation class
They are Domain Objects (or Bussiness Object, whatever suits your fancy) really, which reside in the domain model layer, so I'd say they are "real Models". Anyway, the reason I originally took the approach of passing in the Validator rather than hardcoding the Validator in the model itself, is that I figured that different use-cases (in the same project) can have different validation rules. However, when trying to find a decent example, I draw blank. So, there probably are little benefits (if any at all) for passing it, other than being able to mock it for unit testsarborint wrote:I think the general argument is that the Model knows much more about the domain than the other parts of the app. If you have very reusable Models then they are probably DataSource objects with some of the logic in the Controller -- not really Models.
I concur. Better yet, my Validator actually contains a set of rules which can be and/or'ed to combine rules, which in essence then becomes another rule, if that makes any sense. That makes my Validator really flexible.arborint wrote:For me there is difference between the Rules that determine whether a value is valid or not, and a Validator that runs Rules. You may be saying the same thing that I am. If your Valdiator has $validator->assertTrue () and $validator->assertEmail () and $validator->assertRegex() then it is monolithic and Rules can only be added by extending the class. If your Validator runs rules, like $validator->add(new RuleTrue()) and $validator->add(new RuleEmail()), then you can add any custom rules you want with simple composition.
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
- allspiritseve
- DevNet Resident
- Posts: 1174
- Joined: Thu Mar 06, 2008 8:23 am
- Location: Ann Arbor, MI (USA)
Re: Validation class
Any chance you can show us some code?webaddict wrote:I concur. Better yet, my Validator actually contains a set of rules which can be and/or'ed to combine rules, which in essence then becomes another rule, if that makes any sense. That makes my Validator really flexible.
Re: Validation class
Jup, I'll post it somewhere tonight or tomorrow.
- allspiritseve
- DevNet Resident
- Posts: 1174
- Joined: Thu Mar 06, 2008 8:23 am
- Location: Ann Arbor, MI (USA)
Re: Validation class
Ok, now I am trying to implement validation in a blog app I am writing. I do not think all validation belongs in the model, because as webaddict said, validation can differ depending on the use case. Therefore, I am trying to figure out exactly how to split my rules.
One idea I had was to look at each layer's responsibility-- the controller is responsible for reloading the form, therefore the controller should contain all of the rules that would result in a blog post not being submitted successfully and needing edits: ie, required title, min title length, required body, max body length, etc. Whatever it is, if an error would be displayed to the user, it belongs in the controller. The model (in the form of a gateway) is then responsible for adding or updating a domain object in the database. Therefore, the model should contain all the validation rules that would result in an application error (sent to a logger, maybe). Therefore, if I forgot to set the title in the domain object, the model would throw an exeption, the user would not see the form again with an error, but would be served a page that said a bug was found, and an email has been sent to the administrator, or whatever.
What do you guys think of that? Does that make sense?
One idea I had was to look at each layer's responsibility-- the controller is responsible for reloading the form, therefore the controller should contain all of the rules that would result in a blog post not being submitted successfully and needing edits: ie, required title, min title length, required body, max body length, etc. Whatever it is, if an error would be displayed to the user, it belongs in the controller. The model (in the form of a gateway) is then responsible for adding or updating a domain object in the database. Therefore, the model should contain all the validation rules that would result in an application error (sent to a logger, maybe). Therefore, if I forgot to set the title in the domain object, the model would throw an exeption, the user would not see the form again with an error, but would be served a page that said a bug was found, and an email has been sent to the administrator, or whatever.
What do you guys think of that? Does that make sense?
Re: Validation class
I think all the validation rules belong in the model. The model knows about its concrete storage type and its requirements and should encapsulate access to it. You should make your validation flexible enough that you can use part of it in a given scenario, but the entire set of validation rules should reside in the model.
The controller should then just invoke the validation methods of the model. The controller is only an intermediator between requests and models/views.
I wrote a piece on encapsulating validation logic in the models using the Zend Framework, if you are interested - http://www.techfounder.net/2008/05/21/m ... rk-part-2/
The controller should then just invoke the validation methods of the model. The controller is only an intermediator between requests and models/views.
I wrote a piece on encapsulating validation logic in the models using the Zend Framework, if you are interested - http://www.techfounder.net/2008/05/21/m ... rk-part-2/
- allspiritseve
- DevNet Resident
- Posts: 1174
- Joined: Thu Mar 06, 2008 8:23 am
- Location: Ann Arbor, MI (USA)
Re: Validation class
Do you think the model should be responsible for collecting errors and passing them to the controller then? What happens if there are different validation rules for different controllers? I can't think of a good example at the moment, but I'm sure that happens often.pytrin wrote:I think all the validation rules belong in the model. The model knows about its concrete storage type and its requirements and should encapsulate access to it. You should make your validation flexible enough that you can use part of it in a given scenario, but the entire set of validation rules should reside in the model.
The controller should then just invoke the validation methods of the model. The controller is only an intermediator between requests and models/views.
I wrote a piece on encapsulating validation logic in the models using the Zend Framework, if you are interested - http://www.techfounder.net/2008/05/21/m ... rk-part-2/
Re: Validation class
Different validation rules - for different models. The same model can not be used in different controllers with different validation rules - unless it is responsible for more than one data set. In this case I would argue that it should instance other models internally to handle the different data sets.
Lets talk use-cases for a minute:
When manipulating a data set you have 3 basic operations - create (ie database insert if we're talking databases), update and delete.
When creating a new data set, you want to make sure you have a minimum working set. I can not think of a use-case in which a partial set could be created (again for database, this means all fields not marked as null or having default values are required to validate).
For update operations you can update any combination of fields of the complete set, using the same rules as per creation (only this time none are required).
Delete operation is not really relevant for the validation process.
So the model needs to know:
- The complete set validation rules
- Which fields are required for the creation operation
I sometimes go a step further, and in security name I add:
- Which fields to exclude from being updated
If you could present me a use-case in which what I describe is insufficient then you might be able to convince me the model should not handle all validation.
Lets talk use-cases for a minute:
When manipulating a data set you have 3 basic operations - create (ie database insert if we're talking databases), update and delete.
When creating a new data set, you want to make sure you have a minimum working set. I can not think of a use-case in which a partial set could be created (again for database, this means all fields not marked as null or having default values are required to validate).
For update operations you can update any combination of fields of the complete set, using the same rules as per creation (only this time none are required).
Delete operation is not really relevant for the validation process.
So the model needs to know:
- The complete set validation rules
- Which fields are required for the creation operation
I sometimes go a step further, and in security name I add:
- Which fields to exclude from being updated
If you could present me a use-case in which what I describe is insufficient then you might be able to convince me the model should not handle all validation.
- allspiritseve
- DevNet Resident
- Posts: 1174
- Joined: Thu Mar 06, 2008 8:23 am
- Location: Ann Arbor, MI (USA)
Re: Validation class
I'm trying to think, and here a couple possible scenarios that update a user, but require different validation based on the use case:
A user wants to update their email. They are shown a screen with their password and two email address fields. Their password is required and must match the password in the database. The emails must match each other, and be valid emails.
An administrator wants to change a user's email. He is shown a screen with an email field (maybe two)? The email needs to be a valid email.
Unless I'm overthinking this, these would each require their own validation rules specific to the use-case, using the same model.
A user wants to update their email. They are shown a screen with their password and two email address fields. Their password is required and must match the password in the database. The emails must match each other, and be valid emails.
An administrator wants to change a user's email. He is shown a screen with an email field (maybe two)? The email needs to be a valid email.
Unless I'm overthinking this, these would each require their own validation rules specific to the use-case, using the same model.
Re: Validation class
Ok, good spot
What you are referring to is indeed outside the scope of the model. I was thinking you were talking about the actual data set validation rules, but for the use-case you described you need form validation rules which are context specific.
The model handles all the rules that pertain to the data it is manipulating - but nothing other than that. If you want to make sure the entered password a user submits is valid before updating his email then you should run that check before invoking the model validation routines. You could do that either in the controller, or add specific validation methods to the model (I like that option better if it has to retrieve data, like the password case you described).
Pseudo code:
What you are referring to is indeed outside the scope of the model. I was thinking you were talking about the actual data set validation rules, but for the use-case you described you need form validation rules which are context specific.
The model handles all the rules that pertain to the data it is manipulating - but nothing other than that. If you want to make sure the entered password a user submits is valid before updating his email then you should run that check before invoking the model validation routines. You could do that either in the controller, or add specific validation methods to the model (I like that option better if it has to retrieve data, like the password case you described).
Pseudo code:
Code: Select all
<?php
class FooController {
public function updateEmailAction() {
$data = $this -> getParams();
$users = new Users_Model();
$result = $users -> validatePasswordThenUpdate($data); //This will first check if the password is valid, then run the base validation routines
if($result === true) {
$this -> view -> success = true;
} else {
$this -> view -> errors = $result;
}
echo $this -> render();
}
}
?>