5

我需要允许实现两个接口(FooBar)的类型,而不是其中之一。

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']);

错误的!也允许FozBaz实例。


我需要允许类型的子类Bar,而不是Bar实例。

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

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

错误的!也允许Bar实例。


我可以重新设计我的类/接口,但这不是设计问题。那么,有没有可能用这个组件来实现呢?

4

3 回答 3

5

请参阅根据 FormType 中的另一个选项值定义表单选项允许的值

您应该为此使用规范化器:

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;
});
于 2016-09-28T19:44:33.913 回答
2

最后,我找到了一种方法,但我完全不确定这是一种传统的方法:

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

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

编辑:

好吧,在我睡着之后,我认为我的方法是错误的,因为它已经通过 using setAllowedValuesoraddAllowedValues方法完成了:

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

所以没有必要setAllowedTypes为此目的使用。

于 2016-09-28T15:58:56.277 回答
1

的签名OptionsResolver::setAllowedTypes()就是这样

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

该参数$allowedTypes可以接受字符串列表,并用作逻辑OR,因此任何这些类型都将被允许 - 恐怕这就是你所能做的......

请注意,为了允许您想要的复杂组合,您需要更多参数或其他方法,否则无法知道您是否需要“任何这些类型”,“同时所有这些类型”, “除这些之外的任何类型”或您可以想象的任何其他组合......

我猜他们可能会提供一个接受回调函数作为第二个参数的方法,所以你可以做任何你想做的疯狂检查,但是AFAIK不存在(还)。

于 2016-09-28T15:47:12.153 回答