【问题标题】:CodeIgniter - validate empty valueCodeIgniter - 验证空值
【发布时间】:2014-07-18 16:22:16
【问题描述】:

如何让 CodeIgniter 对具有required 规则但用户留空的字段运行自定义规则?

如果字符串为空,我能想到的最好方法是在字段中添加一个空格,然后添加一个trim 规则——但这感觉很hacky。

示例规则 #1

仅当另一个字段具有特定值时才需要该字段:

// depends[another_field.some_val]
public function depends($str, $field){
    list($post_key, $post_val)=explode('.', $field);
    if($_POST[$post_key] == $post_val){
        return $str != "";
    }
    return true;
}

示例规则 #2

仅当数据库中存在正则表达式时才需要该字段:

// regex[table_name.col_name.some_val]
public function regex($str, $field){
  list($table, $col, $post_val)=explode('.', $field);
  // Grab the regex
  $regex = $this->CI  ->db
                      ->limit(1)
                      ->select($col)
                      ->where($post_val, $_POST[$post_val])
                      ->get($table)
                      ->row($col);

  return preg_match('/'.$regex.'/', $str) === 1;
}

【问题讨论】:

    标签: php codeigniter


    【解决方案1】:

    为什么一个简单的任务需要不同的功能。使用 if..else

    假设如果 input1 的值等于 value1,那么您只需设置 required 验证规则另一个输入是 input2

    查看:

    <form action="/controller_name/function_name/" method="POST">
    
        <input type="text" name="input1" />
        <input type="text" name="input2" />
    
        <input type="submit" />
    </form>
    


    控制器:

    class Controller_name extends CI_Controller
    {
        public function __construct()
        {
           parent::__construct();
           $this->load->library('form_validation');
        }
    
        public function function_name()
        {
            if($this->input->is_post())
            {
                if($this->input->post('input1') == 'value1')
                {
                   $this->form_validation->set_rules('input2', 'input2', 'required');
                }
    
                if ($this->form_validation->run() == FALSE)
                {
                     // something's wrong in form!
                }
                else
                {
                     // form is good, proceed!
                }
            }
        }
    }
    

    【讨论】:

    • 这是一个例子,这并不能回答我的问题。
    • 我就是这么说的。我以不同的方式(更好的方式)回答了你的例子。你投了反对票,那很好。但是我想告诉你,你的方法是错误的。
    【解决方案2】:

    从代码中,您指出的问题是您需要设置一个必填字段。好吧,用新规则创建一种 required 字段:'keep_checking'。这样,您可以强制系统检查您想要的任何内容。我做了什么:

    • 扩展系统核心类的 My_Form_validation 类(因此,您不必接触系统文件)。注意:不要忘记此文件位于 application/libraries 文件夹中
    • 检查是否设置了自定义规则“keep_checking”。这将覆盖设置“必需”规则时不检查字段的行为(参见下面的代码)

    最后一点,在扩展 Form_validation 类之后,您将有一个地方放置您将一直使用的所有新自定义规则,XD

    class MY_Form_validation extends CI_Form_validation
    {
        public function __construct( $rules = array( ) ) {
            parent::__construct( $rules );
        }
    
        protected function _execute($row, $rules, $postdata = NULL, $cycles = 0)
        {
            // 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);
                    $cycles++;
                }
    
                return;
            }
    
            // --------------------------------------------------------------------
    
            // If the field is blank, but NOT required, no further tests are necessary
            $callback = FALSE;
    
            //====================================================================
            // NEW ADDED RULE > 'keep_checking', will check all the rules even if 
            // the field is empty
            //====================================================================
            if ( ! in_array('required', $rules) AND is_null($postdata) AND ! in_array( 'keep_checking', $rules ) )
            {
                // Before we bail out, does the rule contain a callback?
                if (preg_match("/(callback_\w+(\[.*?\])?)/", implode(' ', $rules), $match))
                {
                    $callback = TRUE;
                    $rules = (array('1' => $match[1]));
                }
                else
                {
                    return;
                }
            }
            // --------------------------------------------------------------------
    
            // Isset Test. Typically this rule will only apply to checkboxes.
            //====================================================================
            // NEW ADDED RULE > 'keep_checking', will check all the rules even if 
            // the field is empty
            //====================================================================
        if (is_null($postdata) AND $callback == FALSE && !in_array( 'keep_checking', $rules ))
            {
                if (in_array('isset', $rules, TRUE) OR in_array('required', $rules))
                {
                    // Set the message type
                    $type = (in_array('required', $rules)) ? 'required' : 'isset';
    
                    if ( ! isset($this->_error_messages[$type]))
                    {
                        if (FALSE === ($line = $this->CI->lang->line($type)))
                        {
                            $line = 'The field was not set';
                        }
                    }
                    else
                    {
                        $line = $this->_error_messages[$type];
                    }
    
                    // Build the error message
                    $message = sprintf($line, $this->_translate_fieldname($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)
                {
                    if ( ! method_exists($this->CI, $rule))
                    {
                        continue;
                    }
    
                    // Run the function and grab the result
                    $result = $this->CI->$rule($postdata, $param);
    
                    // 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)
                    {
                        continue;
                    }
                }
                else
                {
                    if ( ! method_exists($this, $rule))
                    {
                        // 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;
                            }
                        }
                        else
                        {
                            log_message('debug', "Unable to find validation rule: ".$rule);
                        }
    
                        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 = $this->CI->lang->line($rule)))
                        {
                            $line = 'Unable to access an error message corresponding to your field name.';
                        }
                    }
                    else
                    {
                        $line = $this->_error_messages[$rule];
                    }
    
                    // Is the parameter we are inserting into the error message the name
                    // of another field?  If so we need to grab its "field label"
                    if (isset($this->_field_data[$param]) AND isset($this->_field_data[$param]['label']))
                    {
                        $param = $this->_translate_fieldname($this->_field_data[$param]['label']);
                    }
    
                    // Build the error message
                    $message = sprintf($line, $this->_translate_fieldname($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;
                }
            }
        }
    }
    

    更新:

    复选框行正在避免继续检查。只需添加我添加的新行,它就会起作用。您必须将 keep_checking 规则添加到您要检查的任何字段:

    class Welcome extends CI_Controller {
    
        /**
         * Index Page for this controller.
         *
         * Maps to the following URL
         *      http://example.com/index.php/welcome
         *  - or -
         *      http://example.com/index.php/welcome/index
         *  - or -
         * Since this controller is set as the default controller in
         * config/routes.php, it's displayed at http://example.com/
         *
         * So any other public methods not prefixed with an underscore will
         * map to /index.php/welcome/<method_name>
         * @see http://codeigniter.com/user_guide/general/urls.html
         */
        public function index()
        {
            $this->load->view('welcome_message');
        }
    
        public function test()
        {
            $this->load->library('form_validation');
    
            $this->form_validation->set_rules('name',       'Name',     'keep_checking|required');
            $this->form_validation->set_rules('surname',    'Surname',  'keep_checking|is_numeric');
    
            if ( $this->form_validation->run() ) {
    
            } else {
                $this->load->view('form');
            }
        }
    }
    

    查看:form.php

    <form action="test" method="post">
    
        <?php echo validation_errors(); ?>
    
        <p>
            Name: <input name="name">
        </p>
        <p>
            Surname: <input name="surname">
        </p>
        <p>
            <input type="submit" value="Send">
        </p>
    </form>
    

    提交该表单后,您会看到 CI 检查输入字段中的所有规则。最后一点,不要忘记 MY_Form_validation 位于库文件夹中

    【讨论】:

    • 你测试过这个吗?我已将您的代码复制到MY_Form_validation.php,在最后一个} 之前添加了我的自定义规则,并添加了您的keep_checking 规则;它似乎没有改变任何东西。
    • 你是对的,没有按预期说话。我更正了它并添加了一个简单的测试以允许您检查它。现在,每个具有 keep_checking 的规则都会检查所有规则,即使该字段为空,XD。请注意,如果规则要求有值,这可能会导致一些错误,因此,请检查您的回调!
    【解决方案3】:

    在我的更新方法中,我只想提交脏的字段。如果一个不需要验证的字段被发送为空,则并非所有字段都是必需的,并且验证失败。

    因此,如果用户想移除他们的手机,它会像 phone:"" 一样发送,如果我尝试这样传递它,验证将不会看到它。

    if($this-put("phone")) $this->form_validation->set_rules('phone', 'Phone', 'trim');
    

    所以我不得不使用 array_key_exist() 让它看到它并传递它,即使它是空的。

    if($this->put("description")) $this->form_validation->set_rules('description', 'Description', 'trim|required');
    
    if(array_key_exists("phone", $this->input->post())) $this->form_validation->set_rules('phone', 'Phone', 'trim');
    

    【讨论】:

      【解决方案4】:

      我想你要找的是callbacks

      您可以在规则中定义回调

      $this->form_validation->set_rules('field1', 'Field 1', 'trim|callback_field1_check');
      $this->form_validation->set_rules('field2', 'Field 2', 'callback_field2_check');
      

      现在你可以拥有一个返回布尔值的函数了。

      public function field1_check($input) {
          if ($input != '') {
              $this->field1Set = true;
          }
      }
      
      public function field2_check($input) {
          // do something on $input
          $input = trim($input);
          // awesome thing is, you get to access all the field variables of your control here
          // so in some other function, you'll toggle a boolean to note that an optional field was filled
          // that variable set by other validation callback, you can use here
          if ($this->field1Set === true && $input == '') return false;
          return true;
      }
      

      【讨论】:

      • 我需要将它添加到每个需要它的控制器,对吧?不像把它放在 MY_Form_validation.php 和所有其他规则一样整洁。
      • 我回答了我自己的问题,但如果你能想到更好的解决方案,赏金仍然有效。
      【解决方案5】:

      我自己想出了一个方法来编辑system/libraries/Form_validation.php

      我在第 487 行将 $callback 更改为 TRUE

      $callback = TRUE;
      

      并注释掉第 488 - 500 行:

          if ( ! in_array('required', $rules) AND is_null($postdata))
          {
              // Before we bail out, does the rule contain a callback?
              if (preg_match("/(callback_\w+(\[.*?\])?)/", implode(' ', $rules), $match))
              {
                  $callback = TRUE;
                  $rules = (array('1' => $match[1]));
              }
              else
              {
                  return;
              }
          }
      

      如果有人能够在不编辑 CodeIgniter 的 system 文件的情况下想出解决方案,那么悬赏仍然有效。

      【讨论】:

        【解决方案6】:
        function add($id = '') {
        
            $this->form_validation->set_rules('title', 'Title', 'trim|required');
            $this->form_validation->set_rules('title_description', 'title_description', 'trim|required');
            $this->form_validation->set_rules('color', 'color', 'trim|required');
            $this->form_validation->set_rules('button', 'button', 'trim|required');
            //$this->form_validation->set_rules('description', 'Description', 'trim|required');
            if ($this->form_validation->run() == FALSE) {
                echo "Not Valid";
            } else {
                echo "Valid";
            }
        }
        

        【讨论】:

          【解决方案7】:

          您可以在视图中添加具有永久值的隐藏输入,并在验证规则中对其进行测试。

          在视图中:

          <input type="hidden" name="id_form" value="1"/>
          

          在模型或控制器中(取决于您的架构)

           public function validates_rules(){
                  $this->form_validation->set_rules('id_form', 'Title', 'callback_values_check');
              ...
                  }
          
          
             public function values_check($id_form){
                 if($this->input->post('other_value_to_test')){
          ...
                 }
              }
          

          【讨论】:

            猜你喜欢
            • 2016-04-18
            • 1970-01-01
            • 2021-07-10
            • 1970-01-01
            • 2012-05-21
            • 2010-12-31
            • 2016-03-20
            • 1970-01-01
            • 2011-01-01
            相关资源
            最近更新 更多