Skip to content

MY Form validation Callbacks into Models

World Wide Web Server edited this page Jul 4, 2012 · 5 revisions

Category:Libraries::Validation | Category:Libraries::Community

Setting Up: [code] $this->form_validation->set_rules('username','User Name', 'trim|required|callback_users_model->is_unique[username]');

[/code]

The callback function in users_model [code] /** * Validation callback **/ function is_unique($value, $field) { $this->form_validation->set_message('users_model->is_unique', "The %s {$value} is not available. Try a different username"); return (bool)(!$this->findBy("{$field} = '{$value}'")); }

[/code]

This is a more advanced version of the previous callbacks into models extension. You may pass the calling object to the Validation class. ie: $this->form_validation->run($this); If not it wil use the CI super object by default.

Note: At line 95, a 'NULL' value is inserted as the fourth argument. That translates to the Form_validation's _execute method as the default argument cycles=0. Not sure what affect that will have yet, but in order to keep Wiredesignz' $parent variable intact, _execute had to be extended to a fifth argument. $parent is intended to support Modular Extensions, but that compatibility has not yet been verified. Modular users, please step in here and verify. --Thanks, Brad

application/libraries/MY_Form_validation.php [code] <?php if (!defined('BASEPATH')) exit('No direct script access allowed');

/**

  • MY_Form_validation extension
  • Allows callback functions into Models
  • Usage:
  • Pass the caller to the validation class
  • $this->validation->run($this);
  • Version 0.3 (c) Wiredesignz 2008-04-24
  • Version 0.4 modified by Bradford Mar 2008-08-27 */

