Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wrong :value in validation rules 'gt', 'gte', 'lt', 'lte' for type numeric #52036

Closed
azgooon opened this issue Jul 5, 2024 · 6 comments
Closed

Comments

@azgooon
Copy link

azgooon commented Jul 5, 2024

Laravel Version

10.48.15

PHP Version

8.3.4

Database Driver & Version

No response

Description

I came across what I think is the bug and would appreciate it if someone could have a second opinion.

In the "steps to reproduce" I have included a snippet which when executed I would have expected to return 2 errors both referencing the currency field, stating that the currency field must be an array (this is just to demonstration purposes). Instead, there are 4 errors 2 about the array and 2 about the amount field informing that the amount field should be greater than 2.

am I missing something or is it not desirable behavior?

Thanks,
Tom.

Steps To Reproduce

    $data = [
        [
            'amount' => 10,
            'currency' => 'GBP',
        ],
        [
            'amount' => 20,
            'currency' => 'GBP',
        ],
    ];

    $rules = [
        '*.amount' => [
            'required',
            'numeric',
            'gt:0',
        ],
        '*.currency' => [
            'array',
        ],
    ];

    $validator = Validator::make($data, $rules);

    dd($validator->getMessageBag()->toArray());
@prateekgoyal261
Copy link

After further testing your issue, it appears that gt:0 is not treating 0 as a value but as a key of the array. For instance, if you add three items in the first row and two items in the second row, gt:0 will return items greater than 3, and gt:1 will return items greater than 2.

Similarly, if you add more array items, gt:3 will behave the same if the array has more than three rows.

Here is an example of the data:

$data = [
[
'amount' => 10,
'currency' => 'GBP',
'country' => 'UK',
],
[
'amount' => 20,
'currency' => 'GBP',
],
];

@azgooon
Copy link
Author

azgooon commented Jul 6, 2024

Is it how it should work? I am not at the laptop right now but if I remember correctly, if we replace gt:0 with gt:10 then an actual number is used so I still think that the behaviour is inconsistent, no?

@Lakshan-Madushanka
Copy link

@prateekgoyal261 No it doesn't treat is as a key it should behave accordingly size rule. Though this is interesting. The first picture that came to my mind was similar to @azgooon's, but I knew that the gt, gte, etc. rules behave according to the size rule. The size rule varies depending on the type. For an array, size corresponds to the count of the array. That rule has been applied to your amount field, treating it as an array type but in your case it should be treated as integer which is quite odd.

Make sure you pass the amount as integer perhaps you may have passed it as an array.

@azgooon
Copy link
Author

azgooon commented Jul 6, 2024

@Lakshan-Madushanka as per example, the amount is definitely passed as int.

@driesvints
Copy link
Member

driesvints commented Jul 8, 2024

So this is quite the gotcha but @prateekgoyal261 is correct. It's because you're using the wildcard as the root of the array causing the value of gt to reference the array key instead of representing a size. The gt, gte, size, etc rules first check for a field/key presence in the root array which will match the 0 or 1 keys of the given array with two data entries. Then it'll check for a size. The solution to this problem is to always use a root key instead of using * as the root of the array:

$data = [
    "values" => [
        [
            "amount" => 10,
            "currency" => "GBP"
        ],
        [
            "amount" => 20,
            "currency" => "GBP"
        ]
    ]
];

$rules = [
    "values.*.amount" => ["required", "numeric", "gt:0"],
    "values.*.currency" => ["array"]
];

$validator = Validator::make($data, $rules);

dd($validator->getMessageBag()->toArray());

@azgooon
Copy link
Author

azgooon commented Jul 8, 2024

Thanks @driesvints, that makes sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants