How do I get CodeIgniter to run custom rules on fields which don't have the required rule but the user left empty?
The best I can come up with is to add a space to the field if the string is empty, and then add a trim rule -- but this feels hacky.
Field is required only if another field has a certain value:
// 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;
}
Field is required only if a regex exists on the database:
// 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;
}
Why is there a need of a different function for a simple task. Use if..else.
Assuming that if input1 has value equals value1, then only you have to set the required validation rule for the other input which is say input2.
View:
<form action="/controller_name/function_name/" method="POST">
<input type="text" name="input1" />
<input type="text" name="input2" />
<input type="submit" />
</form>
Controller:
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!
}
}
}
}
From the code, the problem you point out is that you NEED make a field required. Well, make a kind of required field with a new rule: 'keep_checking'. This way, you force the system to check whatever you want. What I did:
application/libraries folderLast point, after extending the Form_validation class you'll have a place to put all your new custom rules you'll be using all the time, 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;
}
}
}
}
UPDATE:
Checkbox line was avoiding keep checking. Just add the new line I added, and it'll work. You have to add the keep_checking rule to any field you want to check:
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');
}
}
}
View: 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>
After submit that form, you'll see as CI check all rules from the input fields. Last point, don't forget that MY_Form_validation goes inside of libraries folder

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With