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
-------

8a1d16839e [DI] Case sensitive parameter names
This commit is contained in:
Fabien Potencier 2017-08-22 15:02:44 -07:00
commit 481e31c2d1
20 changed files with 285 additions and 56 deletions

View File

@ -7,6 +7,7 @@ CHANGELOG
* deprecated service auto-registration while autowiring * deprecated service auto-registration while autowiring
* deprecated the ability to check for the initialization of a private service with the `Container::initialized()` method * deprecated the ability to check for the initialization of a private service with the `Container::initialized()` method
* deprecated support for top-level anonymous services in XML * deprecated support for top-level anonymous services in XML
* deprecated case insensitivity of parameter names
3.3.0 3.3.0
----- -----

View File

@ -1056,11 +1056,15 @@ EOF;
$php = array(); $php = array();
$dynamicPhp = array(); $dynamicPhp = array();
$normalizedParams = array();
foreach ($this->container->getParameterBag()->all() as $key => $value) { foreach ($this->container->getParameterBag()->all() as $key => $value) {
if ($key !== $resolvedKey = $this->container->resolveEnvPlaceholders($key)) { if ($key !== $resolvedKey = $this->container->resolveEnvPlaceholders($key)) {
throw new InvalidArgumentException(sprintf('Parameter name cannot use env parameters: %s.', $resolvedKey)); throw new InvalidArgumentException(sprintf('Parameter name cannot use env parameters: %s.', $resolvedKey));
} }
if ($key !== $lcKey = strtolower($key)) {
$normalizedParams[] = sprintf(' %s => %s,', $this->export($lcKey), $this->export($key));
}
$export = $this->exportParameters(array($value)); $export = $this->exportParameters(array($value));
$export = explode('0 => ', substr(rtrim($export, " )\n"), 7, -1), 2); $export = explode('0 => ', substr(rtrim($export, " )\n"), 7, -1), 2);
@ -1082,7 +1086,7 @@ EOF;
public function getParameter($name) public function getParameter($name)
{ {
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
$name = strtolower($name); $name = $this->normalizeParameterName($name);
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
@ -1100,7 +1104,7 @@ EOF;
*/ */
public function hasParameter($name) public function hasParameter($name)
{ {
$name = strtolower($name); $name = $this->normalizeParameterName($name);
return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters);
} }
@ -1170,6 +1174,26 @@ EOF;
{$getDynamicParameter} {$getDynamicParameter}
} }
EOF;
$code .= ' private $normalizedParameterNames = '.($normalizedParams ? sprintf("array(\n%s\n );", implode("\n", $normalizedParams)) : 'array();')."\n";
$code .= <<<'EOF'
private function normalizeParameterName($name)
{
if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) {
$normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName;
if ((string) $name !== $normalizedName) {
@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);
}
} else {
$normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name;
}
return $normalizedName;
}
EOF; EOF;
} elseif ($dynamicPhp) { } elseif ($dynamicPhp) {
throw new RuntimeException('You cannot dump a not-frozen container with dynamic parameters.'); throw new RuntimeException('You cannot dump a not-frozen container with dynamic parameters.');
@ -1558,10 +1582,10 @@ EOF;
if (preg_match('/^%([^%]+)%$/', $value, $match)) { if (preg_match('/^%([^%]+)%$/', $value, $match)) {
// we do this to deal with non string values (Boolean, integer, ...) // we do this to deal with non string values (Boolean, integer, ...)
// the preg_replace_callback converts them to strings // the preg_replace_callback converts them to strings
return $this->dumpParameter(strtolower($match[1])); return $this->dumpParameter($match[1]);
} else { } else {
$replaceParameters = function ($match) { $replaceParameters = function ($match) {
return "'.".$this->dumpParameter(strtolower($match[2])).".'"; return "'.".$this->dumpParameter($match[2]).".'";
}; };
$code = str_replace('%%', '%', preg_replace_callback('/(?<!%)(%)([^%]+)\1/', $replaceParameters, $this->export($value))); $code = str_replace('%%', '%', preg_replace_callback('/(?<!%)(%)([^%]+)\1/', $replaceParameters, $this->export($value)));
@ -1607,8 +1631,6 @@ EOF;
*/ */
private function dumpParameter($name) private function dumpParameter($name)
{ {
$name = strtolower($name);
if ($this->container->isCompiled() && $this->container->hasParameter($name)) { if ($this->container->isCompiled() && $this->container->hasParameter($name)) {
$value = $this->container->getParameter($name); $value = $this->container->getParameter($name);
$dumpedValue = $this->dumpValue($value, false); $dumpedValue = $this->dumpValue($value, false);

View File

@ -486,11 +486,6 @@ class XmlFileLoader extends FileLoader
$key = array_pop($keys); $key = array_pop($keys);
} else { } else {
$key = $arg->getAttribute('key'); $key = $arg->getAttribute('key');
// parameter keys are case insensitive
if ('parameter' == $name && $lowercase) {
$key = strtolower($key);
}
} }
$onInvalid = $arg->getAttribute('on-invalid'); $onInvalid = $arg->getAttribute('on-invalid');

View File

@ -91,7 +91,7 @@ class EnvPlaceholderParameterBag extends ParameterBag
parent::resolve(); parent::resolve();
foreach ($this->envPlaceholders as $env => $placeholders) { foreach ($this->envPlaceholders as $env => $placeholders) {
if (!isset($this->parameters[$name = strtolower("env($env)")])) { if (!$this->has($name = "env($env)")) {
continue; continue;
} }
if (is_numeric($default = $this->parameters[$name])) { if (is_numeric($default = $this->parameters[$name])) {

View File

@ -25,6 +25,8 @@ class ParameterBag implements ParameterBagInterface
protected $parameters = array(); protected $parameters = array();
protected $resolved = false; protected $resolved = false;
private $normalizedNames = array();
/** /**
* @param array $parameters An array of parameters * @param array $parameters An array of parameters
*/ */
@ -49,7 +51,7 @@ class ParameterBag implements ParameterBagInterface
public function add(array $parameters) public function add(array $parameters)
{ {
foreach ($parameters as $key => $value) { foreach ($parameters as $key => $value) {
$this->parameters[strtolower($key)] = $value; $this->set($key, $value);
} }
} }
@ -66,7 +68,7 @@ class ParameterBag implements ParameterBagInterface
*/ */
public function get($name) public function get($name)
{ {
$name = strtolower($name); $name = $this->normalizeName($name);
if (!array_key_exists($name, $this->parameters)) { if (!array_key_exists($name, $this->parameters)) {
if (!$name) { if (!$name) {
@ -111,7 +113,7 @@ class ParameterBag implements ParameterBagInterface
*/ */
public function set($name, $value) public function set($name, $value)
{ {
$this->parameters[strtolower($name)] = $value; $this->parameters[$this->normalizeName($name)] = $value;
} }
/** /**
@ -119,7 +121,7 @@ class ParameterBag implements ParameterBagInterface
*/ */
public function has($name) public function has($name)
{ {
return array_key_exists(strtolower($name), $this->parameters); return array_key_exists($this->normalizeName($name), $this->parameters);
} }
/** /**
@ -129,7 +131,7 @@ class ParameterBag implements ParameterBagInterface
*/ */
public function remove($name) public function remove($name)
{ {
unset($this->parameters[strtolower($name)]); unset($this->parameters[$this->normalizeName($name)]);
} }
/** /**
@ -206,7 +208,7 @@ class ParameterBag implements ParameterBagInterface
// a non-string in a parameter value // a non-string in a parameter value
if (preg_match('/^%([^%\s]+)%$/', $value, $match)) { if (preg_match('/^%([^%\s]+)%$/', $value, $match)) {
$key = $match[1]; $key = $match[1];
$lcKey = strtolower($key); $lcKey = strtolower($key); // strtolower() to be removed in 4.0
if (isset($resolving[$lcKey])) { if (isset($resolving[$lcKey])) {
throw new ParameterCircularReferenceException(array_keys($resolving)); throw new ParameterCircularReferenceException(array_keys($resolving));
@ -224,7 +226,7 @@ class ParameterBag implements ParameterBagInterface
} }
$key = $match[1]; $key = $match[1];
$lcKey = strtolower($key); $lcKey = strtolower($key); // strtolower() to be removed in 4.0
if (isset($resolving[$lcKey])) { if (isset($resolving[$lcKey])) {
throw new ParameterCircularReferenceException(array_keys($resolving)); throw new ParameterCircularReferenceException(array_keys($resolving));
} }
@ -288,4 +290,18 @@ class ParameterBag implements ParameterBagInterface
return $value; return $value;
} }
private function normalizeName($name)
{
if (isset($this->normalizedNames[$normalizedName = strtolower($name)])) {
$normalizedName = $this->normalizedNames[$normalizedName];
if ((string) $name !== $normalizedName) {
@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);
}
} else {
$normalizedName = $this->normalizedNames[$normalizedName] = (string) $name;
}
return $normalizedName;
}
} }

View File

@ -1129,6 +1129,21 @@ class ContainerBuilderTest extends TestCase
$container->get('bar'); $container->get('bar');
} }
/**
* @group legacy
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "FOO" instead of "foo" is deprecated since version 3.4.
*/
public function testParameterWithMixedCase()
{
$container = new ContainerBuilder(new ParameterBag(array('foo' => 'bar')));
$container->register('foo', 'stdClass')
->setProperty('foo', '%FOO%');
$container->compile();
$this->assertSame('bar', $container->get('foo')->foo);
}
} }
class FooClass class FooClass

View File

@ -125,10 +125,6 @@ class ContainerTest extends TestCase
$sc->setParameter('foo', 'baz'); $sc->setParameter('foo', 'baz');
$this->assertEquals('baz', $sc->getParameter('foo'), '->setParameter() overrides previously set parameter'); $this->assertEquals('baz', $sc->getParameter('foo'), '->setParameter() overrides previously set parameter');
$sc->setParameter('Foo', 'baz1');
$this->assertEquals('baz1', $sc->getParameter('foo'), '->setParameter() converts the key to lowercase');
$this->assertEquals('baz1', $sc->getParameter('FOO'), '->getParameter() converts the key to lowercase');
try { try {
$sc->getParameter('baba'); $sc->getParameter('baba');
$this->fail('->getParameter() thrown an \InvalidArgumentException if the key does not exist'); $this->fail('->getParameter() thrown an \InvalidArgumentException if the key does not exist');
@ -138,6 +134,20 @@ class ContainerTest extends TestCase
} }
} }
/**
* @group legacy
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "Foo" instead of "foo" is deprecated since version 3.4.
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "FOO" instead of "foo" is deprecated since version 3.4.
*/
public function testGetSetParameterWithMixedCase()
{
$sc = new Container(new ParameterBag(array('foo' => 'bar')));
$sc->setParameter('Foo', 'baz1');
$this->assertEquals('baz1', $sc->getParameter('foo'), '->setParameter() converts the key to lowercase');
$this->assertEquals('baz1', $sc->getParameter('FOO'), '->getParameter() converts the key to lowercase');
}
public function testGetServiceIds() public function testGetServiceIds()
{ {
$sc = new Container(); $sc = new Container();

View File

@ -670,4 +670,43 @@ class PhpDumperTest extends TestCase
$container->get('bar'); $container->get('bar');
} }
/**
* @group legacy
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "foo" instead of "Foo" is deprecated since version 3.4.
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "FOO" instead of "Foo" is deprecated since version 3.4.
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "bar" instead of "BAR" is deprecated since version 3.4.
*/
public function testParameterWithMixedCase()
{
$container = new ContainerBuilder(new ParameterBag(array('Foo' => 'bar', 'BAR' => 'foo')));
$container->compile();
$dumper = new PhpDumper($container);
eval('?>'.$dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Parameter_With_Mixed_Case')));
$container = new \Symfony_DI_PhpDumper_Test_Parameter_With_Mixed_Case();
$this->assertSame('bar', $container->getParameter('foo'));
$this->assertSame('bar', $container->getParameter('FOO'));
$this->assertSame('foo', $container->getParameter('bar'));
$this->assertSame('foo', $container->getParameter('BAR'));
}
/**
* @group legacy
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "FOO" instead of "foo" is deprecated since version 3.4.
*/
public function testParameterWithLowerCase()
{
$container = new ContainerBuilder(new ParameterBag(array('foo' => 'bar')));
$container->compile();
$dumper = new PhpDumper($container);
eval('?>'.$dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Parameter_With_Lower_Case')));
$container = new \Symfony_DI_PhpDumper_Test_Parameter_With_Lower_Case();
$this->assertSame('bar', $container->getParameter('FOO'));
}
} }

View File

@ -4,7 +4,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
$container = new ContainerBuilder(new ParameterBag(array( $container = new ContainerBuilder(new ParameterBag(array(
'FOO' => '%baz%', 'foo' => '%baz%',
'baz' => 'bar', 'baz' => 'bar',
'bar' => 'foo is %%foo bar', 'bar' => 'foo is %%foo bar',
'escape' => '@escapeme', 'escape' => '@escapeme',

View File

@ -78,7 +78,7 @@ class ProjectServiceContainer extends Container
public function getParameter($name) public function getParameter($name)
{ {
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
$name = strtolower($name); $name = $this->normalizeParameterName($name);
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
@ -96,7 +96,7 @@ class ProjectServiceContainer extends Container
*/ */
public function hasParameter($name) public function hasParameter($name)
{ {
$name = strtolower($name); $name = $this->normalizeParameterName($name);
return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters);
} }
@ -142,6 +142,22 @@ class ProjectServiceContainer extends Container
throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name));
} }
private $normalizedParameterNames = array();
private function normalizeParameterName($name)
{
if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) {
$normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName;
if ((string) $name !== $normalizedName) {
@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);
}
} else {
$normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name;
}
return $normalizedName;
}
/** /**
* Gets the default parameters. * Gets the default parameters.
* *

View File

@ -82,7 +82,7 @@ class ProjectServiceContainer extends Container
public function getParameter($name) public function getParameter($name)
{ {
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
$name = strtolower($name); $name = $this->normalizeParameterName($name);
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
@ -100,7 +100,7 @@ class ProjectServiceContainer extends Container
*/ */
public function hasParameter($name) public function hasParameter($name)
{ {
$name = strtolower($name); $name = $this->normalizeParameterName($name);
return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters);
} }
@ -156,6 +156,22 @@ class ProjectServiceContainer extends Container
return $this->dynamicParameters[$name] = $value; return $this->dynamicParameters[$name] = $value;
} }
private $normalizedParameterNames = array();
private function normalizeParameterName($name)
{
if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) {
$normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName;
if ((string) $name !== $normalizedName) {
@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);
}
} else {
$normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name;
}
return $normalizedName;
}
/** /**
* Gets the default parameters. * Gets the default parameters.
* *

View File

@ -80,7 +80,7 @@ class ProjectServiceContainer extends Container
public function getParameter($name) public function getParameter($name)
{ {
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
$name = strtolower($name); $name = $this->normalizeParameterName($name);
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
@ -98,7 +98,7 @@ class ProjectServiceContainer extends Container
*/ */
public function hasParameter($name) public function hasParameter($name)
{ {
$name = strtolower($name); $name = $this->normalizeParameterName($name);
return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters);
} }
@ -152,6 +152,24 @@ class ProjectServiceContainer extends Container
return $this->dynamicParameters[$name] = $value; return $this->dynamicParameters[$name] = $value;
} }
private $normalizedParameterNames = array(
'env(foo)' => 'env(FOO)',
);
private function normalizeParameterName($name)
{
if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) {
$normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName;
if ((string) $name !== $normalizedName) {
@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);
}
} else {
$normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name;
}
return $normalizedName;
}
/** /**
* Gets the default parameters. * Gets the default parameters.
* *
@ -160,7 +178,7 @@ class ProjectServiceContainer extends Container
protected function getDefaultParameters() protected function getDefaultParameters()
{ {
return array( return array(
'env(foo)' => 'foo', 'env(FOO)' => 'foo',
); );
} }
} }

View File

@ -65,7 +65,7 @@ class ProjectServiceContainer extends Container
public function getParameter($name) public function getParameter($name)
{ {
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
$name = strtolower($name); $name = $this->normalizeParameterName($name);
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
@ -83,7 +83,7 @@ class ProjectServiceContainer extends Container
*/ */
public function hasParameter($name) public function hasParameter($name)
{ {
$name = strtolower($name); $name = $this->normalizeParameterName($name);
return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters);
} }
@ -129,6 +129,22 @@ class ProjectServiceContainer extends Container
throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name));
} }
private $normalizedParameterNames = array();
private function normalizeParameterName($name)
{
if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) {
$normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName;
if ((string) $name !== $normalizedName) {
@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);
}
} else {
$normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name;
}
return $normalizedName;
}
/** /**
* Gets the default parameters. * Gets the default parameters.
* *

View File

@ -338,7 +338,7 @@ class Container%s extends Container
public function getParameter($name) public function getParameter($name)
{ {
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
$name = strtolower($name); $name = $this->normalizeParameterName($name);
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
@ -356,7 +356,7 @@ class Container%s extends Container
*/ */
public function hasParameter($name) public function hasParameter($name)
{ {
$name = strtolower($name); $name = $this->normalizeParameterName($name);
return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters);
} }
@ -402,6 +402,22 @@ class Container%s extends Container
throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name));
} }
private $normalizedParameterNames = array();
private function normalizeParameterName($name)
{
if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) {
$normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName;
if ((string) $name !== $normalizedName) {
@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);
}
} else {
$normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name;
}
return $normalizedName;
}
/** /**
* Gets the default parameters. * Gets the default parameters.
* *

View File

@ -341,7 +341,7 @@ class ProjectServiceContainer extends Container
public function getParameter($name) public function getParameter($name)
{ {
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
$name = strtolower($name); $name = $this->normalizeParameterName($name);
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
@ -359,7 +359,7 @@ class ProjectServiceContainer extends Container
*/ */
public function hasParameter($name) public function hasParameter($name)
{ {
$name = strtolower($name); $name = $this->normalizeParameterName($name);
return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters);
} }
@ -405,6 +405,22 @@ class ProjectServiceContainer extends Container
throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name));
} }
private $normalizedParameterNames = array();
private function normalizeParameterName($name)
{
if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) {
$normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName;
if ((string) $name !== $normalizedName) {
@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);
}
} else {
$normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name;
}
return $normalizedName;
}
/** /**
* Gets the default parameters. * Gets the default parameters.
* *

View File

@ -86,7 +86,7 @@ class ProjectServiceContainer extends Container
public function getParameter($name) public function getParameter($name)
{ {
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
$name = strtolower($name); $name = $this->normalizeParameterName($name);
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
@ -104,7 +104,7 @@ class ProjectServiceContainer extends Container
*/ */
public function hasParameter($name) public function hasParameter($name)
{ {
$name = strtolower($name); $name = $this->normalizeParameterName($name);
return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters);
} }
@ -160,6 +160,22 @@ class ProjectServiceContainer extends Container
return $this->dynamicParameters[$name] = $value; return $this->dynamicParameters[$name] = $value;
} }
private $normalizedParameterNames = array();
private function normalizeParameterName($name)
{
if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) {
$normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName;
if ((string) $name !== $normalizedName) {
@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);
}
} else {
$normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name;
}
return $normalizedName;
}
/** /**
* Gets the default parameters. * Gets the default parameters.
* *

View File

@ -5,7 +5,7 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters> <parameters>
<parameter>a string</parameter> <parameter>a string</parameter>
<parameter key="FOO">bar</parameter> <parameter key="foo">bar</parameter>
<parameter key="values" type="collection"> <parameter key="values" type="collection">
<parameter>0</parameter> <parameter>0</parameter>
<parameter key="integer">4</parameter> <parameter key="integer">4</parameter>
@ -23,7 +23,7 @@
<parameter>bar</parameter> <parameter>bar</parameter>
</parameter> </parameter>
</parameter> </parameter>
<parameter key="MixedCase" type="collection"> <!-- Should be lower cased --> <parameter key="mixedcase" type="collection"> <!-- Should be lower cased -->
<parameter key="MixedCaseKey">value</parameter> <!-- Should stay mixed case --> <parameter key="MixedCaseKey">value</parameter> <!-- Should stay mixed case -->
</parameter> </parameter>
<parameter key="constant" type="constant">PHP_EOL</parameter> <parameter key="constant" type="constant">PHP_EOL</parameter>

View File

@ -1,5 +1,5 @@
parameters: parameters:
FOO: bar foo: bar
values: values:
- true - true
- false - false
@ -9,5 +9,5 @@ parameters:
bar: foo bar: foo
escape: '@@escapeme' escape: '@@escapeme'
foo_bar: '@foo_bar' foo_bar: '@foo_bar'
MixedCase: mixedcase:
MixedCaseKey: value MixedCaseKey: value

View File

@ -115,18 +115,18 @@ class EnvPlaceholderParameterBagTest extends TestCase
{ {
$bag = new EnvPlaceholderParameterBag(); $bag = new EnvPlaceholderParameterBag();
$bag->get('env(INT_VAR)'); $bag->get('env(INT_VAR)');
$bag->set('env(Int_Var)', 2); $bag->set('env(INT_VAR)', 2);
$bag->resolve(); $bag->resolve();
$this->assertSame('2', $bag->all()['env(int_var)']); $this->assertSame('2', $bag->all()['env(INT_VAR)']);
} }
public function testResolveEnvAllowsNull() public function testResolveEnvAllowsNull()
{ {
$bag = new EnvPlaceholderParameterBag(); $bag = new EnvPlaceholderParameterBag();
$bag->get('env(NULL_VAR)'); $bag->get('env(NULL_VAR)');
$bag->set('env(Null_Var)', null); $bag->set('env(NULL_VAR)', null);
$bag->resolve(); $bag->resolve();
$this->assertNull($bag->all()['env(null_var)']); $this->assertNull($bag->all()['env(NULL_VAR)']);
} }
/** /**
@ -137,7 +137,7 @@ class EnvPlaceholderParameterBagTest extends TestCase
{ {
$bag = new EnvPlaceholderParameterBag(); $bag = new EnvPlaceholderParameterBag();
$bag->get('env(ARRAY_VAR)'); $bag->get('env(ARRAY_VAR)');
$bag->set('env(Array_Var)', array()); $bag->set('env(ARRAY_VAR)', array());
$bag->resolve(); $bag->resolve();
} }
@ -148,7 +148,7 @@ class EnvPlaceholderParameterBagTest extends TestCase
$bag->get('env(NULL_VAR)'); $bag->get('env(NULL_VAR)');
$bag->resolve(); $bag->resolve();
$this->assertNull($bag->all()['env(null_var)']); $this->assertNull($bag->all()['env(NULL_VAR)']);
} }
/** /**

View File

@ -46,8 +46,6 @@ class ParameterBagTest extends TestCase
)); ));
$bag->remove('foo'); $bag->remove('foo');
$this->assertEquals(array('bar' => 'bar'), $bag->all(), '->remove() removes a parameter'); $this->assertEquals(array('bar' => 'bar'), $bag->all(), '->remove() removes a parameter');
$bag->remove('BAR');
$this->assertEquals(array(), $bag->all(), '->remove() converts key to lowercase before removing');
} }
public function testGetSet() public function testGetSet()
@ -59,10 +57,6 @@ class ParameterBagTest extends TestCase
$bag->set('foo', 'baz'); $bag->set('foo', 'baz');
$this->assertEquals('baz', $bag->get('foo'), '->set() overrides previously set parameter'); $this->assertEquals('baz', $bag->get('foo'), '->set() overrides previously set parameter');
$bag->set('Foo', 'baz1');
$this->assertEquals('baz1', $bag->get('foo'), '->set() converts the key to lowercase');
$this->assertEquals('baz1', $bag->get('FOO'), '->get() converts the key to lowercase');
try { try {
$bag->get('baba'); $bag->get('baba');
$this->fail('->get() throws an Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException if the key does not exist'); $this->fail('->get() throws an Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException if the key does not exist');
@ -109,10 +103,33 @@ class ParameterBagTest extends TestCase
{ {
$bag = new ParameterBag(array('foo' => 'bar')); $bag = new ParameterBag(array('foo' => 'bar'));
$this->assertTrue($bag->has('foo'), '->has() returns true if a parameter is defined'); $this->assertTrue($bag->has('foo'), '->has() returns true if a parameter is defined');
$this->assertTrue($bag->has('Foo'), '->has() converts the key to lowercase');
$this->assertFalse($bag->has('bar'), '->has() returns false if a parameter is not defined'); $this->assertFalse($bag->has('bar'), '->has() returns false if a parameter is not defined');
} }
/**
* @group legacy
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "BAR" instead of "bar" is deprecated since version 3.4.
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "Foo" instead of "foo" is deprecated since version 3.4.
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "FOO" instead of "foo" is deprecated since version 3.4.
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "Foo" instead of "foo" is deprecated since version 3.4.
*/
public function testMixedCase()
{
$bag = new ParameterBag(array(
'foo' => 'foo',
'bar' => 'bar',
));
$bag->remove('BAR');
$this->assertEquals(array('foo' => 'foo'), $bag->all(), '->remove() converts key to lowercase before removing');
$bag->set('Foo', 'baz1');
$this->assertEquals('baz1', $bag->get('foo'), '->set() converts the key to lowercase');
$this->assertEquals('baz1', $bag->get('FOO'), '->get() converts the key to lowercase');
$this->assertTrue($bag->has('Foo'), '->has() converts the key to lowercase');
}
public function testResolveValue() public function testResolveValue()
{ {
$bag = new ParameterBag(array()); $bag = new ParameterBag(array());