From 4b90a3746e929f6bbf2b83c71948665c0c31d1fe Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Mon, 10 Mar 2014 10:24:24 +0200 Subject: Add support for callable form validation rules --- system/libraries/Form_validation.php | 101 +++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 34 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php index 0c4f94914..0a80888d2 100644 --- a/system/libraries/Form_validation.php +++ b/system/libraries/Form_validation.php @@ -144,7 +144,7 @@ class CI_Form_validation { * Set Rules * * This function takes an array of field names and validation - * rules as input, any custom error messages, validates the info, + * rules as input, any custom error messages, validates the info, * and stores it * * @param mixed $field @@ -153,7 +153,7 @@ class CI_Form_validation { * @param array $errors * @return CI_Form_validation */ - public function set_rules($field, $label = '', $rules = '', $errors = array()) + public function set_rules($field, $label = '', $rules = array(), $errors = array()) { // No reason to set rules if we have no POST data // or a validation array has not been specified @@ -187,26 +187,32 @@ class CI_Form_validation { return $this; } - // Convert an array of rules to a string - if (is_array($rules)) - { - $rules = implode('|', $rules); - } - // No fields? Nothing to do... - if ( ! is_string($field) OR ! is_string($rules) OR $field === '') + if ( ! is_string($field) OR $field === '') { return $this; } + elseif ( ! is_array($rules)) + { + // BC: Convert pipe-separated rules string to an array + if (is_string($rules)) + { + $rules = explode('|', $rules); + } + else + { + return $this; + } + } // If the field label wasn't passed we use the field name $label = ($label === '') ? $field : $label; // Is the field name an array? If it is an array, we break it apart // into its components so that we can fetch the corresponding POST data later - $indexes = array(); - if (preg_match_all('/\[(.*?)\]/', $field, $matches)) + if (($is_array = (bool) preg_match_all('/\[(.*?)\]/', $field, $matches)) === TRUE) { + $indexes = array(); sscanf($field, '%[^[][', $indexes[0]); for ($i = 0, $c = count($matches[0]); $i < $c; $i++) @@ -219,10 +225,6 @@ class CI_Form_validation { $is_array = TRUE; } - else - { - $is_array = FALSE; - } // Build our master array $this->_field_data[$field] = array( @@ -468,7 +470,7 @@ class CI_Form_validation { continue; } - $this->_execute($row, explode('|', $row['rules']), $this->_field_data[$field]['postdata']); + $this->_execute($row, $row['rules'], $this->_field_data[$field]['postdata']); } // Did we end up with any errors? @@ -591,19 +593,33 @@ class CI_Form_validation { if ( ! in_array('required', $rules) && ($postdata === NULL OR $postdata === '')) { // Before we bail out, does the rule contain a callback? - if (preg_match('/(callback_\w+(\[.*?\])?)/', implode(' ', $rules), $match)) + foreach ($rules as &$rule) { - $callback = TRUE; - $rules = array(1 => $match[1]); + if (is_string($rule)) + { + if (strncmp($rule, 'callback_', 9) === 0) + { + $callback = TRUE; + $rules = array(1 => $rule); + break; + } + } + elseif (is_callable($rule)) + { + $callback = TRUE; + $rules = array(1 => $rule); + break; + } } - else + + if ( ! $callback) { return; } } // Isset Test. Typically this rule will only apply to checkboxes. - if (($postdata === NULL OR $postdata === '') && $callback === FALSE) + if (($postdata === NULL OR $postdata === '') && ! $callback) { if (in_array('isset', $rules, TRUE) OR in_array('required', $rules)) { @@ -668,39 +684,55 @@ class CI_Form_validation { // somebody messing with the form on the client side, so we'll just consider // it an empty field $postdata = is_array($this->_field_data[$row['field']]['postdata']) - ? NULL - : $this->_field_data[$row['field']]['postdata']; + ? NULL + : $this->_field_data[$row['field']]['postdata']; } // Is the rule a callback? - $callback = FALSE; - if (strpos($rule, 'callback_') === 0) + $callback = $callable = FALSE; + if (is_string($rule)) { - $rule = substr($rule, 9); - $callback = TRUE; + if (strpos($rule, 'callback_') === 0) + { + $rule = substr($rule, 9); + $callback = TRUE; + } + } + elseif (is_callable($rule)) + { + $callable = TRUE; } // Strip the parameter (if exists) from the rule // Rules can contain a parameter: max_length[5] $param = FALSE; - if (preg_match('/(.*?)\[(.*)\]/', $rule, $match)) + if ( ! $callable && preg_match('/(.*?)\[(.*)\]/', $rule, $match)) { $rule = $match[1]; $param = $match[2]; } // Call the function that corresponds to the rule - if ($callback === TRUE) + if ($callback OR $callable) { - if ( ! method_exists($this->CI, $rule)) + if ($callback) { - log_message('debug', 'Unable to find callback validation rule: '.$rule); - $result = FALSE; + if ( ! method_exists($this->CI, $rule)) + { + log_message('debug', 'Unable to find callback validation rule: '.$rule); + $result = FALSE; + } + else + { + // Run the function and grab the result + $result = $this->CI->$rule($postdata, $param); + } } else { - // Run the function and grab the result - $result = $this->CI->$rule($postdata, $param); + $result = is_array($rule) + ? $rule[0]->{$rule[1]}($postdata, $param) + : $rule($postdata, $param); } // Re-assign the result to the master data array @@ -725,6 +757,7 @@ class CI_Form_validation { // Users can use any native PHP function call that has one param. if (function_exists($rule)) { + // Native PHP functions issue warnings if you pass them more parameters than they use $result = ($param !== FALSE) ? $rule($postdata, $param) : $rule($postdata); if ($_in_array === TRUE) -- cgit v1.2.3-24-g4f1b