Расширенная проверка типов с компонентом OptionsResolver


Мне нужны типы разрешений, которые реализуют два интерфейса (Foo и Bar), а не один из них.

interface Foo {};
interface Bar {};

class Foz implements Foo {};
class Baz implements Bar {};
class Foobar implements Foo, Bar {};

$resolver = new OptionsResolver();
$resolver->setRequired('data');
$resolver->setAllowedTypes('data', ['Foo', 'Bar']);

Неправильно! также допускает экземпляры Foz и Baz.


Мне нужно разрешить подкласс типов Bar, а не Bar экземпляров.

class Bar {};
class Foobar extends Bar {};
class FoobarBaz extends Foobar {};

$resolver = new OptionsResolver();
$resolver->setRequired('data');
$resolver->setAllowedTypes('data', ['Bar']);

Неправильно! также допускает Bar экземпляры.


Я могу перепроектировать свои классы/интерфейсы, но это не проблема дизайна. Итак, возможно ли достичь этого с помощью этого компонента?

Author: yceruto, 2016-09-28

3 answers

См. Определение допустимых значений параметра формы в зависимости от другого значения параметра в типе формы.

Для этого следует использовать нормализатор :

use Symfony\Component\Form\Exception\InvalidConfigurationException;

$resolver->setNormalizer('data', function(Options $options, $data) {
    if (!$data instanceof Foo && !$data instanceof Bar) {
        throw new InvalidConfigurationException('"data" option must implement "Foo" and "Bar" interfaces.');
    }

    return $data;
});
 3
Author: Heah, 2017-05-23 11:46:31

Подпись OptionsResolver::setAllowedTypes() - это просто это:

setAllowedTypes(string $option, string|string[] $allowedTypes)

Аргумент $allowedTypes может принимать список строк и используется в качестве логики ИЛИ, поэтому любые из этих типов будут разрешены - боюсь, это все, что вы можете сделать...

Обратите внимание, что для того, чтобы разрешить сложные комбинации, которые вы хотите, вам потребуется либо больше аргументов, либо другие методы, иначе невозможно узнать, хотите ли вы "любой из этих типов", "все эти типы одновременно", "любой тип но эти" или любая другая комбинация, которую вы можете себе представить...

Я предполагаю, что они могут предоставить метод, который принимает функцию обратного вызова в качестве второго аргумента, так что вы можете выполнять любые сумасшедшие проверки, которые хотите, но AFAIK, которого еще не существует (пока).

 1
Author: MikO, 2016-12-08 10:53:01

Наконец, я нашел способ, но я совсем не уверен, что это обычный способ:

//...
function is_foobar($value) {
    //return true or false;
}

$resolver = new OptionsResolver();
$resolver->setRequired('data');
$resolver->setAllowedTypes('data', 'foobar');
//...

РЕДАКТИРОВАТЬ:

Ну, после того, как я продолжу спать, я думаю, что мой подход неверен, потому что это уже сделано с помощью методов setAllowedValues или addAllowedValues:

$resolver->setAllowedValues('foo', function ($value) {
    return $value instanceof Foo && $value instanceof Bar;
});

Поэтому нет необходимости использовать setAllowedTypes для этой цели.

 1
Author: yceruto, 2017-07-07 15:43:21