8000 [OptionsResolver] ContextErrorException on array option with callback allowed type · Issue #10202 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[OptionsResolver] ContextErrorException on array option with callback allowed type #10202

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
codekestrel opened this issue Feb 4, 2014 · 2 comments

Comments

@codekestrel
Copy link

In relation to #8375

I would get the following error when passing an array as an option with a callback allowed type:

ContextErrorException: Notice: Array to string conversion in /vendor/symfony/symfony/src/Symfony/Component/OptionsResolver/OptionsResolver.php line 303

The following alternation resolves the problem:

private function validateOptionValues(array $options)
{
    foreach ($this->allowedValues as $option => $allowedValues) {
        if (isset($options[$option])) {
            if (is_array($allowedValues) && !in_array($options[$option], $allowedValues, true)) {
                throw new InvalidOptionsException(sprintf('The option "%s" has the value "%s", but is expected to be one of "%s"', $option, $options[$option], implode('", "', $allowedValues)));
            }

            if (is_callable($allowedValues) && !call_user_func($allowedValues, $options[$option])) {
                if(! is_scalar($options[$option])) {
                    throw new InvalidOptionsException(sprintf(
                        'The option "%s" of value type "%s" does not have valid content', $option, gettype($options[$option])));
                } else {
                    throw new InvalidOptionsException(sprintf('The option "%s" has the value "%s", which it is not valid', $option, $options[$option]));
                }
            }
        }
    }
}

Is this recognized as a real problem?

This may also solve: #4833

@codekestrel
Copy link
Author

I have tested a solution where by nested resolvers can handle array options.
codekestrel@1ca290f

$resolver = new OptionsResolver();

$resolver
    ->setOptional(array(
        'colors'
    ))
    ->setAllowedTypes(array(
        'colors'  => 'array'
    ))
    ->setAllowedValues(array(
        'colors' => OptionsResolver::create()
            ->setOptional(array(
                'r', 'g', 'b'
            ))
            ->setAllowedTypes(array(
                'r' => 'string',
                'g' => 'string',
                'b' => 'string',
            ))
    ))
;

$options = array(
    'colors'  => array(
        'r' => '#AA0000',
        'g' => '#00AA00',
        'b' => array(),
    )
);

$resolver->resolve($options);

// Throws: The option "b" with value "Array" is expected to be of type "string"

I attempted to write it in without breaking BC and by extension without modifying the interface, however I am not sure this solution is entirely elegant. Can anyone take a look?

@webmozart
Copy link
Contributor

This is fixed by #12156.

webmozart added a commit that referenced this issue Oct 22, 2014
…r (webmozart)

This PR was merged into the 2.6-dev branch.

Discussion
----------

[OptionsResolver] Merged Options class into OptionsResolver

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | yes
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | #4500, #9174, #10585, #10202, #11020, makes #7979+#10616 obsolete
| License       | MIT
| Doc PR        | symfony/symfony-docs#4159

#11716 was reverted as preparation of this PR (453882c).

The Options class was merged into OptionsResolver. This made it possible to fix several tickets, as indicated above.

**Usage**

See [the updated documentation](https://github.com/webmozart/symfony-docs/blob/issue11705/components/options_resolver.rst).

**Bug Fixes**

Previously, the options weren't validated before the normalizers were called. As a result, the normalizers had to perform validation again:

```php
$resolver->setAllowedTypes(array(
    'choices' => 'array',
));
$resolver->setNormalizers(array(
    'choices' => function (Options $options, $value) {
         array_merge($options['choices'], ...);
    },
));

// fatal error
$resolver->resolve(array('choices' => 'foobar'));
```

This is fixed now.

**BC Breaks**

The `array` type hint was removed from `setRequired()`, `setAllowedValues()`, `addAllowedValues()`, `setAllowedTypes()` and `addAllowedTypes()`. If anybody implemented `OptionsResolverInterface`, they must adapt their code.

The Options class was turned into an interface extending ArrayAccess and Countable. Anybody instantiating Options directly should instantiate OptionsResolver instead. Anybody using any of the methods available in Options (`get()`, `has()`) should use the ArrayAccess interface instead.

Normalizers are not called anymore for undefined options (#9174). People need to set a default value if they want a normalizer to be executed independent of the options passed to `resolve()`.

**Deprecations**

OptionsResolverInterface was deprecated and will be removed in 3.0. OptionsResolver instances are not supposed to be shared between classes, hence an interface does not make sense.

Several other methods were deprecated. See the CHANGELOG and UPGRADE-2.6 files for information.

**Todo**

- [x] Fix PHPDoc
- [x] Adapt CHANGELOG/UPGRADE
- [x] Adapt documentation
- [x] Deprecate OptionsResolver[Interface]

Commits
-------

642c119 [OptionsResolver] Merged Options class into OptionsResolver
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants
0