Welcome Guest, Not a member yet? Register   Sign In
form validation associative array index fields
#1

[eluser]phazei[/eluser]
I'm trying to use the form validation class for some fields with indexes. It doesn't seem to be working.


If I have a bunch of field names like name='phone[]' it works, but if I have something like:

name='phone[<?=$userid?>]'

It doesn't validate anything. Help?
#2

[eluser]pistolPete[/eluser]
User guide:

Quote:The Form Validation class supports the use of arrays as field names. Consider this example:

Code:
<input type="text" name="options[]" value="" size="50" />
If you do use an array as a field name, you must use the EXACT array name in the Helper Functions that require the field name, and as your Validation Rule field name.

For example, to set a rule for the above field you would use:

Code:
$this->form_validation->set_rules('options[]', 'Options', 'required');

If that does not work for you, post more code (view and controller) and a better error description.
#3

[eluser]phazei[/eluser]
I'm using
Code:
<input type="text" name="options[4]" value="" size="50" />
Code:
$this->form_validation->set_rules('options[]', 'Options', 'required');

The code looks for an ordered index from 0.

The number in options[#] will always be variable for my use.


I looked at Form_validation.php and found on line 548 it checks:
if ( ! isset($this->_field_data[$row['field']]['postdata'][$cycles]))

Cycles is the count for how many items are in the array, so it automatically assumes the array is indexed continuously. I'm not sure if this is a bug, but the documentation does say that it works with indexed arrays.

From the code I'm guessing that means you can set rules for a specific index,
setrule('name[first]'...


Since the foreach online 471 exists, the data in $postdata isn't going to be an array in the first place, so I'm not certain what the point is. Either way I didn't want to remove it because I haven't checked the entirety of the code.

OTOH, I did fix it by adding:

Code:
$i = 0;
foreach($this->_field_data[$row['field']]['postdata'] as $c_key=>$c_val) {
   if($i == $cycles) {
      $cycles_key = $c_key;
      break;
   }
   $i++;
}

Right before line 548.

And changed all indexes that for:
Code:
$this->_field_data[$row['field']]['postdata'][$cycles])
to
Code:
$this->_field_data[$row['field']]['postdata'][$cycles_key])


It basically gets the $cycles number key value.

My foreach loop is a bit sloppy, there are probably better ways of getting the n-th key. I tried array_slice, but it only gets the value, not the key. I could loop next($array), $cycles times, don't know if that would be better or would just mess up the pointer.
#4

[eluser]phazei[/eluser]
On a second look, the only change that needs to be made to make it work with any keys is line 473:

Code:
$this->_execute($row, $rules, $val, $cycles);

to

Code:
$this->_execute($row, $rules, $val, $key);

ching
#5

[eluser]phazei[/eluser]
So I came across another situation in which this was an issue, and found that my solution didn't work on n-dimensional arrays. The $key value only had the current key, not any keys that came before it. So I made some adjustments that made it work with all the keys.

In Form_validation.php:

Line 466:
Code:
function _execute($row, $rules, $postdata = NULL, $cycles = array())

Line 473:
Code:
$new_key = $cycles;
    $new_key[] = $key;
    $this->_execute($row, $rules, $val, $new_key);

So now $cycles actually stores an array of all the keys for however deep in the array it goes.

Before Line 548:
Code:
$_field_data_postdata =& $this->get_array_by_key_array($this->_field_data[$row['field']]['postdata'],$cycles);

Then all instances of this:
Code:
$this->_field_data[$row['field']]['postdata'][$cycles])
Should be replaced with this:
Code:
$_field_data_postdata

Then at the end of the class I made this function:
Code:
/**
     * Returns the reference to a particular key path
     *
     * @access    protected
     * @param    n-dimentional array, array of keys
     * @return    referenced array
     */    

    function &get;_array_by_key_array(&$array, $key_array = array()) {
        $temp_array =& $array;
        foreach ($key_array as $key => $value) {
            if (isset($temp_array[$value])) {
                $temp_array =& $temp_array[$value];
            } else {
                return null;
            }
        }
        return $temp_array;
    }


And to make it work with set_value:
Code:
function set_value($field = '', $default = '')
    {
        if ( strpos($field, '[') !== FALSE ) {
            $original_field = $field;
            $keys = preg_match_all("/\[([^\]]*)\]/",$field,$matches);
            $keys = $matches[1];
            $field = preg_replace('/\[[^\]]*\]/','[]',$field);
            $value = $this->get_array_by_key_array($this->_field_data[$field]['postdata'],$keys);
            if (isset($value)) {
                return $value;
            }
        }
    
        if ( ! isset($this->_field_data[$field]))
        {
            if ($default == '') {
                return $this->CI->input->post($field);
            }
            
            return $default;
        }
        
        return $this->_field_data[$field]['postdata'];
    }

Now with set_value, it expects set_value to be sent an array with the keys, eg 'field[a][c]', with the same number of brackets as the set rules has. It will then extract the keys, put them into an array, check to see if there is a rule set for "field[][]", and if so, will get the value for it.

I'm still working on the errors, right now only one error is stored for a single rule. It would need to store an error for each item in the array. An option in the error message for something like %k1, %k2, etc, would be nice as well. Then many fields could be regulated with with one rule.




Theme © iAndrew 2016 - Forum software by © MyBB