用户
 找回密码
 入住 CI 中国社区
搜索
查看: 4617|回复: 3
收起左侧

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

[复制链接]
发表于 2008-6-11 10:50:04 | 显示全部楼层 |阅读模式
一般教程上使用时,数据检测都是在controler里测试,可是MVC的原则就是数据处理的任务是交给model处理的,所以今天我在表单提交处理数据的时间,是在model里面处理:代码如下:
controller:
PHP复制代码
 
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:
PHP复制代码
 
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复制代码
<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 的回调函数???

请高手指出问题所在。
 楼主| 发表于 2008-6-11 11:23:43 | 显示全部楼层
在英文wiki上找了一下,终于找到了解决方法:
http://codeigniter.com/wiki/MY_V ... lbacks_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[username]',
            'password'    => 'trim|required|matches[confirm]',
        ));
        $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
 楼主| 发表于 2008-6-11 11:25:32 | 显示全部楼层
//把下面代码存为application/libraries/MY_Validation.php
<?php  if (!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 blank  we'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[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($_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;
    }
}
 楼主| 发表于 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[username]',
            'password'    => 'trim|required|matches[confirm]',
        ));
===================================================================
$this->validation->set_message(’form_model->is_unique‘, ' %s 不能为 "test"');
===================================================================


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

可以看出,在model 里,validation回调函数里是在contoller实例化时的对象函数。

评分

参与人数 1威望 +5 收起 理由
Hex + 5 精品文章

查看全部评分

本版积分规则