8000 [DependencyInjection] Introduce a new ParameterResolver · symfony/symfony@91e6f1a · GitHub
[go: up one dir, main page]

Skip to content

Commit 91e6f1a

Browse files
committed
[DependencyInjection] Introduce a new ParameterResolver
1 parent 4eeb1f0 commit 91e6f1a

File tree

6 files changed

+241
-147
lines changed

6 files changed

+241
-147
lines changed

src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php

Lines changed: 16 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
*/
2323
class ParameterBag implements ParameterBagInterface
2424
{
25+
use ParameterResolverTrait;
26+
2527
protected $parameters = array();
2628
protected $resolved = false;
2729

@@ -157,36 +159,6 @@ public function resolve()
157159
$this->resolved = true;
158160
}
159161

160-
/**
161-
* Replaces parameter placeholders (%name%) by their values.
162-
*
163-
* @param mixed $value A value
164-
* @param array $resolving An array of keys that are being resolved (used internally to detect circular references)
165-
*
166-
* @return mixed The resolved value
167-
*
168-
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
169-
* @throws ParameterCircularReferenceException if a circular reference if detected
170-
* @throws RuntimeException when a given parameter has a type problem.
171-
*/
172-
public function resolveValue($value, array $resolving = array())
173-
{
174-
if (is_array($value)) {
175-
$args = array();
176-
foreach ($value as $k => $v) {
177-
$args[$this->resolveValue($k, $resolving)] = $this->resolveValue($v, $resolving);
178-
}
179-
180-
return $args;
181-
}
182-
183-
if (!is_string($value)) {
184-
return $value;
185-
}
186-
187-
return $this->resolveString($value, $resolving);
188-
}
189-
190162
/**
191163
* Resolves parameters inside a string.
192164
*
@@ -198,50 +170,21 @@ public function resolveValue($value, array $resolving = array())
198170
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
199171
* @throws ParameterCircularReferenceException if a circular reference if detected
200172
* @throws RuntimeException when a given parameter has a type problem.
173+
*
174+
* @deprecated since 3.2, to be removed in 4.0. Use {@link static::resolveValue()} instead.
201175
*/
202176
public function resolveString($value, array $resolving = array())
203177
{
204-
// we do this to deal with non string values (Boolean, integer, ...)
205-
// as the preg_replace_callback throw an exception when trying
206-
// a non-string in a parameter value
207-
if (preg_match('/^%([^%\s]+)%$/', $value, $match)) {
208-
$key = $match[1];
209-
$lcKey = strtolower($key);
210-
211-
if (isset($resolving[$lcKey])) {
212-
throw new ParameterCircularReferenceException(array_keys($resolving));
213-
}
214-
215-
$resolving[$lcKey] = true;
216-
217-
return $this->resolved ? $this->get($key) : $this->resolveValue($this->get($key), $resolving);
218-
}
219-
220-
return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($resolving, $value) {
221-
// skip %%
222-
if (!isset($match[1])) {
223-
return '%%';
224-
}
225-
226-
$key = $match[1];
227-
$lcKey = strtolower($key);
228-
if (isset($resolving[$lcKey])) {
229-
throw new ParameterCircularReferenceException(array_keys($resolving));
230-
}
231-
232-
$resolved = $this->get($key);
178+
@trigger_error(sprintf('The %s method is deprecated since version 3.2 and will be removed in 4.0. Use %s::resolveValue() instead.', __METHOD__, __CLASS__), E_USER_DEPRECATED);
233179

234-
if (!is_string($resolved) && !is_numeric($resolved)) {
235-
throw new RuntimeException(sprintf('A string value must be composed of strings and/or numbers, but found parameter "%s" of type %s inside string value "%s".', $key, gettype($resolved), $value));
236-
}
237-
238-
$resolved = (string) $resolved;
239-
$resolving[$lcKey] = true;
240-
241-
return $this->isResolved() ? $resolved : $this->resolveString($resolved, $resolving);
242-
}, $value);
180+
return $this->resolveValue($value, $resolving);
243181
}
244182

183+
/**
184+
* Whether the parameters are resolved or not (%parameter% replaced).
185+
*
186+
* @return bool
187+
*/
245188
public function isResolved()
246189
{
247190
return $this->resolved;
@@ -288,4 +231,9 @@ public function unescapeValue($value)
288231

289232
return $value;
290233
}
234+
235+
protected function getParameter($name, $resolving = array())
236+
{
237+
return $this->resolved ? $this->get($name) : $this->resolveValue($this->get($name), $resolving);
238+
}
291239
}

