Welcome Guest, Not a member yet? Register   Sign In
Conditional validation rule - "depends_on[field_name]"
#1

[eluser]Mike Ryan[/eluser]
Hi everyone,

I have made some modifications to the form validation class which I hope some of you will find useful. The change is a simple one - I have added a new validation rule, "depends_on", which sets up a parent/child relationship between two fields so that validation for field_b is only performed if field_a is set. I use this to validate fields only if a particular checkbox is set. For example:

View:
Code:
<?php echo form_error('first_name'); ?>
<input type="text" name="first_name" value="<?php echo set_value('first_name'); ?>" maxlength="50" />

<INPUT TYPE=CHECKBOX NAME="send_newsletter">
    
<?php echo form_error('email'); ?>
<input type="text" name="email" value="<?php echo set_value('email'); ?>" />

<input type=submit>

Controller:
Code:
$rules = array(
        array(
            'field'   => 'email',
            'label'   => 'Email address',
            'rules'   => 'required|valid_email|depends_on[send_newsletter]'
            ),
        array(
            'field'   => 'first_name',
            'label'   => 'name',
            'rules'   => 'required'
            )
        );    
$this->load->library('form_validation');
$this->form_validation->set_rules($rules);


If "send_newsletter" is ticked, the email field will be validated as normal. If it is unticked, no validation is performed on the email field.

To implement this change, some minor additions to system/libraries/Form_validation.php are required:

Add this function:
Code:
function depends_on($field)
{  
    return (isset($_POST[$field]));
}

Add this code to the _execute function, just before "Isset Test" (line ~510)
Code:
// Depends_on Test. If the depends_on field is not set, no further tests are necessary
        if (preg_match("/depends_on\[(.*?)\]/",  implode(' ', $rules), $match))
        {
            $parent_field    = $match[1];
            if ( ! $this->depends_on($parent_field) )
            {
                // Before we bail out, does the rule contain a callback?
                if (preg_match("/(callback_\w+)/", implode(' ', $rules), $match))
                {
                    $callback = TRUE;
                    $rules = (array('1' => $match[1]));
                }
                else
                {
                    return;
                }
            }
        }

Add this code to the _execute function, just after if ($result === FALSE)
Code:
if ( $rule == "depends_on" )
{
    return; //there is no error message, so return now
}

My modified Form_validation.php is attached. This is my first contribution to the CI community, so comments and suggestions are most welcome. I am aware from reading the forums that other people have approached this problem in a different way. For those to whom the "P" in LAMP isn't necessarily PHP, TMTOWTDI ;-)
#2

[eluser]hugle[/eluser]
In one of your posts, you wrote that you are planning to look into it, and make it like an extention for Form Validation.

Had you any sucess with it?

Nice contribution Mike!

thanks
#3

[eluser]davidbehler[/eluser]
Sounds nice so far, but I got one suggestion for you:

Don't replace the CI core library but extend it. Place a file called "MY_Form_validation.php" in your application/libraries/ folder and in that file you do this:
Code:
class MY_Form_validation extends CI_Form_validation {

    function My_Form_validation()
    {
        parent::CI_Form_validation();
    }
}
Now you take all the functions you want to add/change and place them inside that new file. And now CI will automatically use this extended library instead of the core library in the system/libraries folder. That way you don't have to change system files and can update much more easily.

See the user guide for further info on that topic.

Otherwise, keep up the nice work Smile
#4

[eluser]hugle[/eluser]
[quote author="waldmeister" date="1227276264"]Sounds nice so far, but I got one suggestion for you:

Don't replace the CI core library but extend it. Place a file called "MY_Form_validation.php" in your application/libraries/ folder and in that file you do this:
Code:
class MY_Form_validation extends CI_Form_validation {

    function My_Form_validation()
    {
        parent::CI_Form_validation();
    }
}
Now you take all the functions you want to add/change and place them inside that new file. And now CI will automatically use this extended library instead of the core library in the system/libraries folder. That way you don't have to change system files and can update much more easily.

See the user guide for further info on that topic.

Otherwise, keep up the nice work Smile[/quote]

You are on time waldmeister Smile
thanks for your explanation. I'm currently playing with MY_* extends CI_* hehe Smile

and just got your tips Smile

thank you Smile
#5

[eluser]xwero[/eluser]
I like the idea to add field relationships using rules but as your example shows it's not so easy when you have to deal with checkboxes/radio buttons.
Also in your rules you have to add the required rule to the email field but that rule should be replaced by the depends_on rule because that is the flag that makes the email field required. Now consider this scenario;

You have a radio button list with following values: full name, e-mail and username. The raddio button list is coupled with a textfield where you have to input one of those things.

This is an advanced field relationship but it shows better that checking for field relationships can have effects on the rules of a field. That is why i think the validation library should have a mechanism to handle the changing of rules build in that is not a hack like your code, i write this will all due respect. Something like
Code:
$rule['email'] =
array(
      'parent_value[fieldname]'=>
          array(
                '1'=>'required|email',
                'default'=>'missing_parent' // could be moved to the parent_value rule
               )
     );
I went back to the pre 1.7 validation syntax to emphasize the rules part. But as you can imagine adding field relationships can create monstrous rules.

An alternative would be to extend the required rule to accept parameters so you can do
Code:
$rule['email'] = 'required[newsletter,isset]';
The first parameter is the field and the second is the rule that needs to be fulfilled. The second parameter could cause problems if the rule requires parameters.
Code:
$rule['email'] = 'required[newsletter,max_length[200]]';

And with this alternative you can only add one relationship with one rule that needs to be fulfilled so it's limited. This could be solved by identifying the fields with a prefix and split the groups based on that.
Code:
$rule['email'] = 'required[field:newsletter,isset,value_not_zero,field:offers,isset]';


Excuse me for this long post but i just wanted to give more context to the field relationship problem and at the same time explain some ideas how to deal with it.
#6

[eluser]Colin Williams[/eluser]
Still pretending CI and radio/checkboxes don't get along? Very unfortunate....
#7

[eluser]xwero[/eluser]
Colin if the comment is addressed to me, i didn't mention anything like that. I wrote checking the field relations is difficult because they add levels of checks to the validation library where the current code is limited to one level. It's not a comment on how the library handles checkboxes/radio buttons.
#8

[eluser]Colin Williams[/eluser]
Not a comment directed to you at all, my friend, xwero. Just directed at the topic, and how absurd it seems, to me at least, that such validation is impossible within the framework as-is.
#9

[eluser]PeterGreffen[/eluser]
I know it's an old post, but anyway:

In the case that the input field 'newsletter_email' should only be validated IF the 'newsletter_checkbox' is checked, simply add the rule '|required' to the newsletter_email field ONLY WHEN the newsletter_checkbox is checked...

Code:
$required_if = $this->input->post('newsletter_checkbox') ? '|required' : '' ;
$this->form_validation->set_rules('newsletter_email', 'newsletter_email', 'trim'. $required_if .'|email');

How hard was that? Tongue




Theme © iAndrew 2016 - Forum software by © MyBB