Welcome Guest, Not a member yet? Register   Sign In
[EDIT: My bad, not a Bug]: Form Validation with Callable Rules
#1

(This post was last modified: 02-05-2016, 07:22 AM by Chip.)

May not be used very often, but I hit an issue when using callable rules in form validation.

Overview & A Refresher
Quick refresh, this is when you are setting up a custom rule but instead of using a function in your controller you want to use one that exists elsewhere (for instance, in a model). An example:

If you have a form that needs a user to select a valid product from a drop down (drop down has product id as value and product name as the option), it'd be nice to have a call back that checks the submitted id against those in the database to make sure it's valid. Old school way is to have a public function product_id_check in your controller. Better way (in my opinion) is to have this in your product model:

PHP Code:
    public function is_valid_product_id($product_id=0)
    {
        
$result $this->db->get_where('products', array('id'=>$product_id));
        return (
$result->num_rows() > 0);
    } 

So to call this model function directly from the controller where you are setting up validation, you would set a rule and it's corresponding message like this:

PHP Code:
    $this->load->model('products_model''products');
    
$this->form_validation->set_rules(
     
  'product_id''Product',
     
  array(
 
             'required',
 
             array($this->products'is_valid_product_id')
     
  ),
     
  array(
     
     'is_valid_product_id' => 'Please select a product.'
     
  )
    ); 

The Validation Library checks to see if it can call the function 'is_valid_product_id' either on it's own, or as a part of the passed in object. If that function is callable then it sends it the single parameter and looks for a true or false back. This works as intended. The last array there sets the message. There's a small issue here in that you could have a collision (what if you are using two different 'is_valid_product_id' check functions in the same validation?) but that's a pretty extreme edge case if you're naming your functions descriptively enough.

The bug I encountered is that that error message is never being returned.


The Bug

At this time the message you will always receive back if your validation check returns FALSE is:

Quote:Unable to access an error message corresponding to your field name {field}.(Anonymous function)

The custom error message is never returned. 

This generic error message is returned on line 820 of Form_validation.php. It's being thrown because $rule is ALWAYS being set to TRUE (a boolean) when it should be set to the string name of your function (in the example above it should be equal to 'is_valid_product_id'). The validation library uses this string to see if an error message has been set for that function name.

Tracking back, line 754 in Form_validation.php has:

PHP Code:
if ($callable !== FALSE)
{
 
  $rule $callable;


I'm guessing the intent was that if $callable isn't false then it would be set to the name of the function?

Anyway, replacing this if statement with some code that set's $rule to the ACTUAL function name fixes things:

PHP Code:
$rule $rule[1]; 

And that's what I've done. But I'm not sure if that could throw off anything else expecting $rule to be a boolean. Even though throughout it appears that it never should be.

Side note, I thought about simply updating the check "if ($callable !== FALSE)" to "if (!is_bool($callable))" to preserve whatever the original intent of this piece of code was, but if you do that you still won't be setting $rule to the proper function/message name. It looks like this may be an instance of a dev checking for FALSE instead of atually checking for the type BOOLEAN. So you could also do this:

PHP Code:
if (is_bool($callable))
{
    
$rule $rule[1];
}
else
{
    
$rule $callable;


But not understanding the intent of ever setting $rule to $callable I went with the more permanent fix.
Reply
#2

Why not just submit a pull request?
Reply
#3

It's not a bug, you have to explicitly name the rule, like shown in the documentation: http://www.codeigniter.com/userguide3/li...-as-a-rule (third example).

I'm surprised to see that you've actually thought of the possible rule name collision, yet you didn't realize that's exactly why it works that way.
Reply
#4

@ skunkbad Didn't want to throw out a pull request if in case I was missing something. Thanks to Narf, I see that I was.

@ Narf, thanks for the correction.
Reply




Theme © iAndrew 2016 - Forum software by © MyBB