@HellWalk

Component\Validator — Как сделать проверку на «Отсутствует или массив»?

В доменной модели (т.е. не фреймворк и фреймворк там не нужен) используется компонент Symfony\Component\Validator

Пример нативного использования

Нужно сделать проверку вида:
if (array_key_exists('address', $data) && !is_array($data['address'])) {
    // throw new
}


Т.е. ключ 'address' в массиве может отсутствовать, а если он есть - он должен содержать массив

Казалось бы, нужно сделать проверку таким образом:

$constraint = new Assert\Collection([
            'address' => [
                new Assert\Blank(),
                new Assert\Type('array'),
            ],
    ]);


Но, не работает - если ключ отсутствует, пишет "This field is missing"

Перепробовал массу других вариантов, перечитал кажется уже всю документацию но так и не пойму, как сделать нужную проверку.
  • Вопрос задан
  • 181 просмотр
Решения вопроса 1
BoShurik
@BoShurik Куратор тега Symfony
Symfony developer
Вам нужна опция allowMissingFields

$validator = (new ValidatorBuilder())->getValidator();
$constraints = [
    new Assert\Collection([
        'fields' => [
            'address' => [
                new Assert\NotNull(),
                new Assert\Type('array'),
            ],
        ],
        'allowMissingFields' => true,
        'allowExtraFields' => true,
    ]),
    new Assert\Collection([
        'fields' => [
            'required' => [
                new Assert\NotNull(),
            ],
        ],
        'allowExtraFields' => true,
    ]),
];

$data = [];
dump($data);
dump($validator->validate($data, $constraints)); // Ko

$data = [
    'address' => null,
];
dump($data);
dump($validator->validate($data, $constraints)); // Ko

$data = [
    'address' => [],
];
dump($data);
dump($validator->validate($data, $constraints)); // Ko

$data = [
    'address' => 'address',
];
dump($data);
dump($validator->validate($data, $constraints)); // Ko

$data = [
    'address' => [],
    'required' => 'value',
];
dump($data);
dump($validator->validate($data, $constraints)); // Ok
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Maksclub
@Maksclub
maksfedorov.ru
new Assert\Collection([
'address' => ...

У данного ассерта нет поля 'address', есть например fields...

Можете сделать через Expression
new Assert\Expression([
    'expression' => 'this.isValidAddress()',
    'message'    => 'Адрес или пустой или массив',
])

Тогда нужно будет добавить в класс, где поле address метод
public function isValidAddress(): bool
{
      return $this->address === null || \is_array($this->address);
}


UPD: Если доменную модель нужно валидировать, значит она может пребывать в невалидных состояних, что говорит о плохом дизайне (что само в свою очередь допустимо, если не раскидываться словами "доменная" и "модель").
Такое бывает, когда объекты значатся объектами номинально и представляют из себя анемичные (без поведения и инкапсуляции) объекты, а обычные структуры (пусть и типизированные и называющиеся со слова class). Это способ процедурного программирования через ООП-синтаксис. В силу слабой типизации PHP такое программирование является обходным вариантом, чтобы типы сохранить, но к ООП парадигме отношения не имеет. Потому тут сильно вперед вырывается тот же Golang, проще описывать такие процедурные вещи и типизированный.

Валидировать можно и нужно ДТО к примеру, модель доменную не нужно -- она всегда валидна в любом из состояний, по определению. Автомобиль либо едет сам, если есть бензин, либо нет, никто его извне не "едет" после некой проверки наличия бензина извне.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы