[eluser]housecor[/eluser]
For a given datamapper model, how should fields that are required on some forms and not required/used on others be handled? My idea was to pass a validation array into the constructor, but would love to hear how others are solving this.
For example, my User model has a required password field in the validation array. I'd like to use the same user model elsewhere on an abbreviated form that only requires a few user related fields and doesn't require a password.
[eluser]Spir[/eluser]
[quote author="housecor" date="1273859488"]For a given datamapper model, how should fields that are required on some forms and not required/used on others be handled? My idea was to pass a validation array into the constructor, but would love to hear how others are solving this.
For example, my User model has a required password field in the validation array. I'd like to use the same user model elsewhere on an abbreviated form that only requires a few user related fields and doesn't require a password.[/quote]Maybe you can pass a function to your validation and in that function make some tests?
Imagine you have a var in your class that tells whether to check or not the value. That function will test the var and if it's set to TRUE for instance it will ask for a data.
Not sure I'm clear.
Here is an example (quick and dirty) :
Code: class Object extends DataMapper {
var $validation = array('field' => Array('rules' => array('trim', '_check_value')));
var $doWeCheck_field = TRUE;
/**
* Validation function. Checks field value is in the list
*
* @access private
* @param string : field name
* @return bool
*/
function _check_value($field){
if ($this->doWeCheck_field) {
# check value
} else {
return TRUE;
}
return FALSE;
}
function set_check_field($bool=FALSE){
$this->doWeCheck_field=$bool;
}
}
in controller:
Code: $o = new Object();
$o->set_check_field(TRUE); // field will be required
$o->set_check_field(FALSE); // field will not be required
[eluser]housecor[/eluser]
Interesting approach, thanks for the reply! I'm currently going a different route. I'm setting all the "universal" fields in the standard datamapper fashion via $validation. Then, I've setup the constructor of my datamapper model to accept a single $form_type parameter. Based on that parameter, I know what additional fields should be validated.
Code: class User extends DataMapper {
//Note: These are default validation rules. Additional rules are set based on the form type
//passed into the constructor.
var $validation = array(
array('field' => 'prefix', 'label' => 'Prefix', 'rules' => array('required', 'trim', 'max_length' => 10)),
array('field' => 'first_name', 'label' => 'First Name', 'rules' => array('required', 'trim', 'max_length' => 200)),
array('field' => 'last_name', 'label' => 'Last Name', 'rules' => array('required', 'trim', 'max_length' => 200)),
array('field' => 'account_id', 'label' => 'Account ID', 'rules' => array('integer', 'max_length' => 6)),
array('field' => 'email', 'label' => 'Email Address', 'rules' => array('trim', 'unique', 'valid_email')),
array('field' => 'company', 'label' => 'Company', 'rules' => array('required', 'trim', 'max_length' => 200)),
array('field' => 'job_title', 'label' => 'Job Title', 'rules' => array('required', 'trim', 'max_length' => 200))
);
/**
* Constructor
* @param string form_type - Type of form being processed.
*/
function __construct($form_type = null) {
$this->set_custom_validation($form_type);
parent::__construct();
}
/**
* Sets custom validation fields based on the form_type passed.
* Useful so fields that are only required/used on certain forms
* aren't required on every form dealing with user data.
* NOTE: This doesn't overwrite the default validation
* set in the $validation property above, it merely adds
* addtional fields to validate.
* @return
*/
function set_custom_validation($form_type) {
switch ($form_type) {
case 'register':
$this->validation[] = array('field' => 'password', 'label' => 'Password', 'rules' => array('required', 'trim', 'min_length' => 6, 'max_length' => 40, 'hash'));
break;
case 'password_reset':
$this->validation[] = array('field' => 'password_reset_token', 'label' => 'Password Reset Token', 'rules' => array('max_length' => 32));
break;
}
}
So as you can see, the password is only required on the registration form. And the password reset token is only processed on the password reset page.
I'm pretty happy with this setup but also considered simply passing additional validation fields directly to the constructor rather than passing a form type.
[eluser]Spir[/eluser]
Sounds good. You should consider a default to your switch in case $form_type is null (since you allow null in the constructor).
[eluser]NachoF[/eluser]
Ok, so I have changed it to do this.
Code: $project->trans_begin();
if($project->save())
{
if($phase->save(array($project,$state)))
{
$project->trans_commit();
redirect("Success!");
}
else
$project->trans_rollback();
}
else
$phase->validate();//so that the form will also display validation errors from phase
It seems to be working... any advice is welcome though.
[eluser]Buso[/eluser]
[quote author="OverZealous" date="1273852143"] @Buso
Search for arrays in the manual. The first result is your answer. ;-)
[/quote]
Perfect! Thanks Phil
[eluser]Namaless[/eluser]
Sorry for stupid question, but is possible to get "dropdown" from DMZ?
[eluser]OverZealous[/eluser]
@housecor
I wouldn't replace the $validation array. Most likely this will lead to unexpected results, because of the manipulation that happens on that array. Also, DMZ only uses the first validation array for the object. That array is cached for the session, and is used to set up all further objects.
One way to handle sometimes-required objects is to add a custom _required method to your object. This method can then decide whether a field is required or not. (This may cause issues if you have other rules, and those other rules fail if the field is empty.)
It is a small problem if you need fields that are only sometimes required, because DMZ skips running the rest of the validation if the field is not required. I might look at adding a special rule, 'is_required', that allows an object to determine whether a field is required based on context. That might be awhile, though.
[eluser]housecor[/eluser]
Thanks Phil! To clarify, I'm not actually replacing the validation array - I'm merely adding some additional fields *before* the constructor is called. (I changed my example code above to reflect this). Since I'm still setting up the validation array before the constructor is called, I don't see how this could cause any issues. The technique is working great for me thus far, but as the author, if you still think I'm headed for trouble, please let me know.
BTW - Excellent work on DMZ! I really enjoy working with it and your documentation is superb.
[eluser]OverZealous[/eluser]
@housecor
That still might not be doing what you want!
The reason is that DMZ replaces the $validation array (along with some other parameters) from the statically cached copy! So, if you load in, say, a User model, however the validation array is configured at that moment is how all future Users are configured until the end of the HTTP request.
Hence my thoughts above. I'm liking the idea of a is_required function more and more, though. I am actually thinking about different ways to implement it, than my original idea, though.
|