itlong 发表于 2008-6-11 10:50:04

解决:validation在model里使用, callback会出问题

一般教程上使用时,数据检测都是在controler里测试,可是MVC的原则就是数据处理的任务是交给model处理的,所以今天我在表单提交处理数据的时间,是在model里面处理:代码如下:
controller:

class Form extends Controller
{
    function Form()
    {
      parent::Controller();
      $this->load->helper(array('url', 'form'));
      $this->load->model('form_model');
    }
    function index()
    {
      $this->load->view('myform');
    }
    function dosubmit()
    {
         $this->form_model->dosubmit();
    }
}
==============================================================
model:

class Form_model extends Model
{
    function Form_model()
    {
      parent::Model();
      $this->load->library('validation');
    }
    function dosubmit()
    {
      $rules['username'] = "callback_username_check";
      $rules['password'] = "required";
      $this->validation->set_rules($rules);   
      if ($this->validation->run() == false)
      {
            $this->load->view('myform');
         }
      else
      {
             return true;
         }
   }//end dosubmit

    function username_check($str)
    {
      if($str=='test')
      {
            $this->validation->set_message('username_check', ' %s 不能为 "test"');
            return false;
      }
      else
      {
            return true;
      }
    }//end username_check

}//end model

===================================================================
myform:
<html>
<head>
<title>My Form</title>
<meta http-equiv="Content-Type" c />
</head>
<body>
<?=$this->validation->error_string; ?>
<?=form_open('form/dosubmit');?>
<input type="text" name="username"><br />
<input type="text" name="password"><br />
</form>
</body>
</html>


===================================================
测试结果是:
当用户名username为“test”时,检测不出有错误 ,password为空时可以检测出错误。
就是说明,在model里不能用到validation 的回调函数???

请高手指出问题所在。

itlong 发表于 2008-6-11 11:23:43

在英文wiki上找了一下,终于找到了解决方法:
http://codeigniter.com/wiki/MY_Validation_-_Callbacks_into_Models/
方法是要扩展一下validation,文章好像在说,在比目前版本更高版本将来会更新。
做法如下:
model:

class Form_model extends Model
{
    function Form_model()
    {
      parent::Model();
      $this->load->library('validation');
    }
    function dosubmit()
    {
  $this->validation->set_rules(array(
            'username'    => 'trim|required|callback_form_model->is_unique',
            'password'    => 'trim|required|matches',
      ));
      $this->validation->set_rules($rules);   
      if ($this->validation->run() == false)
      {
            $this->load->view('myform');
         }
      else
      {
             return true;
         }
   }//end dosubmit

   function is_unique($value)
   {
         if($value =='test')
          {
         $this->validation->set_message('form_mode->is_unique', ' The %s 不能为"rest"');
          return false;
          }
          else
         {
               return true;
         }
    /*
    $this->db->where($field,$value);
    $this->db->from($this->_table);
    return ($this->db->count_all_results() == 0);
    */这里是从数库里找出是否存在username这一记录。如果存在则返回false;
}

}//end model

itlong 发表于 2008-6-11 11:25:32

//把下面代码存为application/libraries/MY_Validation.php
<?phpif (!defined('BASEPATH')) exit('No direct script access allowed');

/**
* MY_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
*/

class MY_Validation extends CI_Validation
{
    function get_fields()
    {
      return $this->_fields;
    }
   
