Advanced type checking using the OptionsResolver component

I need permission types that implement two interfaces ( Foo and Bar ), and not one of them.

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

Wrong! also allows instances of Foz and Baz .


I need to allow subclass types of Bar , not Bar instances.

 class Bar {}; class Foobar extends Bar {}; class FoobarBaz extends Foobar {}; $resolver = new OptionsResolver(); $resolver->setRequired('data'); $resolver->setAllowedTypes('data', ['Bar']); 

Wrong! allows instances of Bar .


I can redesign my classes / interfaces, but this is not a design issue. So, can this be achieved with this component?

+5
source share
3 answers

See Define valid form parameter values ​​depending on another parameter value in FormType format .

To do this, use the normalizer :

 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; }); 
+2
source

The signature of OptionsResolver::setAllowedTypes() is just this :

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

The $allowedTypes can take a list of strings and be used as a logical OR, so any of these types will be allowed - all you can do is I'm afraid ...

Please note that in order to resolve the complex combinations that you need, you will need more arguments or other methods, otherwise there is no way to find out if you want "any of these types", "all these types at the same time" , "any type, but these" or any other combination that you can imagine ...

I suppose they can provide a method that takes a callback function as the second argument, so you can perform any crazy checks, but AFAIK does not exist (yet).

+1
source

Finally, I found a way, but I'm not sure if this is the usual way:

 //... function is_foobar($value) { //return true or false; } $resolver = new OptionsResolver(); $resolver->setRequired('data'); $resolver->setAllowedTypes('data', 'foobar'); //... 

EDIT:

Well, after I sleep, I think my approach is wrong, because it has already been executed using the setAllowedValues or addAllowedValues :

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

Therefore, you do not need to use setAllowedTypes for this.

+1
source

Source: https://habr.com/ru/post/1257403/


All Articles