class MY_Form_validation extends CI_Form_validation {

function get_fields()
{
    return $this->_fields;
}

/**
 * Run the Validator
 *
 * This function does all the work.
 *
 * @access    public
 * @return    bool
 */        
function run($group = '', &$parent = NULL)
{
    // Do we even have any data to process?  Mm?
    if (count($_POST) == 0)
    {
        return FALSE;
    }
    
    isset($parent) OR $parent = $this->CI;

    // Does the _field_data array containing the validation rules exist?
    // If not, we look to see if they were assigned via a config file
    if (count($this->_field_data) == 0)
    {
        // No validation rules?  We're done...
        if (count($this->_config_rules) == 0)
        {
            return FALSE;
        }
        
        // Is there a validation rule for the particular URI being accessed?
        $uri = ($group == '') ? trim($parent->uri->ruri_string(), '/') : $group;
        
        if ($uri != '' AND isset($this->_config_rules[$uri]))
        {
            $this->set_rules($this->_config_rules[$uri]);
        }
        else
        {
            $this->set_rules($this->_config_rules);
        }

        // We're we able to set the rules correctly?
        if (count($this->_field_data) == 0)
        {
            log_message('debug', "Unable to find validation rules");
            return FALSE;
        }
    }

    // Load the language file containing error messages
    $parent->lang->load('form_validation');
                        
    // Cycle through the rules for each field, match the 
    // corresponding $_POST item and test for errors
    foreach ($this->_field_data as $field => $row)
    {        
        // Fetch the data from the corresponding $_POST array and cache it in the _field_data array.
        // Depending on whether the field name is an array or a string will determine where we get it from.
        
        if ($row['is_array'] == TRUE)
        {
            $this->_field_data[$field]['postdata'] = $this->_reduce_array($_POST, $row['keys']);
        }
        else
        {
            if (isset($_POST[$field]))
            {
                $this->_field_data[$field]['postdata'] = $_POST[$field];
            }
        }
    
        $this->_execute($row, explode('|', $row['rules']), $this->_field_data[$field]['postdata'], NULL, $parent);        
    }

    // Did we end up with any errors?
    $total_errors = count($this->_error_array);

    if ($total_errors > 0)
    {
        $this->_safe_form_data = TRUE;
    }

    // Now we need to re-set the POST data with the new, processed data
    $this->_reset_post_array();
    
    // No errors, validation passes!
    if ($total_errors == 0)
    {
        return TRUE;
    }

    // Validation fails
    return FALSE;
}

// --------------------------------------------------------------------

/**
 * Executes the Validation routines
 *
 * @access    private
 * @param    array
 * @param    array
 * @param    mixed
 * @param    integer
 * @return    mixed
 */    
function _execute($row, $rules, $postdata = NULL, $cycles = 0, &$parent)
{
    // If the $_POST data is an array we will run a recursive call
    if (is_array($postdata))
    { 
        foreach ($postdata as $key => $val)
        {
            $this->_execute($row, $rules, $val, $cycles, $parent);
            $cycles++;
        }
        
        return;
    }

    // --------------------------------------------------------------------

    // If the field is blank, but NOT required, no further tests are necessary
    if ( ! in_array('required', $rules, TRUE) AND is_null($postdata))
    {
        return;
    }

    // --------------------------------------------------------------------
    
    // Isset Test. Typically this rule will only apply to checkboxes.
    if (is_null($postdata))
    {            
        if (in_array('isset', $rules, TRUE) OR in_array('required', $rules))
        {
            if ( ! isset($this->_error_messages['isset']))
            {
                if (FALSE === ($line = $parent->lang->line('isset')))
                {
                    $line = 'The field was not set';
                }                            
            }
            else
            {
                $line = $this->_error_messages['isset'];
            }
            
            // Build the error message
            $message = sprintf($line, $row['label']);

            // Save the error message
            $this->_field_data[$row['field']]['error'] = $message;
            
            if ( ! isset($this->_error_array[$row['field']]))
            {
                $this->_error_array[$row['field']] = $message;
            }
        }
                
        return;
    }

    // --------------------------------------------------------------------

    // Cycle through each rule and run it
    foreach ($rules As $rule)
    {
        $_in_array = FALSE;
        
        // We set the $postdata variable with the current data in our master array so that
        // each cycle of the loop is dealing with the processed data from the last cycle
        if ($row['is_array'] == TRUE AND is_array($this->_field_data[$row['field']]['postdata']))
        {
            // We shouldn't need this safety, but just in case there isn't an array index
            // associated with this cycle we'll bail out
            if ( ! isset($this->_field_data[$row['field']]['postdata'][$cycles]))
            {
                continue;
            }
        
            $postdata = $this->_field_data[$row['field']]['postdata'][$cycles];
            $_in_array = TRUE;
        }
        else
        {
            $postdata = $this->_field_data[$row['field']]['postdata'];
        }

        // --------------------------------------------------------------------

        // Is the rule a callback?            
        $callback = FALSE;
        if (substr($rule, 0, 9) == 'callback_')
        {
            $rule = substr($rule, 9);
            $callback = TRUE;
        }
        
        // Strip the parameter (if exists) from the rule
        // Rules can contain a parameter: max_length[5]
        $param = FALSE;
        if (preg_match("/(.*?)\[(.*?)\]/", $rule, $match))
        {
            $rule    = $match[1];
            $param    = $match[2];
        }
        
        // Call the function that corresponds to the rule
        if ($callback === TRUE)
        {

            /* Allows callbacks into Models */
            
            if (list($class, $method) = split('->', $rule))
            {
                if ( ! method_exists($parent->$class, $method))
                {         
                    continue;
                }
            
                $result = $parent->$class->$method($postdata, $param);
            }
            else
            {
                if ( ! method_exists($parent, $rule))
                {         
                    continue;
                }
                
                $result = $parent->$rule($postdata, $param);    
            }
            
            /* Original code removed */
            
            /*if ( ! method_exists($parent, $rule))
            {         
                continue;
            }
            
            // Run the function and grab the result
            $result = $parent->$rule($postdata, $param);*/
            
            /* Original code continues */

            // Re-assign the result to the master data array
            if ($_in_array == TRUE)
            {
                $this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result;
            }
            else
            {
                $this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result;
            }
        
            // If the field isn't required and we just processed a callback we'll move on...
            if ( ! in_array('required', $rules, TRUE) AND $result !== FALSE)
            {
                return;
            }
        }
        else
        {                
            if ( ! method_exists($this, $rule))
            {
                /*
                 * Run the native PHP function if called for
                 *
                 * If our own wrapper function doesn't exist we see
                 * if a native PHP function does. Users can use
                 * any native PHP function call that has one param.
                 */
                if (function_exists($rule))
                {
                    $result = $rule($postdata);
                                        
                    if ($_in_array == TRUE)
                    {
                        $this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result;
                    }
                    else
                    {
                        $this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result;
                    }
                }
                                    
                continue;
            }

            $result = $this->$rule($postdata, $param);

            if ($_in_array == TRUE)
            {
                $this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result;
            }
            else
            {
                $this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result;
            }
        }
                        
        // Did the rule test negatively?  If so, grab the error.
        if ($result === FALSE)
        {
            if ( ! isset($this->_error_messages[$rule]))
            {
                if (FALSE === ($line = $parent->lang->line($rule)))
                {
                    $line = 'Unable to access an error message corresponding to your field name.';
                }                        
            }
            else
            {
                $line = $this->_error_messages[$rule];
            }                

            // Build the error message
            $message = sprintf($line, $row['label'], $param);

            // Save the error message
            $this->_field_data[$row['field']]['error'] = $message;
            
            if ( ! isset($this->_error_array[$row['field']]))
            {
                $this->_error_array[$row['field']] = $message;
            }
            
            return;
        }
    }
}    

} // END MY_Form_validation Class

/* End of file MY_Form_validation.php / / Location: ./system/application/libraries/MY_Form_validation.php */ [/code]

Clone this wiki locally