Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[OptionsResolver] Added support for nesting options definition #27291

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

Merged
merged 1 commit into from
Oct 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Added support for nested options definition
  • Loading branch information
yceruto committed Sep 12, 2018
commit d04e40be5ab82415b979e047c06d6c76182fcdb2
1 change: 1 addition & 0 deletions 1 src/Symfony/Component/OptionsResolver/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ CHANGELOG
4.2.0
-----

* added support for nested options definition
* added `setDeprecated` and `isDeprecated` methods

3.4.0
Expand Down
73 changes: 69 additions & 4 deletions 73 src/Symfony/Component/OptionsResolver/OptionsResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ class OptionsResolver implements Options
*/
private $defaults = array();

/**
* A list of closure for nested options.
*
* @var \Closure[][]
*/
private $nested = array();

/**
* The names of required options.
*/
Expand Down Expand Up @@ -130,6 +137,20 @@ class OptionsResolver implements Options
* is spread across different locations of your code, such as base and
* sub-classes.
*
* If you want to define nested options, you can pass a closure with the
* following signature:
*
* $options->setDefault('database', function (OptionsResolver $resolver) {
* $resolver->setDefined(array('dbname', 'host', 'port', 'user', 'pass'));
* }
*
* To get access to the parent options, add a second argument to the closure's
* signature:
*
* function (OptionsResolver $resolver, Options $parent) {
* // 'default' === $parent['connection']
* }
*
* @param string $option The name of the option
* @param mixed $value The default value of the option
*
Expand Down Expand Up @@ -167,15 +188,27 @@ public function setDefault($option, $value)
$this->lazy[$option][] = $value;
$this->defined[$option] = true;

// Make sure the option is processed
unset($this->resolved[$option]);
// Make sure the option is processed and is not nested anymore
unset($this->resolved[$option], $this->nested[$option]);

return $this;
}

if (isset($params[0]) && null !== ($class = $params[0]->getClass()) && self::class === $class->name && (!isset($params[1]) || (null !== ($class = $params[1]->getClass()) && Options::class === $class->name))) {
// Store closure for later evaluation
$this->nested[$option][] = $value;
$this->defaults[$option] = array();
$this->defined[$option] = true;

// Make sure the option is processed and is not lazy anymore
unset($this->resolved[$option], $this->lazy[$option]);

return $this;
}
}

// This option is not lazy anymore
unset($this->lazy[$option]);
// This option is not lazy nor nested anymore
unset($this->lazy[$option], $this->nested[$option]);

// Yet undefined options can be marked as resolved, because we only need
// to resolve options with lazy closures, normalizers or validation
Expand Down Expand Up @@ -354,6 +387,11 @@ public function getDefinedOptions()
return array_keys($this->defined);
}

public function isNested(string $option): bool
{
return isset($this->nested[$option]);
}

/**
* Deprecates an option, allowed types or values.
*
Expand Down Expand Up @@ -649,6 +687,7 @@ public function clear()

$this->defined = array();
$this->defaults = array();
$this->nested = array();
$this->required = array();
$this->resolved = array();
$this->lazy = array();
Expand Down Expand Up @@ -767,6 +806,32 @@ public function offsetGet($option)

$value = $this->defaults[$option];

// Resolve the option if it is a nested definition
if (isset($this->nested[$option])) {
// If the closure is already being called, we have a cyclic dependency
if (isset($this->calling[$option])) {
throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', implode('", "', array_keys($this->calling))));
}

if (!\is_array($value)) {
throw new InvalidOptionsException(sprintf('The nested option "%s" with value %s is expected to be of type array, but is of type "%s".', $option, $this->formatValue($value), $this->formatTypeOf($value, 'array')));
}

// The following section must be protected from cyclic calls.
// BEGIN
yceruto marked this conversation as resolved.
Show resolved Hide resolved
$this->calling[$option] = true;
try {
$resolver = new self();
foreach ($this->nested[$option] as $closure) {
$closure($resolver, $this);
}
$value = $resolver->resolve($value);
} finally {
unset($this->calling[$option]);
}
// END
}

// Resolve the option if the default value is lazily evaluated
if (isset($this->lazy[$option])) {
// If the closure is already being called, we have a cyclic
Expand Down
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.