How to get nested error messages with Symfony Validator?

1.1k views Asked by At

I am trying to validate raw values like described in the Symfony docs. https://symfony.com/doc/current/validation/raw_values.html

When I provide the name key in the input - I see nested errors. But when I do not provide it - validation stops on the parent field. In other words, I want to run nested validation always, even if the parent field is missed.

Expected response when parent key is missed:

array(2) {
  [0]=>
  array(2) {
    ["path"]=>
    string(18) "[name][first_name]"
    ["message"]=>
    string(22) "This field is missing."
  }
  [1]=>
  array(2) {
    ["path"]=>
    string(17) "[name][last_name]"
    ["message"]=>
    string(22) "This field is missing."
  }
}

Real response (when parent key is missed):

array(1) {
  [0]=>
  array(2) {
    ["path"]=>
    string(6) "[name]"
    ["message"]=>
    string(22) "This field is missing."
  }
}

Uncomment the name field in the $input to reproduce the behavior.

Code:

<?php

require_once '../vendor/autoload.php';

use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Validation;

$validator = Validation::createValidator();

$input = [
    //'name' => [],
];

$constraint = new Assert\Collection(
    [
        'name' => new Assert\Collection(
            [
                'first_name' => new Assert\Required(),
                'last_name' => new Assert\Required(),
            ],
        ),
    ]
);

$items = [];

$violations = $validator->validate($input, $constraint);
foreach ($violations as $violation) {
    $items[] = [
        'path' => $violation->getPropertyPath(),
        'message' => $violation->getMessage(),
    ];
}

var_dump($items);
1

There are 1 answers

2
Arleigh Hix On

I think you may need to check for the parent key then use an appropriately different Assert\Collection object for the structure of the input.

<?php

require_once '../vendor/autoload.php';

use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Validation;

$validator = Validation::createValidator();

$input = [
    //'name' => [],
];

$notNestedConstraint = new Assert\Collection(
    [
        'first_name' => new Assert\Required(),
        'last_name' => new Assert\Required(),
    ],
);
$nestedConstraint = new Assert\Collection(
    [
        'name' => $notNestedConstraint,
    ]
);

$items = [];
$constraint = (array_key_exists('name', $input)) ? $nestedConstraint: $notNestedConstraint

$violations = $validator->validate($input, $constraint);
foreach ($violations as $violation) {
    $items[] = [
        'path' => $violation->getPropertyPath(),
        'message' => $violation->getMessage(),
    ];
}

var_dump($items);