F
F
feycot2019-05-23 12:41:41
symfony
feycot, 2019-05-23 12:41:41

How to use Sypfony Validation 3.4 to check the key for the type of an array + its elements, but not to check the elements if not an array?

Good afternoon, there is a set of assertions for checking incoming parameters (array)

$rules = new Assert\Collection([
        'userdata' => new Assert\Required([new Assert\Collection([
            'fullname'  => new Assert\NotBlank(),
            'email'     => new Assert\Email(),
            'telephone' => new Assert\NotBlank(),
            ])
        ]),
        "items"    => new Assert\Required([
            new Assert\Type('array'),
            new Assert\NotBlank(),
            new Assert\All([
                new Assert\Type('array'),
                new Assert\Collection([
                    "id"        => new Assert\NotBlank(),
                    "quantity"  => new Assert\NotBlank(),
                    ])
                ])
            ]),
    ]);

How to check the items key for an array type, and if it is an array, then also its elements?
If items is not an array, then throw an error and do not check further child elements, if an array, then check the attributes of child elements
At the moment, if I pass an integer in the items key, then the error is "Expected argument of type \"array or Traversable and ArrayAccess\", \"string\" given"

Answer the question

In order to leave comments, you need to log in

1 answer(s)
B
BoShurik, 2019-05-23
@feycot

Apparently this is a "bug" in version 3.4: https://github.com/symfony/symfony/issues/26463
Here is a PR that solves the problem, but it is frozen in 4.2: https://github.com/symfony/symfony/ pull/27917
As a solution:

$rules = new Assert\Collection([
    "items"    => new Assert\Required([
        new Assert\NotBlank(),
        new Assert\Callback(function ($value, ExecutionContextInterface $context) {
            $validator = $context->getValidator();

            $violations = $validator->validate($value, new Assert\Type('array'));

            if ($violations->count() > 0) {
                /** @var ConstraintViolationInterface $violation */
                foreach ($violations as $violation) {
                    $context
                        ->buildViolation($violation->getMessage(), $violation->getParameters())
                        ->atPath('items')
                        ->addViolation()
                    ;
                }

                return;
            }

            $violations = $validator->validate($value, new Assert\All([
                new Assert\Type('array'),
                new Assert\Collection([
                    "id"        => new Assert\NotBlank(),
                    "quantity"  => new Assert\NotBlank(),
                ])
            ]));

            /** @var ConstraintViolationInterface $violation */
            foreach ($violations as $violation) {
                $context
                    ->buildViolation($violation->getMessage(), $violation->getParameters())
                    ->atPath('items'. $violation->getPropertyPath())
                    ->addViolation()
                ;
            }
        }),
    ]),
]);

$validator = Validation::createValidator();

$data = [
    'items' => [
        [
            'id' => 'id',
            'quantity' => 'quantity',
        ],
    ],
];

dump($validator->validate($data, $rules)); // Ok

$data = [
    'items' => 1,
];

dump($validator->validate($data, $rules)); // Ko

$data = [
    'items' => [
        [
            'id' => 'id',
            'quantity' => 'quantity',
        ],
        [
            'id2' => 'id',
            'quantity2' => 'quantity',
        ]
    ],
];

dump($validator->validate($data, $rules)); // Ko

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question