Welcome Guest, Not a member yet? Register   Sign In
Form Validation Rulesets (alternative syntax proposal)
#1
Big Grin 
(This post was last modified: 02-06-2015, 01:28 AM by SPK.)

Hey guys!

I work at a company that hosts multiple CI sites, and they work lovely. But some of these sites are user input heavy (i.e. lots of forms).

Traditionally the way to define multiple validation rulesets has been sub arrays:
http://www.codeigniter.com/userguide3/li...s-of-rules

However this quickly leads to verbose "sets" with repeating fields. Example:

PHP Code:
$config = array(
 
   'signup1' => array(
 
       array(
 
           'field' => 'emailaddress',
 
           'label' => 'EmailAddress',
 
           'rules' => 'required|valid_email'
 
       ),
 
       array(
 
           'field' => 'username',
 
           'label' => 'Username',
 
           'rules' => 'required'
 
       ),
 
       array(
 
           'field' => 'password',
 
           'label' => 'Password',
 
           'rules' => 'required'
 
       ),
 
   ),
 
   'signup2' => array(
 
       array(
 
           'field' => 'title',
 
           'label' => 'Title',
 
           'rules' => 'required'
 
       ),
 
       array(
 
           'field' => 'username',
 
           'label' => 'Username',
 
           'rules' => 'required'
 
       ),
 
       array(
 
           'field' => 'password',
 
           'label' => 'Password',
 
           'rules' => 'required'
 
       ),
 
   )
); 

An alternative to this would be to add a "groups" key to each array, where you can declare what group(s) a field belongs to:

PHP Code:
$config = array(
 
   array(
 
       'field' => 'emailaddress',
 
       'label' => 'EmailAddress',
 
       'rules' => 'required|valid_email',
 
       'groups' => 'signup1'
 
   ),
 
   array(
 
       'field' => 'title',
 
       'label' => 'Title',
 
       'rules' => 'required',
 
       'groups' => 'signup2'
 
   ),
 
   array(
 
       'field' => 'username',
 
       'label' => 'Username',
 
       'rules' => 'required',
 
       'groups' => 'signup1|signup2'
 
   ),
 
   array(
 
       'field' => 'password',
 
       'label' => 'Password',
 
       'rules' => 'required',
 
       'groups' => 'signup1|signup2'
 
   )
); 

To test this idea i've build an extension to the form_validation library (largely a copy of the system run function) :

PHP Code:
class MY_Form_validation extends CI_Form_validation {

 
   protected $CI;

 
   public function __construct($config = array())
 
   {
 
       parent::__construct($config);
 
       $this->CI =& get_instance();
 
   }

 
   public function run_group($group '')
 
   {
 
       // Do we even have any data to process?  Mm?
 
       $validation_array = empty($this->validation_data) ? $_POST $this->validation_data;
 
       if (count($validation_array) === 0)
 
       {
 
           return FALSE;
 
       }

 
       // Does the _field_data array containing the validation rules exist?
 
       // If not, we look to see if they were assigned via a config file
 
       if (count($this->_field_data) === 0)
 
       {
 
           // No validation rules?  We're done...
 
           if (count($this->_config_rules) === 0)
 
           {
 
               return FALSE;
 
           }

 
           // New group array key support. From these values create a new temporary group.
 
           // Then use this new group as validation group. When empty, validate the whole config file.
 
           foreach($this->_config_rules as $config_item)
 
           {
 
               if(isset($config_item['groups']))
 
               {
 
                   $groups explode('|'$config_item['groups']);
 
                   foreach($groups as $value)
 
                   {
 
                       if($value == $group)
 
                       {
 
                           $temp_config_array[] = $config_item;
 
                       }
 
                   }
 
               }
 
           }

 
           $this->set_rules(isset($temp_config_array) ? $temp_config_array $this->_config_rules);

 
           // Were we able to set the rules correctly?
 
           if (count($this->_field_data) === 0)
 
           {
 
               log_message('debug''Unable to find validation rules');
 
               return FALSE;
 
           }
 
       }

 
       // Load the language file containing error messages
 
       $this->CI->lang->load('form_validation');

 
       // Cycle through the rules for each field and match the corresponding $validation_data item
 
       foreach ($this->_field_data as $field => $row)
 
       {
 
           // Fetch the data from the validation_data array item and cache it in the _field_data array.
 
           // Depending on whether the field name is an array or a string will determine where we get it from.
 
           if ($row['is_array'] === TRUE)
 
           {
 
               $this->_field_data[$field]['postdata'] = $this->_reduce_array($validation_array$row['keys']);
 
           }
 
           elseif (isset($validation_array[$field]) && $validation_array[$field] !== '')
 
           {
 
               $this->_field_data[$field]['postdata'] = $validation_array[$field];
 
           }
 
       }

 
       // Execute validation rules
 
       // Note: A second foreach (for now) is required in order to avoid false-positives
 
       // for rules like 'matches', which correlate to other validation fields.
 
       foreach ($this->_field_data as $field => $row)
 
       {
 
           // Don't try to validate if we have no rules set
 
           if (empty($row['rules']))
 
           {
 
               continue;
 
           }

 
           $this->_execute($row$row['rules'], $this->_field_data[$field]['postdata']);
 
       }

 
       // Did we end up with any errors?
 
       $total_errors count($this->_error_array);
 
       if ($total_errors 0)
 
       {
 
           $this->_safe_form_data TRUE;
 
       }

 
       // Now we need to re-set the POST data with the new, processed data
 
       $this->_reset_post_array();

 
       return ($total_errors === 0);
 
   }


The new call would now be:

PHP Code:
$this->form_validation->run_group('signup1'); 

This extension seems to work nicely, but i wonder if any of you can poke some holes in it. I wouldn't want to continue if it ends up being a bad idea. As my colleague said; there is probably a good reason why this isn't the default way Codeigniter handles groups.

Also this might help others who've had / have similar issue's. All thoughts are welcome Big Grin

Regards,
Stephan
Reply
#2

Hey,

I think this is a great idea! I've come up with a slightly different form_validation.php config that removes some of the redundancy as well:

Code:
/*
|--------------------------------------------------------------------------
| First Name Validation
|--------------------------------------------------------------------------
|
| Standard validation for first name input
|
*/
$first_name_validation = array(
    'field'    => 'first_name',
    'label'    => 'First Name',
    'rules'    => 'trim|required|max_length[15]'
);
/*
|--------------------------------------------------------------------------
| Last Name Validation
|--------------------------------------------------------------------------
|
| Standard validation for last name input
|
*/
$last_name_validation = array(
    'field'    => 'last_name',
    'label'    => 'Last Name',
    'rules'    => 'trim|required|max_length[40]'
);

Then in the config array:

[code]/*
|--------------------------------------------------------------------------
| Validation Rule Sets
|--------------------------------------------------------------------------
|
| Sets of rules used throughout website
|
*/
$config = array(
'contact' => array(
$first_name_validation,
$last_name_validation,
),
'register' => array(
$first_name_validation,
$last_name_validation,
),
);

Cheers!
Reply




Theme © iAndrew 2016 - Forum software by © MyBB