10000 [DependencyInjection] Introduce a new ParameterResolver · symfony/symfony@8c0875c · GitHub
[go: up one dir, main page]

Skip to content

Commit 8c0875c

Browse files
committed
[DependencyInjection] Introduce a new ParameterResolver
1 parent 904279e commit 8c0875c

File tree

6 files changed

+241
-145
lines changed

6 files changed

+241
-145
lines changed

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

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

@@ -141,36 +143,6 @@ public function resolve()
141143
$this->resolved = true;
142144
}
143145

144-
/**
145-
* Replaces parameter placeholders (%name%) by their values.
146-
*
147-
* @param mixed $value A value
148-
* @param array $resolving An array of keys that are being resolved (used internally to detect circular references)
149-
*
150-
* @return mixed The resolved value
151-
*
152-
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
153-
* @throws ParameterCircularReferenceException if a circular reference if detected
154-
* @throws RuntimeException when a given parameter has a type problem.
155-
*/
156-
public function resolveValue($value, array $resolving = array())
157-
{
158-
if (is_array($value)) {
159-
$args = array();
160-
foreach ($value as $k => $v) {
161-
$args[$this->resolveValue($k, $resolving)] = $this->resolveValue($v, $resolving);
162-
}
163-
164-
return $args;
165-
}
166-
167-
if (!is_string($value)) {
168-
return $value;
169-
}
170-
171-
return $this->resolveString($value, $resolving);
172-
}
173-
174146
/**
175147
* Resolves parameters inside a string.
176148
*
@@ -182,48 +154,21 @@ public function resolveValue($value, array $resolving = array())
182154
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
183155
* @throws ParameterCircularReferenceException if a circular reference if detected
184156
* @throws RuntimeException when a given parameter has a type problem.
157+
*
158+
* @deprecated since 3.2, to be removed in 4.0. Use {@link static::resolveValue()} instead.
185159
*/
186160
public function resolveString($value, array $resolving = array())
187161
{
188-
// we do this to deal with non string values (Boolean, integer, ...)
189-
// as the preg_replace_callback throw an exception when trying
190-
// a non-string in a parameter value
191-
if (preg_match('/^%([^%\s]+)%$/', $value, $match)) {
192-
$key = strtolower($match[1]);
193-
194-
if (isset($resolving[$key])) {
195-
throw new ParameterCircularReferenceException(array_keys($resolving));
196-
}
197-
198-
$resolving[$key] = true;
199-
200-
return $this->resolved ? $this->get($key) : $this->resolveValue($this->get($key), $resolving);
201-
}
202-
203-
return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($resolving, $value) {
204-
// skip %%
205-
if (!isset($match[1])) {
206-
return '%%';
207-
}
208-
209-
$key = strtolower($match[1]);
210-
if (isset($resolving[$key])) {
211-
throw new ParameterCircularReferenceException(array_keys($resolving));
212-
}
213-
214-
$resolved = $this->get($key);
162+
@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);
215163

216-
if (!is_string($resolved) && !is_numeric($resolved)) {
217-
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));
218-
}
219-
220-
$resolved = (string) $resolved;
221-
$resolving[$key] = true;
222-
223-
return $this->isResolved() ? $resolved : $this->resolveString($resolved, $resolving);
224-
}, $value);
164+
return $this->resolveValue($value, $resolving);
225165
}
226166

167+
/**
168+
* Whether the parameters are resolved or not (%parameter% replaced).
169+
*
170+
* @return bool
171+
*/
227172
public function isResolved()
228173
{
229174
return $this->resolved;
@@ -270,4 +215,9 @@ public function unescapeValue($value)
270215

271216
return $value;
272217
}
218+
219+
protected function getParameter($name, $resolving = array())
220+
{
221+
return $this->resolved ? $this->get($name) : $this->resolveValue($this->get($name), $resolving);
222+
}
273223
}

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
{
@@ -112,73 +110,6 @@ public function testHas()
112110
$this->assertFalse($bag->has('bar'), '->has() returns false if a parameter is not defined');
113111
}
114112

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

227158
/**
228159
* @dataProvider stringsWithSpacesProvider
160+
* @group legacy
229161
*/
230162
public function testResolveStringWithSpacesReturnsString($expected, $test, $description)
231163
{

0 commit comments

Comments
 (0)
0