8000 feature #23874 [DI] Case sensitive parameter names (ro0NL) · symfony/symfony@481e31c · GitHub
[go: up one dir, main page]

Skip to content

Commit 481e31c

Browse files
committed
feature #23874 [DI] Case sensitive parameter names (ro0NL)
This PR was merged into the 3.4 branch. Discussion ---------- [DI] Case sensitive parameter names | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | yes | Tests pass? | yes | Fixed tickets | #23809 | License | MIT | Doc PR | symfony/symfony-docs#... <!--highly recommended for new features--> @GuilhemN took your patch.. but i use the same deprecation messages as for case sensitive service id's, i found it more clear. Also comparing to $origName to keep the diff smaller Commits ------- 8a1d168 [DI] Case sensitive parameter names
2 parents e8bb73c + 8a1d168 commit 481e31c

20 files changed

+285
-56
lines changed

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ CHANGELOG
77
* deprecated service auto-registration while autowiring
88
* deprecated the ability to check for the initialization of a private service with the `Container::initialized()` method
99
* deprecated support for top-level anonymous services in XML
10+
* deprecated case insensitivity of parameter names
1011

1112
3.3.0
1213
-----

src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,11 +1056,15 @@ private function addDefaultParametersMethod()
10561056

10571057
$php = array();
10581058
$dynamicPhp = array();
1059+
$normalizedParams = array();
10591060