    /**
   * Run the Validator
   *
   * This function does all the work.
   *
   * @access    public
   * @return    bool
   */      
    function run(&$parent = NULL)
    {      
      // Do we even have any data to process?Hmm?
      if (count($_POST) == 0 OR count($this->_rules) == 0)
      {
            return FALSE;
      }
      
      isset($parent) OR $parent = $this->CI;
      
      // Load the language file containing error messages
      $parent->load->language('validation');
                           
      // Cycle through the rules and test for errors
      foreach ($this->_rules as $field => $rules)
      {
            //Explode out the rules!
            $ex = explode('|', $rules);

            // Is the field required?If not, if the field is blankwe'll move on to the next test
            if ( ! in_array('required', $ex, TRUE))
            {
                if ( ! isset($_POST[$field]) OR $_POST[$field] == '')
                {
                  continue;
                }
            }
            
            /*
             * Are we dealing with an "isset" rule?
             *
             * Before going further, we'll see if one of the rules
             * is to check whether the item is set (typically this
             * applies only to checkboxes).If so, we'll
             * test for it here since there's not reason to go
             * further
             */
            if ( ! isset($_POST[$field]))
            {            
                if (in_array('isset', $ex, TRUE) OR in_array('required', $ex))
                {
                  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
                  $mfield = ( ! isset($this->_fields[$field])) ? $field : $this->_fields[$field];
                  $message = sprintf($line, $mfield);

                  // Set the error variable.Example: $this->username_error
                  $error = $field.'_error';
                  $this->$error = $this->_error_prefix.$message.$this->_error_suffix;
                  $this->_error_array[] = $message;
                }
                        
                continue;
            }
   
            /*
             * Set the current field
             *
             * The various prepping functions need to know the
             * current field name so they can do this:
             *
             * $_POST[$this->_current_field] == 'bla bla';
             */
            $this->_current_field = $field;

            // Cycle through the rules!
            foreach ($ex As $rule)
            {
                // 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
                $param = FALSE;
                if (preg_match("/(.*?)\[(.*?)\]/", $rule, $match))
                {
                  $rule    = $match;
                  $param    = $match;
                }

    // 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($_POST[$field], $param);
      }
      else
      {
            if ( ! method_exists($parent, $rule))
            {         
                continue;
            }
            
            $result = $parent->$rule($_POST[$field], $param);   
      }
      
      /* Original code continues */
      
      // 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))
                  {
                        /*
                         * 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))
                        {
                            $_POST[$field] = $rule($_POST[$field]);
                            $this->$field = $_POST[$field];
                        }
                                          
                        continue;
                  }
                  
                  $result = $this->$rule($_POST[$field], $param);
                }
                              
                // 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
                  $mfield = ( ! isset($this->_fields[$field])) ? $field : $this->_fields[$field];
                  $mparam = ( ! isset($this->_fields[$param])) ? $param : $this->_fields[$param];
                  $message = sprintf($line, $mfield, $mparam);
                  
                  // Set the error variable.Example: $this->username_error
                  $error = $field.'_error';
                  $this->$error = $this->_error_prefix.$message.$this->_error_suffix;

                  // Add the error to the error array
                  $this->_error_array[] = $message;               
                  
                  continue 2;
                }               
            }
            
      }
      
      $total_errors = count($this->_error_array);

      /*
         * Recompile the class variables
         *
         * If any prepping functions were called the $_POST data
         * might now be different then the corresponding class
         * variables so we'll set them anew.
         */   
      if ($total_errors > 0)
      {
            $this->_safe_form_data = TRUE;
      }
      
      $this->set_fields();

      // Did we end up with any errors?
      if ($total_errors == 0)
      {
            return TRUE;
      }
      
      // Generate the error string
      foreach ($this->_error_array as $val)
      {
            $this->error_string .= $this->_error_prefix.$val.$this->_error_suffix."\n";
      }

      return FALSE;
    }
}

itlong 发表于 2008-6-11 11:52:03

重要注意:
你在controller里$this->load->model('form_model');时,如果自己定义了一个名字,如“validmodel”,一定要保持model里:
==============================(以下是默认)===================================
  $this->validation->set_rules(array(
            'username'    => 'trim|required|callback_form_model->is_unique',
            'password'    => 'trim|required|matches',
      ));
===================================================================
$this->validation->set_message(’form_model->is_unique‘, ' %s 不能为 "test"');
===================================================================


要改为:
  $this->validation->set_rules(array(
            'username'    => 'trim|required|callback_validmodel->is_unique',
            'password'    => 'trim|required|matches',
      ));
===================================================================
$this->validation->set_message(’validmodel->is_unique‘, ' %s 不能为 "test"');
===================================================================

可以看出,在model 里,validation回调函数里是在contoller实例化时的对象函数。
页: [1]
查看完整版本: 解决:validation在model里使用, callback会出问题