2016-09-28 7 views
5

2つのインターフェイス(FooおよびBar)を実装する型を許可する必要があります。OptionsResolverコンポーネントによる高度な型検証

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のインスタンスも許可します。


クラス/インターフェイスを再設計できますが、設計上の問題ではありません。 だから、このコンポーネントで実現することは可能でしょうか?

答えて

2

Define a form option allowed values depending on another option value in a 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; 
}); 
1

OptionsResolver::setAllowedTypes()の署名はただthisです:

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

引数$allowedTypesは、文字列のリストを受け入れることができ、およびロジックORとして使用されているので、これらのタイプのどのが許可されます - あなたができることはすべて私が恐れることです...

あなたが望む複雑な組み合わせを可能にするためには、もっと多くの引数や他の方法が必要です。 eは、「これらのタイプのいずれか」、「これらのタイプのすべてを同時に」、「これらのタイプ以外のタイプ」、または他の組み合わせを想像することができるかどうかを知る方法はありません。

2番目の引数としてコールバック関数を受け入れるメソッドを提供することができますので、必要なクレイジーチェックを行うことができますが、まだ存在しないAFAIKがあります。

+0

感謝@MikOをあなたの答えのために、私はあなたのアドバイスに感謝(1) – yceruto

1

最後に、私は道を見つけたが、私はそれは、従来の方法だということは全くわからない:

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

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

EDIT:

まあ、私が寝た後、I既にsetAllowedValuesまたはaddAllowedValuesメソッドを使用して行われているため、私のアプローチが間違っていると思います。

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

このため、setAllowedTypesを使用する必要はありません。

+1

ええ、あなたはsymfonyの 'OptionsResolver'クラスを見れば、' offsetGet ($ isFunction = 'is _'。$ type)) 'のようにチェックしていますので、驚いたことにそれはうまくいくはずです。恐ろしい回避策だと言えます:) – MikO

+1

はい "恐ろしい"という言葉ですが、さらに悪いことに、無効な型のエラーメッセージです: 'InvalidOptionsException:値" Bazのオプション "data"は "foobar"しかし、タイプ "Baz"です.' :) – yceruto

関連する問題