Skip to content

Navigation Menu

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

Commit 937a1cd

Browse filesBrowse files
committed
Added support for nested options definition
1 parent 5e28ac3 commit 937a1cd
Copy full SHA for 937a1cd

File tree

3 files changed

+480
-4
lines changed
Filter options

3 files changed

+480
-4
lines changed

‎src/Symfony/Component/OptionsResolver/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/OptionsResolver/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
4.2.0
55
-----
66

7+
* added support for nested options definition
78
* added `setDeprecated` and `isDeprecated` methods
89

910
3.4.0

‎src/Symfony/Component/OptionsResolver/OptionsResolver.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/OptionsResolver/OptionsResolver.php
+69-4Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ class OptionsResolver implements Options
3737
*/
3838
private $defaults = array();
3939

40+
/**
41+
* A list of closure for nested options.
42+
*
43+
* @var \Closure[][]
44+
*/
45+
private $nested = array();
46+
4047
/**
4148
* The names of required options.
4249
*/
@@ -130,6 +137,20 @@ class OptionsResolver implements Options
130137
* is spread across different locations of your code, such as base and
131138
* sub-classes.
132139
*
140+
* If you want to define nested options, you can pass a closure with the
141+
* following signature:
142+
*
143+
* $options->setDefault('database', function (OptionsResolver $resolver) {
144+
* $resolver->setDefined(array('dbname', 'host', 'port', 'user', 'pass'));
145+
* }
146+
*
147+
* To get access to the parent options, add a second argument to the closure's
148+
* signature:
149+
*
150+
* function (OptionsResolver $resolver, Options $parent) {
151+
* // 'default' === $parent['connection']
152+
* }
153+
*
133154
* @param string $option The name of the option
134155
* @param mixed $value The default value of the option
135156
*
@@ -167,15 +188,27 @@ public function setDefault($option, $value)
167188
$this->lazy[$option][] = $value;
168189
$this->defined[$option] = true;
169190

170-
// Make sure the option is processed
171-
unset($this->resolved[$option]);
191+
// Make sure the option is processed and is not nested anymore
192+
unset($this->resolved[$option], $this->nested[$option]);
193+
194+
return $this;
195+
}
196+
197+
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))) {
198+
// Store closure for later evaluation
199+
$this->nested[$option][] = $value;
200+
$this->defaults[$option] = array();
201+
$this->defined[$option] = true;
202+
203+
// Make sure the option is processed and is not lazy anymore
204+
unset($this->resolved[$option], $this->lazy[$option]);
172205

173206
return $this;
174207
}
175208
}
176209

177-
// This option is not lazy anymore
178-
unset($this->lazy[$option]);
210+
// This option is not lazy nor nested anymore
211+
unset($this->lazy[$option], $this->nested[$option]);
179212

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

390+
public function isNested(string $option): bool
391+
{
392+
return isset($this->nested[$option]);
393+
}
394+
357395
/**
358396
* Deprecates an option, allowed types or values.
359397
*
@@ -671,6 +709,7 @@ public function clear()
671709

672710
$this->defined = array();
673711
$this->defaults = array();
712+
$this->nested = array();
674713
$this->required = array();
675714
$this->resolved = array();
676715
$this->lazy = array();
@@ -803,6 +842,32 @@ public function offsetGet($option)
803842

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

845+
// Resolve the option if it is a nested definition
846+
if (isset($this->nested[$option])) {
847+
// If the closure is already being called, we have a cyclic dependency
848+
if (isset($this->calling[$option])) {
849+
throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', implode('", "', array_keys($this->calling))));
850+
}
851+
852+
if (!\is_array($value)) {
853+
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')));
854+
}
855+
856+
// The following section must be protected from cyclic calls.
857+
// BEGIN
858+
$this->calling[$option] = true;
859+
try {
860+
$resolver = new self();
861+
foreach ($this->nested[$option] as $closure) {
862+
$closure($resolver, $this);
863+
}
864+
$value = $resolver->resolve($value);
865+
} finally {
866+
unset($this->calling[$option]);
867+
}
868+
// END
869+
}
870+
806871
// Resolve the option if the default value is lazily evaluated
807872
if (isset($this->lazy[$option])) {
808873
// If the closure is already being called, we have a cyclic

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.