Part of the EllisLab Network
   
 
validation callbackfunction in own library?
Posted: 06 January 2007 04:11 PM   [ Ignore ]  
Grad Student
Rank
Total Posts:  61
Joined  11-27-2006

Hi,

i am just playing around with the validation function,
but i wonder how i may use a function located in one of my own libraries
as a callback function.

$rules['email']="required|callback_duplicateEmail";

isn’t working. probably because i have to call a function located in one of my own libs like so:

$this->mylibrary->duplicateEmail($email);

how may i solve this?
i dont want to put the callback function into the controller where the validation is made
as i want to reuse the duplicateEmail function in different places.

best regards,

Thadeus

Profile
 
 
Posted: 06 January 2007 07:10 PM   [ Ignore ]   [ # 1 ]  
Lab Assistant
RankRank
Total Posts:  144
Joined  09-08-2006

i would assume ur checking for dupe email in a DB?

if that is the case what i do is since its DB related is in my model i have an userExists method that checks both username and password and returns true or false accordingly.

then in my controller checking fields and what not i might have

if ($this->validation->run())
{
    $data
= $this->_registerFields();
            
    if (
$this->user_model->exists($data))
    
{
        $this
->validation->error_string = 'username or email address already exists.';
    
}
    
else
    
{

since its in my model i can call that method from anywhere in my code to check.

hope it gives you some help or triggers the light smile

Profile
 
 
Posted: 06 January 2007 10:26 PM   [ Ignore ]   [ # 2 ]  
Research Assistant
Avatar
RankRankRank
Total Posts:  486
Joined  09-14-2006

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();
 Signature 

Code Igniter 1.5.4 / CentOS 5 / PHP 5.2.3 / Apache 2.2.2 / MySQL 5.0.27

Profile
 
 
Posted: 07 January 2007 09:41 AM   [ Ignore ]   [ # 3 ]  
Grad Student
Rank
Total Posts:  61
Joined  11-27-2006

thanks a lot for your pointers! grin

Profile
 
 
Posted: 24 February 2007 05:30 PM   [ Ignore ]   [ # 4 ]  
Summer Student
Total Posts:  6
Joined  02-19-2007

Great job, man!!! You helped me so much!
This mechanism should be hard-coded into the next release!!!

Profile
 
 
Posted: 02 March 2007 11:36 AM   [ Ignore ]   [ # 5 ]  
Grad Student
Avatar
Rank
Total Posts:  88
Joined  01-12-2007

Does this still work with the current version of CI? I am trying to implement this now bit i can’t get it to work so far.

Profile
 
 
Posted: 02 March 2007 11:40 AM   [ Ignore ]   [ # 6 ]  
Research Assistant
Avatar
RankRankRank
Total Posts:  486
Joined  09-14-2006

It should still work. Are you seeing an error or is it just not validating as expected? Post the code you are using.

 Signature 

Code Igniter 1.5.4 / CentOS 5 / PHP 5.2.3 / Apache 2.2.2 / MySQL 5.0.27

Profile
 
 
Posted: 02 March 2007 11:53 AM   [ Ignore ]   [ # 7 ]  
Grad Student
Avatar
Rank
Total Posts:  88
Joined  01-12-2007

It’s not validating

Here’s the code

class Aanmelden extends Controller {

    
function __construct() {
        parent
::__construct();
        
$this->load->helper(array('form', 'url', 'my_validation', 'my_interface'));
        
$this->load->model('aanmelden_model');
        
$this->load->library('validation');
        
$this->validation->callback_obj =& $this->aanmelden_model;
        
$this->validation->set_error_delimiters('<li><span class="errorText">', '</span></li>');
    
}
    
    
function index() {
      
      
//this works
      //echo $this->aanmelden_model->isPaginaVrij('test-paginas');
      
    
$rules['pagina'] = "trim|required||alpha_dash|max_length[64]|pagina_format|callback_isPaginaVrij"; // <-this doesn't
    
$rules['title_tag'] = "required|max_length[128]|htmlspecialchars";
    
$rules['naam'] = "required|alpha_dash|max_length[64]";
    
$rules['email'] = "required|valid_email|max_length[128]";
    
$rules['email_bevestiging'] = "matches[email]";
    
$rules['wachtwoord'] = "required|alpha_dash|min_length[6]|max_length[32]";
    
$rules['wachtwoord_bevestiging'] = "matches[wachtwoord]";
    
$rules['adult'] = "required|numeric|max_length[1]";
    
$rules['voorwaarden'] = "required";
    
$this->validation->set_rules($rules);
   
    
$fields['pagina'] = 'Pagina naam';
    
$fields['title_tag'] = 'Pagina titel';
    
$fields['naam'] = 'Gebruikers naam';
    
$fields['email'] = 'Email';
    
$fields['email_bevestiging'] = 'Email bevestiging';
    
$fields['wachtwoord'] = 'Wachtwoord';
    
$fields['wachtwoord_bevestiging'] = 'Wachtwoord bevestiging';
    
$fields['adult'] = 'Adult';
    
$fields['voorwaarden'] = 'Voorwaarden';   
    
$this->validation->set_fields($fields);
    
    
$this->validation->set_message('isPaginaVrij', 'Pagina naam bestaat al');
    
      if (
$this->validation->run() == FALSE) {
        $data[
'navigation'] = get_components('menu, pagina_registratie, inloggen');
          
$data['layout_div'] = get_layout_divs('big');
            
$this->load->view('home/aanmelden_view', $data);
        
} else {
            $this
->load->view('beheer');
        
}        
    }
}

And the model

class Aanmelden_model extends Model {

  
function __construct() {
        parent
::__construct();
    
}
    
    
function isPaginaVrij($pagina) {
    $query
= $this->db->query('SELECT pagina FROM m_paginas WHERE pagina = ?', $pagina);
    return
$query->num_rows() > 0 ? FALSE : TRUE;
  
}
         
    
function isNaamVrij($naam) {
    $query
= $this->db->query('SELECT naam FROM m_gebruikers WHERE naam = ?', $naam);
    return
$query->num_rows() > 0 ? FALSE : TRUE;
  
}     
         
}
Profile
 
 
Posted: 02 March 2007 12:08 PM   [ Ignore ]   [ # 8 ]  
Research Assistant
Avatar
RankRankRank
Total Posts:  486
Joined  09-14-2006

You need to set an error message in your callback function before returning false. Something like:

function isNaamVrij($naam) {
  $query
= $this->db->query('SELECT naam FROM m_gebruikers WHERE naam = ?', $naam);

  
$result = $query->num_rows() > 0 ? FALSE : TRUE;

  if (!
result) {
    $CI
=& get_instance();
    
$CI->validation->set_message('isNaamVrij', 'Your error message here.'isNaamVrij);
    return
false;
  
}

  
return true;
}
 Signature 

Code Igniter 1.5.4 / CentOS 5 / PHP 5.2.3 / Apache 2.2.2 / MySQL 5.0.27

Profile
 
 
Posted: 02 March 2007 01:02 PM   [ Ignore ]   [ # 9 ]  
Grad Student
Avatar
Rank
Total Posts:  88
Joined  01-12-2007

But that’s just a detail right? Or is that necessary? Anyway i have implemented that now but it still doesn’t work. I’ll try again in small towmorrow.

Also I agree with Element, this realy should be part of the core as it is an intuitive way to work, leaving it out suggest to me that the framework has small scale applications in mind.

Profile
 
 
Posted: 02 March 2007 01:12 PM   [ Ignore ]   [ # 10 ]  
Research Assistant
Avatar
RankRankRank
Total Posts:  486
Joined  09-14-2006

It’s necessary. The callback functions must explicitly set an error if there is not already an entry in the validation language file. You could also set the error in the language file instead if you like.

 Signature 

Code Igniter 1.5.4 / CentOS 5 / PHP 5.2.3 / Apache 2.2.2 / MySQL 5.0.27

Profile
 
 
Posted: 03 March 2007 06:35 AM   [ Ignore ]   [ # 11 ]  
Grad Student
Avatar
Rank
Total Posts:  88
Joined  01-12-2007

It turned out to be some foolish overlooking error, i placed MY_Validation in the system/libraries folder instead of application/libraries.

Thanks for this joeles!

Profile
 
 
Posted: 05 April 2007 12:07 PM   [ Ignore ]   [ # 12 ]  
Summer Student
Total Posts:  21
Joined  02-05-2007

joeles,
Just wanted to let you know - I believe there is a rather serious bug in your code. You see when you set the “callbackobj” you pass it by reference right.

Then later, if the callbackobj is set and not an array you change it too an array which actually also changes the class you are referencing! So the code works fine if you use callbackobj as an array in the first place, but the minute you use it directly as in your example if you later try to reference that object - you will run into problems.

Other than that - awesome little update, thanks!

Profile
 
 
   
 
 
Post Marker Legend
New Topic New posts Hot Topic Hot Topic with new posts New Poll New Poll Moved Topic Moved Topic Sticky Topic Sticky topic
Old Topic No new posts Hot Old Topic Hot Topic with no new posts Old Poll Old Poll Closed Topic Closed Topic Announcement Announcements
Theme
Change Theme
Visitor Statistics
The most visitors ever was 819, on March 11, 2010 11:15 AM
Total Registered Members: 120382 Total Logged-in Users: 19
Total Topics: 126499 Total Anonymous Users: 2
Total Replies: 665229 Total Guests: 326
Total Posts: 791728    
Members ( View Memberlist )