Welcome Guest, Not a member yet? Register   Sign In
Arrayed Inputs Validation
#1

(This post was last modified: 01-14-2024, 10:34 AM by grimpirate.)

Running into a strange issue with code validation of name="somename[]" inputs. I'll do my best to explain. I have a form in which inputs are added/removed by the user. I am also adding/removing rules to my validation rule array based on the fields submitted. There are exceptional circumstances that don't allow me to use a universal "somename.*" rule to apply to all the inputs. So if N "somename[]" fields are submitted there will be a rule for somename.0, somename.1, somename.2, ..., somename.(N - 1). What has happened is that when I run the following:
PHP Code:
if(!$this->validate($rules))
 return 
redirect()->back()->withInput();
echo 
'<pre>';
print_r($this->validator->getValidated()); 
The validated data (for 3 inputs) I should be getting back is [somename] = [0 => 'name', 1 => 'name', 2 => 'name'].
However, I am in fact getting back [somename] = [2 => 'name', 3 => 'name', 4 => 'name'].
My $rules array is not written in a contiguous order, meaning that somename.2 rule is defined before somename.0 and somename.1. I believe this is the source of the issue, because when I run:
PHP Code:
ksort($rules);
if(!
$this->validate($rules))
 return 
redirect()->back()->withInput();
echo 
'<pre>';
print_r($this->validator->getValidated()); 
The output of getValidated() is the expected array, and it stands to reason that sorting the $rules array should have no effect on the output. I know there were some issues/bugs with array validation in one of the recent updates. Is this related or something else?

Simplest test harness (in case I sound nuts):
Config/Routes.php
PHP Code:
<?php

use CodeIgniter\Routes\RouteCollection;

/**
 * @var RouteCollection $routes
 */
$routes->get('/foobar''Home::foo');
$routes->post('/foobar''Home::bar'); 
Controllers/Home.php
PHP Code:
<?php

namespace App\Controllers;

class 
Home extends BaseController
{
        public function foo()
        {
                helper('form');
                echo form_open();
                echo form_input('somename[0]');
                echo form_input('somename[1]');
                echo form_input('somename[2]');
                echo form_submit();
                echo form_close();
        }

        public function bar()
        {
                $rules = [
                        'somename.2' => [
                                'rules' => [
                                        'permit_empty',
                                ],
                        ],
                        'somename.0' => [
                                'rules' => [
                                        'permit_empty',
                                ],
                        ],
                        'somename.1' => [
                                'rules' => [
                                        'permit_empty',
                                ],
                        ],
                ];

                // Uncomment ksort to show expected results
                // ksort($rules);

                if(!$this->validate($rules))
                        return redirect()->back()->withInput();

                print_r($this->validator->getValidated());
        }

Reply
#2

I've submitted a pull request for this. Looking into the code of how validated data is retrieved I see that Codeigniter4/system/Validation/DotArrayFilter.php makes use of the array_merge_recursive function. The PHP manual states that 
Quote:If the input arrays have the same string keys, then the values for these keys are merged together into an array, and this is done recursively, so that if one of the values is an array itself, the function will merge it with a corresponding entry in another array too. If, however, the arrays have the same numeric key, the later value will not overwrite the original value, but will be appended.
It seems that since I request '.2' before '.0' and '.1' the values of '.0' and '.1' are appended to the returned merged array, which is why the somename array has keys of 2, 3, and 4. I'm of the opinion this is a bug. If I request an array with strings there won't be a problem. For instance 'somename.first' would return the expected value even if it was preceded by 'somename.last'. However, if I ask for 'somename.1' before 'somename.0' I'll be retrieving a different index in my resultant data. This doesn't seem like a big deal, but if I have position dependent insertions (as is the case with what I'm attempting to do) happening into a database after form submission it can produce an error. The workarounds are either prepend your numerical indices with an arbitrary letter for instance, 'somename.a1' or to sort the $rules beforehand. However, sorting the rules doesn't work if for instance your input fields are 'somename.0', 'somename.1' and 'somename.3', the resultant array will be indexed 0,1,2 rather than 0,1,3. array_merge_recursive doesn't seem to respect numerical indices at all other than starting the resultant merge with whatever the first index is.
Reply




Theme © iAndrew 2016 - Forum software by © MyBB