src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBagInterface.php

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
*
2020
* @author Fabien Potencier <fabien@symfony.com>
2121
*/
22-
interface ParameterBagInterface
22+
interface ParameterBagInterface extends ParameterResolverInterface
2323
{
2424
/**
2525
* Clears all parameters.
@@ -86,15 +86,6 @@ public function has($name);
8686
*/
8787
public function resolve();
8888

89-
/**
90-
* Replaces parameter placeholders (%name%) by their values.
91-
*
92-
* @param mixed $value A value
93-
*
94-
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
95-
*/
96-
public function resolveValue($value);
97-
9889
/**
9990
* Escape parameter placeholders %.
10091
*
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\ParameterBag;
13+
14+
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
15+
use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
16+
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
17+
18+
/**
19+
* Replaces parameter placeholders (%name%) by their values.
20+
*
21+
* @author Guilhem N. <egetick@gmail.com>
22+
*/
23+
interface ParameterResolverInterface
24+
{
25+
/**
26+
* Replaces parameter placeholders (%name%) by their values.
27+
*
28+
* @param mixed $value A value
29+
*
30+
* @return mixed The resolved value
31+
*
32+
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
33+
* @throws ParameterCircularReferenceException if a circular reference is detected
34+
* @throws RuntimeException when a given parameter has a type problem.
35+
*/
36+
public function resolveValue($value);
37+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\ParameterBag;
13+
14+
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
15+
use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
16+
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
17+
18+
/**
19+
* Implementation of {@link ParameterResolverInterface}.
20+
*
21+
* @author Guilhem N. <egetick@gmail.com>
22+
*/
23+
trait ParameterResolverTrait
24+
{
25+
/**
26+
* Replaces parameter placeholders (%name%) by their values.
27+
*
28+
* @param mixed $value A value
29+
*
30+
* @return mixed The resolved value
31+
*
32+
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
33+
* @throws ParameterCircularReferenceException if a circular reference is detected
34+
* @throws RuntimeException when a given parameter has a type problem.
35+
*/
36+
public function resolveValue($value, array $resolving = array())
37+
{
38+
if (is_array($value)) {
39+
$args = array();
40+
foreach ($value as $k => $v) {
41+
$args[$this->resolveValue($k, $resolving)] = $this->resolveValue($v, $resolving);
42+
}
43+
44+
return $args;
45+
}
46+
47+
if (!is_string($value)) {
48+
return $value;
49+
}
50+
51+
// we do this to deal with non string values (Boolean, integer, ...)
52+
// as the preg_replace_callback throw an exception when trying
53+
// a non-string in a parameter value
54+
if (preg_match('/^%([^%\s]+)%$/', $value, $match)) {
55+
$key = strtolower($match[1]);
56+
57+
if (isset($resolving[$key])) {
58+
throw new ParameterCircularReferenceException(array_keys($resolving));
59+
}
60+
61+
$resolving[$key] = true;
62+
63+
return $this->getParameter($key, $resolving);
64+
}
65+
66+
return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($resolving, $value) {
67+
// skip %%
68+
if (!isset($match[1])) {
69+
return '%%';
70+
}
71+
72+
$key = strtolower($match[1]);
73+
if (isset($resolving[$key])) {
74+
throw new ParameterCircularReferenceException(array_keys($resolving));
75+
}
76+
77+
$resolving[$key] = true;
78+
$resolved = $this->getParameter($key, $resolving);
79+
80+
if (!is_string($resolved) && !is_numeric($resolved)) {
81+
throw new RuntimeException(sprintf('A string value must be composed of strings and/or numbers, but found parameter "%s" of type %s inside string value "%s".', $key, gettype($resolved), $value));
82+
}
83+
84+
return (string) $resolved;
85+
}, $value);
86+
}
87+
88+
/**
89+
* Gets a parameter.
90+
*
91+
* @param string $name The parameter name
92+
* @param array $resolving used internally to detect circular references
93+
*
94+
* @return mixed The parameter value
95+
*
96+
* @throws ParameterNotFoundException if the parameter is not defined
97+
*/
98+
abstract protected function getParameter($name, $resolving = array());
99+
}

src/Symfony/Component/DependencyInjection/Tests/ParameterBag/ParameterBagTest.php

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313

1414
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
1515
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
16-
use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
17-
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
1816

1917
class ParameterBagTest extends \PHPUnit_Framework_TestCase
2018
{
@@ -107,73 +105,6 @@ public function testHas()
107105
$this->assertFalse($bag->has('bar'), '->has() returns false if a parameter is not defined');
108106
}
109107

110-
public function testResolveValue()
111-
{
112-
$bag = new ParameterBag(array());
113-
$this->assertEquals('foo', $bag->resolveValue('foo'), '->resolveValue() returns its argument unmodified if no placeholders are found');
114-
115-
$bag = new ParameterBag(array('foo' => 'bar'));
116-
$this->assertEquals('I\'m a bar', $bag->resolveValue('I\'m a %foo%'), '->resolveValue() replaces placeholders by their values');
117-
$this->assertEquals(array('bar' => 'bar'), $bag->resolveValue(array('%foo%' => '%foo%')), '->resolveValue() replaces placeholders in keys and values of arrays');
118-
$this->assertEquals(array('bar' => array('bar' => array('bar' => 'bar'))), $bag->resolveValue(array('%foo%' => array('%foo%' => array('%foo%' => '%foo%')))), '->resolveValue() replaces placeholders in nested arrays');
119-
$this->assertEquals('I\'m a %%foo%%', $bag->resolveValue('I\'m a %%foo%%'), '->resolveValue() supports % escaping by doubling it');
120-
$this->assertEquals('I\'m a bar %%foo bar', $bag->resolveValue('I\'m a %foo% %%foo %foo%'), '->resolveValue() supports % escaping by doubling it');
121-
$this->assertEquals(array('foo' => array('bar' => array('ding' => 'I\'m a bar %%foo %%bar'))), $bag->resolveValue(array('foo' => array('bar' => array('ding' => 'I\'m a bar %%foo %%bar')))), '->resolveValue() supports % escaping by doubling it');
122-
123-
$bag = new ParameterBag(array('foo' => true));
124-
$this->assertTrue($bag->resolveValue('%foo%'), '->resolveValue() replaces arguments that are just a placeholder by their value without casting them to strings');
125-
$bag = new ParameterBag(array('foo' => null));
126-
$this->assertNull($bag->resolveValue('%foo%'), '->resolveValue() replaces arguments that are just a placeholder by their value without casting them to strings');
127-
128-
$bag = new ParameterBag(array('foo' => 'bar', 'baz' => '%%%foo% %foo%%% %%foo%% %%%foo%%%'));
129-
$this->assertEquals('%%bar bar%% %%foo%% %%bar%%', $bag->resolveValue('%baz%'), '->resolveValue() replaces params placed besides escaped %');
130-
131-
$bag = new ParameterBag(array('baz' => '%%s?%%s'));
132-
$this->assertEquals('%%s?%%s', $bag->resolveValue('%baz%'), '->resolveValue() is not replacing greedily');
133-
134-
$bag = new ParameterBag(array());
135-
try {
136-
$bag->resolveValue('%foobar%');
137-
$this->fail('->resolveValue() throws an InvalidArgumentException if a placeholder references a non-existent parameter');
138-
} catch (ParameterNotFoundException $e) {
139-
$this->assertEquals('You have requested a non-existent parameter "foobar".', $e->getMessage(), '->resolveValue() throws a ParameterNotFoundException if a placeholder references a non-existent parameter');
140-
}
141-
142-
try {
143-
$bag->resolveValue('foo %foobar% bar');
144-
$this->fail('->resolveValue() throws a ParameterNotFoundException if a placeholder references a non-existent parameter');
145-
} catch (ParameterNotFoundException $e) {
146-
$this->assertEquals('You have requested a non-existent parameter "foobar".', $e->getMessage(), '->resolveValue() throws a ParameterNotFoundException if a placeholder references a non-existent parameter');
147-
}
148-
149-
$bag = new ParameterBag(array('foo' => 'a %bar%', 'bar' => array()));
150-
try {
151-
$bag->resolveValue('%foo%');
152-
$this->fail('->resolveValue() throws a RuntimeException when a parameter embeds another non-string parameter');
153-
} catch (RuntimeException $e) {
154-
$this->assertEquals('A string value must be composed of strings and/or numbers, but found parameter "bar" of type array inside string value "a %bar%".', $e->getMessage(), '->resolveValue() throws a RuntimeException when a parameter embeds another non-string 10000 parameter');
155-
}
156-
157-
$bag = new ParameterBag(array('foo' => '%bar%', 'bar' => '%foobar%', 'foobar' => '%foo%'));
158-
try {
159-
$bag->resolveValue('%foo%');
160-
$this->fail('->resolveValue() throws a ParameterCircularReferenceException when a parameter has a circular reference');
161-
} catch (ParameterCircularReferenceException $e) {
162-
$this->assertEquals('Circular reference detected for parameter "foo" ("foo" > "bar" > "foobar" > "foo").', $e->getMessage(), '->resolveValue() throws a ParameterCircularReferenceException when a parameter has a circular reference');
163-
}
164-
165-
$bag = new ParameterBag(array('foo' => 'a %bar%', 'bar' => 'a %foobar%', 'foobar' => 'a %foo%'));
166-
try {
167-
$bag->resolveValue('%foo%');
168-
$this->fail('->resolveValue() throws a ParameterCircularReferenceException when a parameter has a circular reference');
169-
} catch (ParameterCircularReferenceException $e) {
170-
$this->assertEquals('Circular reference detected for parameter "foo" ("foo" > "bar" > "foobar" > "foo").', $e->getMessage(), '->resolveValue() throws a ParameterCircularReferenceException when a parameter has a circular reference');
171-
}
172-
173-
$bag = new ParameterBag(array('host' => 'foo.bar', 'port' => 1337));
174-
$this->assertEquals('foo.bar:1337', $bag->resolveValue('%host%:%port%'));
175-
}
176-
177108
public function testResolveIndicatesWhyAParameterIsNeeded()
178109
{
179110
$bag = new ParameterBag(array('foo' => '%bar%'));
@@ -221,6 +152,7 @@ public function testEscapeValue()
221152

222153
/**
223154
* @dataProvider stringsWithSpacesProvider
155+
* @group legacy
224156
*/
225157
public function testResolveStringWithSpacesReturnsString($expected, $test, $description)
226158
{

0 commit comments

Comments
 (0)
2A4E
0