Welcome Guest, Not a member yet? Register   Sign In
Form Validation "ignores" false results of custom functions placed in helper
#1

[eluser]Xelgen[/eluser]
Hello, stuck on this for hours, read the manual word-by-word but didn't understand the reasons.

So, I'm using custom functions for Form Validations in CI 1.7.0 .
When the function is in controller file, everything works perfect.
But as I have lot of functions being used in lot of different places, I wanted to place them all in helper file, let's say my_validation_helper.php

The weird things start here.

First of all I found out, that in this case you shouldn't use "callback_" prefix in rule. As if you do so, the fucntion will not be found and called. After looking through validation class source it looks reasonable.
When you place just function name in rules, it is being called, and processed.

BUT it looks like, Validation Class just "doesn't care" of what did function return.

Helper:
Code:
//* My validation helper file
<?php
function always_false($a)
    {        
        echo 'I\'m Always False'; //See if it is being called
        return FALSE;    
    }

My validation config:
Code:
$config = array(
                 'reciept' => array(
                                    array(
                                            'field' => 'reciept_number',
                                            'label' => 'Reciept Number',
                                            'rules' => 'trim|required|is_natural|exact_length[8]|always_false'
                                          
                                         ),
                                     ),
               );

My Controller:
Code:
function index()
    {        
        $this->load->library('form_validation');
        $this->load->helper('my_verification');    
        
            
        
        if ($this->form_validation->run('reciept') === FALSE)
        {
               $this->load->view('add');              
        }
        else
        {

               // SKIPPED - Processing data, and passing it to model
        
               $this->load->view('add_success', $data);
        }
}

So when I enter 8 digit number, in field, I should get a validation error, with "Unable to access an error message corresponding to your field name." error message, right? Instead validation is being considered as successfully passed, and controller sends data to the model. (yes, with "I'm always false" being echoed)

What can be the reason? And how to solve that?
Will do really appreciate any ideas.

P.S. Functions are working properly when called from controller. So helper loading and it's functions do work.

P.P.S. It's same if I write let's say php's is_bool function - string successfuly validates as "boolean".
#2

[eluser]Tom Schlick[/eluser]
when you call the custom function to be validated it must be prefixed with "callback_"

http://ellislab.com/codeigniter/user-gui...#callbacks

so it would be
Code:
$config = array(
                 'reciept' => array(
                                    array(
                                            'field' => 'reciept_number',
                                            'label' => 'Reciept Number',
                                            'rules' => 'trim|required|is_natural|exact_length[8]|callback_always_false'
                                          
                                         ),
                                     ),
               );
#3

[eluser]Xelgen[/eluser]
I've mentioned this problem in the beginning of my post. callback_ prefix works only if function is placed inside the controller, but if it's function from helper, or just native php function with callback_ prefix it will not be even called.

If you look through code of /system/libraries/Form_validation.php you can see that.