10601061
foreach ($this->container->getParameterBag()->all() as $key => $value) {
10611062
if ($key !== $resolvedKey = $this->container->resolveEnvPlaceholders($key)) {
10621063
throw new InvalidArgumentException(sprintf('Parameter name cannot use env parameters: %s.', $resolvedKey));
10631064
}
1065+
if ($key !== $lcKey = strtolower($key)) {
1066+
$normalizedParams[] = sprintf(' %s => %s,', $this->export($lcKey), $this->export($key));
1067+
}
10641068
$export = $this->exportParameters(array($value));
10651069
$export = explode('0 => ', substr(rtrim($export, " )\n"), 7, -1), 2);
10661070

@@ -1082,7 +1086,7 @@ private function addDefaultParametersMethod()
10821086
public function getParameter($name)
10831087
{
10841088
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
1085-
$name = strtolower($name);
1089+
$name = $this->normalizeParameterName($name);
10861090
10871091
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
10881092
throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
@@ -1100,7 +1104,7 @@ public function getParameter($name)
11001104
*/
11011105
public function hasParameter($name)
11021106
{
1103-
$name = strtolower($name);
1107+
$name = $this->normalizeParameterName($name);
11041108
11051109
return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters);
11061110
}
@@ -1170,6 +1174,26 @@ private function getDynamicParameter(\$name)
11701174
{$getDynamicParameter}
11711175
}
11721176
1177+
1178+
EOF;
1179+
1180+
$code .= ' private $normalizedParameterNames = '.($normalizedParams ? sprintf("array(\n%s\n );", implode("\n", $normalizedParams)) : 'array();')."\n";
1181+
$code .= <<<'EOF'
1182+
1183+
private function normalizeParameterName($name)
1184+
{
1185+
if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) {
1186+
$normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName;
1187+
if ((string) $name !== $normalizedName) {
1188+
@trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since version 3.4.', $name, $normalizedName), E_USER_DEPRECATED);
1189+
}
1190+
} else {
1191+
$normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name;
1192+
}
1193+
1194+
return $normalizedName;
1195+
}
1196+
11731197
EOF;
11741198
} elseif ($dynamicPhp) {
11751199
throw new RuntimeException('You cannot dump a not-frozen container with dynamic parameters.');
@@ -1558,10 +1582,10 @@ private function dumpValue($value, $interpolate = true)
15581582
if (preg_match('/^%([^%]+)%$/', $value, $match)) {
15591583
// we do this to deal with non string values (Boolean, integer, ...)
15601584
// the preg_replace_callback converts them to strings
1561-
return $this->dumpParameter(strtolower($match[1]));
1585+
return $this->dumpParameter($match[1]);
15621586
} else {
15631587
$replaceParameters = function ($match) {
1564-
return "'.".$this->dumpParameter(strtolower($match[2])).".'";
1588+
return "'.".$this->dumpParameter($match[2]).".'";
15651589
};
15661590

15671591
$code = str_replace('%%', '%', preg_replace_callback('/(?<!%)(%)([^%]+)\1/', $replaceParameters, $this->export($value)));
@@ -1607,8 +1631,6 @@ private function dumpLiteralClass($class)
16071631
*/
16081632
private function dumpParameter($name)
16091633
{
1610-
$name = strtolower($name);
1611-
16121634
if ($this->container->isCompiled() && $this->container->hasParameter($name)) {
16131635
$value = $this->container->getParameter($name);
16141636
$dumpedValue = $this->dumpValue($value, false);

src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -486,11 +486,6 @@ private function getArgumentsAsPhp(\DOMElement $node, $name, $file, $lowercase =
486486
$key = array_pop($keys);
487487
} else {
488488
$key = $arg->getAttribute('key');
489-
490-
// parameter keys are case insensitive
491-
if ('parameter' == $name && $lowercase) {
492-
$key = strtolower($key);
493-
}
494489
}
495490

496491
$onInvalid = $arg->getAttribute('on-invalid');

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public function resolve()
9191
parent::resolve();
9292

9393
foreach ($this->envPlaceholders as $env => $placeholders) {
94-
if (!isset($this->parameters[$name = strtolower("env($env)")])) {
94+
if (!$this->has($name = "env($env)")) {
9595
continue;
9696
}
9797
if (is_numeric($default = $this->parameters[$name])) {

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

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ class ParameterBag implements ParameterBagInterface
2525
protected $parameters = array();
2626
protected $resolved = false;
2727

28+
private $normalizedNames = array();
29+
2830
/**
2931
* @param array $parameters An array of parameters
3032
*/
@@ -49,7 +51,7 @@ public function clear()
4951
public function add(array $parameters)
5052
{
5153
foreach ($parameters as $key => $value) {
52-
$this->parameters[strtolower($key)] = $value;
54+
$this->set($key, $value);
5355
}
5456
}
5557

@@ -66,7 +68,7 @@ public function all()
6668
*/
6769
public function get($name)
6870
{
69-
$name = strtolower($name);
71+
$name = $this->normalizeName($name);
7072

7173
if (!array_key_exists($name, $this->parameters)) {
7274
if (!$name) {
@@ -111,15 +113,15 @@ public function get($name)
111113
*/
112114
public function set($name, $value)
113115
{
114-
$this->parameters[strtolower($name)] = $value;
116+
$this->parameters[$this->normalizeName($name)] = $value;
115117
}
116118

117119
/**
118120
* {@inheritdoc}
119121
*/
120122
public function has($name)
121123
{
122-
return array_key_exists(strtolower($name), $this->parameters);
124+
return array_key_exists($this->normalizeName($name), $this->parameters);
123125
}
124126

125127
/**
@@ -129,7 +131,7 @@ public function has($name)
129131
*/
130132
public function remove($name)
131133
{
132-
unset($this->parameters[strtolower($name)]);
134+
unset($this->parameters[$this->normalizeName($name)]);
133135
}
134136

135137
/**
@@ -206,7 +208,7 @@ public function resolveString($value, array $resolving = array())
206208
// a non-string in a parameter value
207209
if (preg_match('/^%([^%\s]+)%$/', $value, $match)) {
208210
$key = $match[1];
209-
$lcKey = strtolower($key);
211+
$lcKey = strtolower($key); // strtolower() to be removed in 4.0
210212

211213
if (isset($resolving[$lcKey])) {
212214
throw new ParameterCircularReferenceException(array_keys($resolving));
@@ -224,7 +226,7 @@ public function resolveString($value, array $resolving = array())
224226
}
225227

226228
$key = $match[1];
227-
$lcKey = strtolower($key);
229+
$lcKey = strtolower($key); // strtolower() to be removed in 4.0
228230
if (isset($resolving[$lcKey])) {
229231
throw new ParameterCircularReferenceException(array_keys($resolving));
230232
}
@@ -288,4 +290,18 @@ public function unescapeValue($value)
288290

289291
return $value;
290292
}
293+
294+
private function normalizeName($name)
295+
{
296+
if (isset($this->normalizedNames[$normalizedName = strtolower($name)])) {
297+
$normalizedName = $this->normalizedNames[$normalizedName];
298+
if ((string) $name !== $normalizedName) {
299+
@trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since version 3.4.', $name, $normalizedName), E_USER_DEPRECATED);
300+
}
301+
} else {
302+
$normalizedName = $this->normalizedNames[$normalizedName] = (string) $name;
303+
}
304+
305+
return $normalizedName;
306+
}
291307
}

src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,21 @@ public function testPrivateServiceTriggersDeprecation()
11291129

11301130
$container->get('bar');
11311131
}
1132+
1133+
/**
1134+
* @group legacy
1135+
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "FOO" instead of "foo" is deprecated since version 3.4.
1136+
*/
1137+
public function testParameterWithMixedCase()
1138+
{
1139+
$container = new ContainerBuilder(new ParameterBag(array('foo' => 'bar')));
1140+
$container->register('foo', 'stdClass')
1141+
->setProperty('foo', '%FOO%');
1142+
1143+
$container->compile();
1144+
1145+
$this->assertSame('bar', $container->get('foo')->foo);
1146+
}
11321147
}
11331148

11341149
class FooClass

src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,6 @@ public function testGetSetParameter()
125125
$sc->setParameter('foo', 'baz');
126126
$this->assertEquals('baz', $sc->getParameter('foo'), '->setParameter() overrides previously set parameter');
127127

128-
$sc->setParameter('Foo', 'baz1');
129-
$this->assertEquals('baz1', $sc->getParameter('foo'), '->setParameter() converts the key to lowercase');
130-
$this->assertEquals('baz1', $sc->getParameter('FOO'), '->getParameter() converts the key to lowercase');
131-
132128
try {
133129
$sc->getParameter('baba');
134130
$this->fail('->getParameter() thrown an \InvalidArgumentException if the key does not exist');
@@ -138,6 +134,20 @@ public function testGetSetParameter()
138134
}
139135
}
140136

137+
/**
138+
* @group legacy
139+
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "Foo" instead of "foo" is deprecated since version 3.4.
140+
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "FOO" instead of "foo" is deprecated since version 3.4.
141+
*/
142+
public function testGetSetParameterWithMixedCase()
143+
{
144+
$sc = new Container(new ParameterBag(array('foo' => 'bar')));
145+
146+
$sc->setParameter('Foo', 'baz1');
147+
$this->assertEquals('baz1', $sc->getParameter('foo'), '->setParameter() converts the key to lowercase');
148+
$this->assertEquals('baz1', $sc->getParameter('FOO'), '->getParameter() converts the key to lowercase');
149+
}
150+
141151
public function testGetServiceIds()
142152
{
143153
$sc = new Container();

src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,4 +670,43 @@ public function testPrivateServiceTriggersDeprecation()
670670

671671
$container->get('bar');
672672
}
673+
674+
/**
675+
* @group legacy
676+
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "foo" instead of "Foo" is deprecated since version 3.4.
677+
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "FOO" instead of "Foo" is deprecated since version 3.4.
678+
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "bar" instead of "BAR" is deprecated since version 3.4.
679+
*/
680+
public function testParameterWithMixedCase()
681+
{
682+
$container = new ContainerBuilder(new ParameterBag(array('Foo' => 'bar', 'BAR' => 'foo')));
683+
$container->compile();
684+
685+
$dumper = new PhpDumper($container);
686+
eval('?>'.$dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Parameter_With_Mixed_Case')));
687+
688+
$container = new \Symfony_DI_PhpDumper_Test_Parameter_With_Mixed_Case();
689+
690+
$this->assertSame('bar', $container->getParameter('foo'));
691+
$this->assertSame('bar', $container->getParameter('FOO'));
692+
$this->assertSame('foo', $container->getParameter('bar'));
693+
$this->assertSame('foo', $container->getParameter('BAR'));
694+
}
695+
696+
/**
697+
* @group legacy
698+
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "FOO" instead of "foo" is deprecated since version 3.4.
699+
*/
700+
public function testParameterWithLowerCase()
701+
{
702+
$container = new ContainerBuilder(new ParameterBag(array('foo' => 'bar')));
703+
$container->compile();
704+
705+
$dumper = new PhpDumper($container);
706+
eval('?>'.$dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Parameter_With_Lower_Case')));
707+
708+
$container = new \Symfony_DI_PhpDumper_Test_Parameter_With_Lower_Case();
709+
710+
$this->assertSame('bar', $container->getParameter('FOO'));
711+
}
673712
}

src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container8.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
55

66
$container = new ContainerBuilder(new ParameterBag(array(
7-
'FOO' => '%baz%',
7+
'foo' => '%baz%',
88
'baz' => 'bar',
99
'bar' => 'foo is %%foo bar',
1010
'escape' => '@escapeme',

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services10.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ protected function getTestService()
7878
public function getParameter($name)
7979
{
8080
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
81-
$name = strtolower($name);
81+
$name = $this->normalizeParameterName($name);
8282

8383
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
8484
throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
@@ -96,7 +96,7 @@ public function getParameter($name)
9696
*/
9797
public function hasParameter($name)
9898
{
99-
$name = strtolower($name);
99+
$name = $this->normalizeParameterName($name);
100100

101101
return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters);
102102
}
@@ -142,6 +142,22 @@ private function getDynamicParameter($name)
142142
throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name));
143143
}
144144

145+
private $normalizedParameterNames = array();
146+
147+
private function normalizeParameterName($name)
148+
{
149+
if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) {
150+
$normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName;
151+
if ((string) $name !== $normalizedName) {
152+
@trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since version 3.4.', $name, $normalizedName), E_USER_DEPRECATED);
153+
}
154+
} else {
155+
$normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name;
156+
}
157+
158+
return $normalizedName;
159+
}
160+
145161
/**
146162
* Gets the default parameters.
147163
*

0 commit comments

Comments
 (0)
0