I had a similar problem except I wanted all my validation contained in my model, so I extended the Validation class to allow callback functions to be methods in any object(s) as well as regular procedural functions. Below is my extended Validation class (install according to user guide) and example usage. I hope it helps.
MY_Validation.php (I had to remove the comments to make it fit here. Refer to the original if you need them. The code I changed is contained withing // EDITED ... // /EDITED)
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
class MY_Validation extends CI_Validation {
function run()
{
if (count($_POST) == 0 OR count($this->_rules) == 0)
{
return FALSE;
}
$this->CI->lang->load('validation');
foreach ($this->_rules as $field => $rules)
{ $ex = explode('|', $rules);
if ( ! in_array('required', $ex, TRUE) AND strpos($rules, 'callback_') === FALSE)
{
if ( ! isset($_POST[$field]) OR $_POST[$field] == '')
{
continue;
}
}
if ( ! isset($_POST[$field]))
{
if (in_array('isset', $ex, TRUE) OR in_array('required', $ex))
{
if ( ! isset($this->_error_messages['isset']))
{
if (FALSE === ($line = $this->CI->lang->line('isset')))
{
$line = 'The field was not set';
}
}
else
{
$line = $this->_error_messages['isset'];
}
$field = ( ! isset($this->_fields[$field])) ? $field : $this->_fields[$field];
$this->_error_array[] = sprintf($line, $field);
}
continue;
}
$this->_current_field = $field;
foreach ($ex As $rule)
{
$callback = FALSE;
if (substr($rule, 0, 9) == 'callback_')
{
$rule = substr($rule, 9);
$callback = TRUE;
}
$param = FALSE;
if (preg_match("/(.*?)\[(.*?)\]/", $rule, $match))
{
$rule = $match[1];
$param = $match[2];
}
// Call the function that corresponds to the rule
if ($callback === TRUE)
{
// EDITED
unset($result);
if (!isset($this->callback_obj)) $this->callback_obj = array($this->CI);
if (!is_array($this->callback_obj)) $this->callback_obj = array($this->callback_obj);
if (function_exists($rule)) $result = $rule($_POST[$field], $param);
foreach ($this->callback_obj as $obj)
if (method_exists($obj, $rule)) $result = $obj->$rule($_POST[$field], $param);
// we didn't find the requested callback, continue
if (!isset($result)) continue;
// /EDITED
// If the field isn't required and we just processed a callback we'll move on...
if ( ! in_array('required', $ex, TRUE) AND $result !== FALSE)
{
continue 2;
}
}
else
{
if ( ! method_exists($this, $rule))
{
if (function_exists($rule))
{
$_POST[$field] = $rule($_POST[$field]);
$this->$field = $_POST[$field];
}
continue;
}
$result = $this->$rule($_POST[$field], $param);
}
if ($result === FALSE)
{
if ( ! isset($this->_error_messages[$rule]))
{
if (FALSE === ($line = $this->CI->lang->line($rule)))
{
$line = 'Unable to access an error message corresponding to your field name.';
}
}
else
{
$line = $this->_error_messages[$rule];;
}
$mfield = ( ! isset($this->_fields[$field])) ? $field : $this->_fields[$field];
$mparam = ( ! isset($this->_fields[$param])) ? $param : $this->_fields[$param];
$message = sprintf($line, $mfield, $mparam);
$error = $field.'_error';
$this->$error = $this->_error_prefix.$message.$this->_error_suffix;
$this->_error_array[] = $message;
continue 2;
}
}
}
$total_errors = count($this->_error_array);
if ($total_errors > 0)
{
$this->_safe_form_data = TRUE;
}
$this->set_fields();
if ($total_errors == 0)
{
return TRUE;
}
foreach ($this->_error_array as $val)
{
$this->error_string .= $this->_error_prefix.$val.$this->_error_suffix."\n";
}
return FALSE;
}
}
?>
Usage:
$this->load->library('mylibrary');
$this->load->library('validation');
$this->validation->callback_obj =& $this->mylibrary; // this can also be set to an array to mix callbacks from different objects, example: $this->validation->callback_obj = array($this, $this->mylibrary, $this->myotherlibrary);
$this->validation->set_rules(array(
'email' => 'callback_duplicateEmail'
));
$result = $this->validation->run();