使用 OptionsResolver 组件进行高级类型验证
Advanced type validation with OptionsResolver component
我需要允许实现两个接口(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
个实例。
我可以重新设计我的 classes/interfaces 但这不是设计问题。 那么,是否可以用这个组件来实现呢?
OptionsResolver::setAllowedTypes()
的签名就是this:
setAllowedTypes(string $option, string|string[] $allowedTypes)
参数$allowedTypes
可以接受一个字符串列表,并且用作逻辑OR,所以any的这些类型将被允许 - 恐怕你只能做这些......
请注意,为了允许您想要的复杂组合,您需要更多参数或其他方法,否则无法知道您是否需要 "any of these types"、"all of these types at the same time"、"any type but these ones" 或您能想到的任何其他组合...
我猜他们可能会提供一种方法,该方法接受回调函数作为第二个参数,因此您可以进行任何您想要的疯狂检查,但是 AFAIK 不存在(还没有)。
终于找到了一个方法,但我完全不确定这是不是常规方法:
//...
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
。
见。
您应该为此使用 标准化器:
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;
});
我需要允许实现两个接口(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
个实例。
我可以重新设计我的 classes/interfaces 但这不是设计问题。 那么,是否可以用这个组件来实现呢?
OptionsResolver::setAllowedTypes()
的签名就是this:
setAllowedTypes(string $option, string|string[] $allowedTypes)
参数$allowedTypes
可以接受一个字符串列表,并且用作逻辑OR,所以any的这些类型将被允许 - 恐怕你只能做这些......
请注意,为了允许您想要的复杂组合,您需要更多参数或其他方法,否则无法知道您是否需要 "any of these types"、"all of these types at the same time"、"any type but these ones" 或您能想到的任何其他组合...
我猜他们可能会提供一种方法,该方法接受回调函数作为第二个参数,因此您可以进行任何您想要的疯狂检查,但是 AFAIK 不存在(还没有)。
终于找到了一个方法,但我完全不确定这是不是常规方法:
//...
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
。
见
您应该为此使用 标准化器:
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;
});