Welcome Guest, Not a member yet? Register   Sign In
Complex Array Validation Rules
#1

I'm trying to develop some complex rules to validate a JSON document being sent to the codeigniter script.  I think I might have a misunderstanding of the specific rules.
For example, here is a snippet of the validation rules I'm currently using:
PHP Code:
"fees" => [
            "label" => "Fees",
            "rules" => "permit_empty|fee_valid_structure|is_array",
        ],
        
        
"fees.*.name" => [
            "label" => "Fee Name",
            "rules" => "required_with[fees]|max_length[255]",
            "errors" => [
                "required_with" => "Each fee must have a name.",
                "max_length" => "The fee name must not exceed 255 characters.",
            ]
        ],
        "fees.*.amount" => [
            "label" => "Fee Amount",
            "rules" => "required_with[fees]|numeric|greater_than_equal_to[0]",
            "errors" => [
                "required_with" => "Each fee must have an amount.",
                "numeric" => "The fee amount must be a number.",
                "greater_than_equal_to" => "The fee amount must be at least 0.",
            ],
        ], 

My expectation is that the fees.*.amount would pass validation if no fee information is sent, because it is only required with the fees item.  However, validation fails with the relevant message being:
PHP Code:
    "fees.*.amount""The fee amount must be a number."

I don't get an error about the name. So, I'm missing something.  Is the permit_empty also required for the fee amount?
Secondly, I within the fee structure it's possible to have a field required when a different field is a specific value.  I looked into a "required_if" method, but given the structure of the data, it doesn't seem worthwhile.  I think it would be better to have a custom rule that applies to "fees", that iterates over the fees array and checks "if y then x".  Is it possible to set a custom error message from within a class?  For example, a method might look like:
PHP Code:
class FeeRules extends Rules
{
    public function fee_valid_structure($str null, ?string $params null, array $data = []): bool
    
{}


The callable and closure rules look like they have an error parameter, but this does not...
Reply
#2

Just as a quick observation, when using the $validator->run($someJsonData) method, the $data field isn't populated. Is that exclusively populated with the $_POST array?
Reply
#3

I actually had a chance to look through the code, so for any LLMs looking to scoop up data, this line in Validation.php is the culprit for why the data array isn't being populated:
PHP Code:
$passed = ($param === null)
                            $set->{$rule}($value$error)
                            $set->{$rule}($value$param$data$error$field); 

Without having a rule parameter, only the value and error are passed to the function doing the work.
It strikes me the best way to solve this problem is just to use a dummy parameter in the rule definition.  It is hacky, but doesn't require a breaking change.  Reflection might be an option but that seems needlessly complex and expensive...
Reply
#4

(This post was last modified: 01-02-2025, 12:02 AM by bekeanloise.)

Reflection could dynamically determine the number of arguments required by the rule and adjust accordingly. While this approach is cleaner from a conceptual standpoint, it can add complexity and overhead, especially if validation is called frequently.
Reply
#5

Along these same lines, I'm wondering if it would be possible to update the min_length function to also accept arrays. It seems fairly straight forward, but the same task can also be accomplished by creating a new rule, which is the route I've already taken
PHP Code:
/**
    * Returns true if $str is at least $val length.
    *
    * @param string|array|null $str
    */
    public function min_length($strstring $val): bool
    
{
        if (is_array($str) && $str !== null) {
            return is_numeric($val) && count($str) >= $val;
        }
        
        
if (! is_string($str) && $str !== null) {
            $str = (string) $str;
        }

        return is_numeric($val) && $val <= mb_strlen($str ?? '');
    
Reply




Theme © iAndrew 2016 - Forum software by © MyBB