If you place "callback_" prefix in rule, $rule is being checked and executed only if it's in $this->CI object space.
Code:
// Starting from Line 590:
if ($callback === TRUE)
            {
                if ( ! method_exists($this->CI, $rule))
                {        
                    continue;
                }
                
                // Run the function and grab the result
                $result = $this->CI->$rule($postdata, $param);


So, it's not the reason.
#4

[eluser]Tom Schlick[/eluser]
why not place a function in the controller and have it call the helper function and have it return the data the helper function returns
#5

[eluser]xwero[/eluser]
You can put the rules in MY_Form_validation then you don't need to prefix them with callback_ and they are usable everywhere.

I wonder if you have many callbacks how many are really form specific?
#6

[eluser]Xelgen[/eluser]
Well I'll have to do that, if there will be no chance to understand how to make it in normal way.
There are lot of forms, with complicated verification, and same function is being used 4-5 times, in different controller. Code will be far away from being DRY, compact & nice, if I make it that way.

Still I think it is a bug, because if I return not bool(False), but let's say a string, everything still works fine. So I can process data during verification with a helper function. I'm also able to set error messages from that functions, but I can not "stop" it, and "mark" validation as failed.

May be I'll try another workaround, trying to place helper functions in $this->CI space, or using old-good, but so much not-CI-way: require/include methods, still IMHO it's workaround and not a proper solution.
#7

[eluser]Xelgen[/eluser]
[quote author="xwero" date="1232139988"]You can put the rules in MY_Form_validation then you don't need to prefix them with callback_ and they are usable everywhere.

I wonder if you have many callbacks how many are really form specific?[/quote]

Yeah, that's another wayaround.
Well, I'm still in a middle of project, but for now, there are about 9 functions, with 4 being universal, and called now from at least 2 controllers, and one or two controllers needing them, will be written soon.

P.S. Anyway thanks for your help guys Smile
#8

[eluser]ironyCurtain[/eluser]
This is not a bug--it is intended behavior. The variable reciept_number is processed and set to false, right after a string is printed. Form_validation takes the return value of your function as the new value of the receipt_number field. There's an assumption that you are performing some operation on it. This syntax is used frequently for core php functions that take one argument, like html_special_chars, mysql_real_escape_string, and others. Read the Form_validation section of the Userguide, starting at Prepping data.

To be evaluated in as a validation function by form_validation->run(), always_false would need to be prefixed with callback_ and put in the controller, or included in a class that inherits Form_validation. Sound like the the best solution for you is to put the universal functions you mentioned into MY_Form_validation.
#9

[eluser]Xelgen[/eluser]
Well, the thing is, that I can not think of any reason for such behavior to be intended. Again if we look at the manual, in form_validation.html#rulereference we see, that:
Quote:You can also use any native PHP functions that permit one parameter.


And as in this section we talk about rules, and not prepping data, I understand it as if I can use any PHP function (native or custom) that accepts one parameter, and returns bool(false) on fail for validation rules.

So I should be able to use, let's say native is_bool() function. But currently result is the same.
I just didn't find time, to try to make same thing, with old Validation class, and see if it acts the same way, or it's a problem which came with new class.

If we couldn't use any php function, then extending Form_validation class, with your own functions/methods would be reasonable. But as we obviously can use other, functions in rule, I treat extending class just for adding your functions as a workaround of problem.

And about your idea, that "Form_validation takes the return value of your function as the new value of the receipt_number field", I again can't agree.
In the manual, Callback section.
Quote:If your callback returns anything other then a boolean TRUE/FALSE it is assumed that the data is your newly processed form data.

So it shouldn't treat "false" as a new value. And actually it doesn't, as running same always_false(), over a reciept_value, didnt' change it's value, it still remained 8-digit number.

I've switched to other thing for a day or 2, but I feel more like going into source of Form_validation, and trying to fix problem myself and share fix with community, then extending Class, putting "aliases" in controller or making other tricks. Smile
#10

[eluser]ironyCurtain[/eluser]
[quote author="Xelgen" date="1232306715"]Well, the thing is, that I can not think of any reason for such behavior to be intended. Again if we look at the manual, in form_validation.html#rulereference we see, that:
Quote:You can also use any native PHP functions that permit one parameter.
[/quote]

Perhaps this is a place where the manual should be more explicit here about exactly what this means. This clearly isn't true for the current release, and I'm not sure about the old validation library.

[quote author="Xelgen" date="1232306715"]
And about your idea, that “Form_validation takes the return value of your function as the new value of the receipt_number field”, I again can’t agree.
In the manual, Callback section.

Quote:If your callback returns anything other then a boolean TRUE/FALSE it is assumed that the data is your newly processed form data.
[/quote]

Alright so it doesn't actually change the value if it returned boolean. I didn't bother trying it before I posted, but look at that line again. You're not using a callback, you're using a helper function. A callback is only a callback if it's prefixed with callback_. AFAIK CodeIgniter only uses functions that are not callbacks and undefined in Form_validation as data processors and not in the actual validation. This should probably either be changed or the docs should be modified to be more clear about what can and can't be done.

[quote author="Xelgen" date="1232306715"]
If we couldn't use any php function, then extending Form_validation class, with your own functions/methods would be reasonable. But as we obviously can use other, functions in rule, I treat extending class just for adding your functions as a workaround of problem.
[/quote][/quote]

What the docs do say is that you can use "native" php functions, and you are not using a native php function, you're defining a new function. This all doesn't really matter. I don't understand what the problem with extending Form_validation is. It's at the core of how you're supposed to work in CI. For example, if I wanted to add a validation function to check the database if a given value is unique, it's like 6 lines of code.
Code:
class MY_Form_validation extends CI_Form_validation
{
    function unique($value, $field)
    {
        list($table, $column) = explode('.', $field);
        $query = $this->CI->db->query("SELECT COUNT(*) dupe FROM $table WHERE $column = '$value' LIMIT 1");
        $row = $query->row();
        return ($row->dupe == 0);
    }
}

Then feel free to toss something like
Code:
'rules' => 'trim|required|is_natural|exact_length[8]|unique[receipt.id]'

into your $config array. That's the sort of thing you want, right?




Theme © iAndrew 2016 - Forum software by © MyBB