framework: Can't get failed item with array validation directly

  • Laravel Version: 5.6.39
  • PHP Version: 7.1.7
  • Database Driver & Version: MySQL 5.7.19

Description:

When running an array validator, invalid items in the array can’t be seen without parsing the $validator->failedRules array keys.

Steps To Reproduce:

Use this code in a controller:

$validator = \Illuminate\Support\Facades\Validator::make([
            "records" =>
            [
                "ABC123",
                "ABC122",
                "ABB132",
                "ADCD23"
            ]
        ],[
            "records.*" => [
                "required",
                "regex:/[A-F]{3}[0-9]{3}/"
            ]
        ]);

if I call

dump($validator->invalid());

It outputs:

array:1 [▼
  "records" => array:4 [▼
    0 => "ABC123"
    1 => "ABC122"
    2 => "ABB132"
    3 => "ADCD23"
  ]
]

Which should be (IMO),

array:1 [▼
  "records" => array:4 [▼   
    0 => "ADCD23"  // or indexed as 3
  ]
]

If I call

dump($validator->failed());

It returns

array:1 [▼
  "records.3" => array:1 [▼
    "Regex" => array:1 [▼
      0 => "/[A-F]{3}[0-9]{3}/"
    ]
  ]
]

Which I can tell which item fails the validation, but there should be a shorter way.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 15 (15 by maintainers)

Most upvoted comments

Regarding this problem, it might not be a problem (depending on how we look at it). invalid() method is supposed to return data that is invalid. It just happens to consider as data only first level of keys (attributesThatHaveMessages() will return only first level keys for messages and then intersection with data is done). All nested keys won’t be changed.

Here https://github.com/d3jn/framework/commit/db35f5dfee6c0337352613643b767b060385e81b I’ve extended invalid() test with additional assertion for when wildcard * character is used deeper in the nested rule:

$v = new Validator($trans, ['items' => ['correct', 'invalid', 'also-correct']], ['items.*' => 'in:correct,also-correct']);
$this->assertEquals([
    'items' => [
        1 => 'invalid'
    ]
], $v->invalid());

And here’s the result (as of now for 5.8):

F                                                                   1 / 1 (100%)

Time: 489 ms, Memory: 64.00 MB

There was 1 failure:

1) Illuminate\Tests\Validation\ValidationValidatorTest::testInvalidMethod
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
 Array (
     'items' => Array (
         1 => 'invalid'
+        0 => 'correct'
+        2 => 'also-correct'
     )
 )

On one hand, data’s items key was invalid and is returned (with all it’s elements) as it is. But implementing n-level support for invalid() result would be a right way to go about it IMO (so that only keys that were failed are left no matter their level in the array) and would definitely help.

What do you think? Is it a problem? I can work on a fix for this behavior if that’s the case. I am also referencing @taylorotwell here since #28665 was closed as such that missed any explanation of a problem.

P. S. Also, whoever implemented ValidationValidatorTest::testInvalidMethod in the first place did a poor job, since actual values are passed into PHPUnit assertion as expected (and vice versa). I don’t know if it warrants separate pull request to fix such tests, but it definitely makes diffs in PHPUnit reports very confusing.