Validation icon indicating copy to clipboard operation
Validation copied to clipboard

Each overwriting messages

Open tchari opened this issue 4 years ago • 2 comments

When you validate the elements of an array (or iterable) using each, the messages get "overwritten" when you get the exception message.

    try {
      Validator::notEmpty()->iterableType()->each(
        Validator::key('street', Validator::stringType()->notEmpty())
        ->key('region', Validator::stringType()->notEmpty())
        ->key('country', Validator::stringType()->notEmpty())
        ->key('other', Validator::nullable(Validator::notEmpty()->stringType()), false)
      )->assert(
        [
          ['region' => 'Oregon', 'country' => 'USA', 'other' => 123],
          ['street' => '', 'region' => 'Oregon', 'country' => 'USA'],
          ['street' => 123, 'region' => 'Oregon', 'country' => 'USA'],
        ]
      );
    } catch (NestedValidationException $e) {
      var_dump($e->getMessages());
    }

The above var_dump results in

array(1) {
  ["each"]=>
  string(29) "street must be of type string"
}

However, I would have expected

array(1) {
  ["each"]=>
  array(3) {
    [0]=>
    array(2) {
      ['street']=>
      string(22) "street must be present"
      ['other'] =>
      string(28) "other must be of type string"
    }
    [1]=>
    array(1) {
      ['street']=>
      string(24) "street must not be empty"
    }
    [2]=>
    array(1) {
      ['street']=>
      string(29) "street must be of type string"
    }
  }
}

It is a little alarming that no exception is present for the first erroneous 'other' field. Is there a different rule for this?

tchari avatar Feb 05 '21 02:02 tchari

Unfortunatelly, this and other composite messages are completely broken in 2.x, and there isn't much we can do without further changing the core NestedValidationException.

However, for each specifically, this is a deal braker since it makes it unusable, so I made a hotfix and it should be available on 2.3.

Check out this test to see how the behavior changed.

For 3.0, most messages for composite validators should be reporting using a . notation or some other tree expression equivalent. I haven't settled on it yet, but every message should be available somewhere. It might be a getAllMessages or something, but it will be there.

alganet avatar Feb 19 '23 18:02 alganet

Is this still an issue? I'm upgrading a site here, and I'm trying the following code:

        $v = new V();
        $v->addRule(V::key('id', V::scalarVal()));
        $v->addRule(V::key('fileReference', V::length(4, 35), false));
        $v->addRule(V::key('scenario', V::length(3, 16), false));
        $v->addRule(V::key('totalGrossMass', V::numericVal(), false));
        $v->addRule(V::key('bolNumber', V::length(1, 35)->scalarVal(), false));
        $v->addRule(V::key('arrivedDate', V::dateTime('Y-m-d H:i:s'), false));
        $v->addRule(V::key('packages', V::intVal(), false));
        $v->addRule(V::key('status', V::in(Status::toArray()), false));

        try {
            $v->assert($payload);
        } catch (NestedValidationException $e) {
            $messages = $e->getMessages();
        }

This gives me the following:

[
    "validator" => 'fileReference must have a length between 4 and 35'
]

I would have expected the key to say fileReference and not validator? Is this related or am I using it wrong?

delboy1978uk avatar Jun 26 '23 10:06 delboy1978uk