8000 [DependencyInjection] Enable deprecating parameters · symfony/symfony@0f0a2fb · GitHub
[go: up one dir, main page]

Skip to content

Commit 0f0a2fb

Browse files
HeahDudechalasr
authored andcommitted
[DependencyInjection] Enable deprecating parameters
1 parent 4adb375 commit 0f0a2fb

18 files changed

+671
-40
lines changed

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ CHANGELOG
1010
* Add support for nesting autowiring-related attributes into `#[Autowire(...)]`
1111
* Deprecate undefined and numeric keys with `service_locator` config
1212
* Fail if Target attribute does not exist during compilation
13+
* Enable deprecating parameters with `ContainerBuilder::deprecateParameter()`
1314

1415
6.2
1516
---

src/Symfony/Component/DependencyInjection/Container.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
2323
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
2424
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
25+
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
2526
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
2627
use Symfony\Contracts\Service\ResetInterface;
2728

@@ -82,7 +83,10 @@ public function compile()
8283
{
8384
$this->parameterBag->resolve();
8485

85-
$this->parameterBag = new FrozenParameterBag($this->parameterBag->all());
86+
$this->parameterBag = new FrozenParameterBag(
87+
$this->parameterBag->all(),
88+
$this->parameterBag instanceof ParameterBag ? $this->parameterBag->allDeprecated() : []
89+
);
8690

8791
$this->compiled = true;
8892
}

src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
use Symfony\Component\DependencyInjection\Exception\BadMethodCallException;
3535
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
3636
use Symfony\Component\DependencyInjection\Exception\LogicException;
37+
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
3738
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
3839
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
3940
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
@@ -610,7 +611,15 @@ public function merge(self $container)
610611
}
611612
}
612613
$this->addAliases($container->getAliases());
613-
$this->getParameterBag()->add($container->getParameterBag()->all());
614+
$parameterBag = $this->getParameterBag();
615+
$otherBag = $container->getParameterBag();
616+
$parameterBag->add($otherBag->all());
617+
618+
if ($parameterBag instanceof ParameterBag && $otherBag instanceof ParameterBag) {
619+
foreach ($otherBag->allDeprecated() as $name => $deprecated) {
620+
$parameterBag->deprecate($name, ...$deprecated);
621+
}
622+
}
614623

615624
if ($this->trackResources) {
616625
foreach ($container->getResources() as $resource) {
@@ -626,9 +635,9 @@ public function merge(self $container)
626635
$this->extensionConfigs[$name] = array_merge($this->extensionConfigs[$name], $container->getExtensionConfig($name));
627636
}
628637

629-
if ($this->getParameterBag() instanceof EnvPlaceholderParameterBag && $container->getParameterBag() instanceof EnvPlaceholderParameterBag) {
630-
$envPlaceholders = $container->getParameterBag()->getEnvPlaceholders();
631-
$this->getParameterBag()->mergeEnvPlaceholders($container->getParameterBag());
638+
if ($parameterBag instanceof EnvPlaceholderParameterBag && $otherBag instanceof EnvPlaceholderParameterBag) {
639+
$envPlaceholders = $otherBag->getEnvPlaceholders();
640+
$parameterBag->mergeEnvPlaceholders($otherBag);
632641
} else {
633642
$envPlaceholders = [];
634643
}
@@ -689,6 +698,20 @@ public function prependExtensionConfig(string $name, array $config)
689698
array_unshift($this->extensionConfigs[$name], $config);
690699
}
691700

701+
/**
702+
* Deprecates a service container parameter.
703+
*
704+
* @throws ParameterNotFoundException if the parameter is not defined
705+
*/
706+
public function deprecateParameter(string $name, string $package, string $version, string $message = 'The parameter "%s" is deprecated.'): void
707+
{
708+
if (!$this->parameterBag instanceof ParameterBag) {
709+
throw new BadMethodCallException(sprintf('The parameter bag must be an instance of "%s" to call "%s".', ParameterBag::class, __METHOD__));
710+
}
711+
712+
$this->parameterBag->deprecate($name, $package, $version, $message);
713+
}
714+
692715
/**
693716
* Compiles the container.
694717
*

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

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper;
3636
use Symfony\Component\DependencyInjection\Loader\FileLoader;
3737
use Symfony\Component\DependencyInjection\Parameter;
38+
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
3839
use Symfony\Component\DependencyInjection\Reference;
3940
use Symfony\Component\DependencyInjection\ServiceLocator as BaseServiceLocator;
4041
use Symfony\Component\DependencyInjection\TypedReference;
@@ -1234,6 +1235,8 @@ private function startClass(string $class, string $baseClass, bool $hasProxyClas
12341235
*/
12351236
class $class extends $baseClass
12361237
{
1238+
private const DEPRECATED_PARAMETERS = [];
1239+
12371240
protected \$parameters = [];
12381241
protected readonly \WeakReference \$ref;
12391242
@@ -1242,11 +1245,9 @@ public function __construct()
12421245
\$this->ref = \WeakReference::create(\$this);
12431246
12441247
EOF;
1248+
$code = str_replace(" private const DEPRECATED_PARAMETERS = [];\n\n", $this->addDeprecatedParameters(), $code);
12451249
if ($this->asFiles) {
1246-
$code = str_replace('$parameters = []', "\$containerDir;\n protected \$parameters = [];\n private \$buildParameters", $code);
1247-
$code = str_replace('__construct()', '__construct(array $buildParameters = [], $containerDir = __DIR__)', $code);
1248-
$code .= " \$this->buildParameters = \$buildParameters;\n";
1249-
$code .= " \$this->containerDir = \$containerDir;\n";
1250+
$code = str_replace('__construct()', '__construct(private array $buildParameters = [], protected string $containerDir = __DIR__)', $code);
12501251

12511252
if (null !== $this->targetDirRegex) {
12521253
$code = str_replace('$parameters = []', "\$targetDir;\n protected \$parameters = []", $code);
@@ -1391,6 +1392,24 @@ public function getRemovedIds(): array
13911392
EOF;
13921393
}
13931394

1395+
private function addDeprecatedParameters(): string
1396+
{
1397+
if (!($bag = $this->container->getParameterBag()) instanceof ParameterBag) {
1398+
return '';
1399+
}
1400+
1401+
if (!$deprecated = $bag->allDeprecated()) {
1402+
return '';
1403+
}
1404+
$code = '';
1405+
ksort($deprecated);
1406+
foreach ($deprecated as $param => $deprecation) {
1407+
$code .= ' '.$this->doExport($param).' => ['.implode(', ', array_map($this->doExport(...), $deprecation))."],\n";
1408+
}
1409+
1410+
return " private const DEPRECATED_PARAMETERS = [\n{$code} ];\n\n";
1411+
}
1412+
13941413
private function addMethodMap(): string
13951414
{
13961415
$code = '';
@@ -1552,6 +1571,10 @@ private function addDefaultParametersMethod(): string
15521571
15531572
public function getParameter(string $name): array|bool|string|int|float|\UnitEnum|null
15541573
{
1574+
if (isset(self::DEPRECATED_PARAMETERS[$name])) {
1575+
trigger_deprecation(...self::DEPRECATED_PARAMETERS[$name]);
1576+
}
1577+
15551578
if (isset($this->buildParameters[$name])) {
15561579
return $this->buildParameters[$name];
15571580
}
@@ -1590,17 +1613,23 @@ public function getParameterBag(): ParameterBagInterface
15901613
foreach ($this->buildParameters as $name => $value) {
15911614
$parameters[$name] = $value;
15921615
}
1593-
$this->parameterBag = new FrozenParameterBag($parameters);
1616+
$this->parameterBag = new FrozenParameterBag($parameters, self::DEPRECATED_PARAMETERS);
15941617
}
15951618
15961619
return $this->parameterBag;
15971620
}
15981621

15991622
EOF;
1623+
16001624
if (!$this->asFiles) {
16011625
$code = preg_replace('/^.*buildParameters.*\n.*\n.*\n\n?/m', '', $code);
16021626
}
16031627

1628+
if (!($bag = $this->container->getParameterBag()) instanceof ParameterBag || !$bag->allDeprecated()) {
1629+
$code = preg_replace("/\n.*DEPRECATED_PARAMETERS.*\n.*\n.*\n/m", '', $code, 1);
1630+
$code = str_replace(', self::DEPRECATED_PARAMETERS', '', $code);
1631+
}
1632+
16041633
if ($dynamicPhp) {
16051634
$loadedDynamicParameters = $this->exportParameters(array_combine(array_keys($dynamicPhp), array_fill(0, \count($dynamicPhp), false)), '', 8);
16061635
$getDynamicParameter = <<<'EOF'

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ class FrozenParameterBag extends ParameterBag
2525
* all keys are already lowercased.
2626
*
2727
* This is always the case when used internally.
28-
*
29-
* @param array $parameters An array of parameters
3028
*/
31-
public function __construct(array $parameters = [])
32-
{
29+
public function __construct(
30+
array $parameters = [],
31+
protected array $deprecatedParameters = [],
32+
) {
3333
$this->parameters = $parameters;
3434
$this->resolved = true;
3535
}
@@ -49,6 +49,11 @@ public function set(string $name, array|bool|string|int|float|\UnitEnum|null $va
4949
throw new LogicException('Impossible to call set() on a frozen ParameterBag.');
5050
}
5151

52+
public function deprecate(string $name, string $package, string $version, string $message = 'The parameter "%s" is deprecated.')
53+
{
54+
throw new LogicException('Impossible to call deprecate() on a frozen ParameterBag.');
55+
}
56+
5257
public function remove(string $name)
5358
{
5459
throw new LogicException('Impossible to call remove() on a frozen ParameterBag.');

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class ParameterBag implements ParameterBagInterface
2424
{
2525
protected $parameters = [];
2626
protected $resolved = false;
27+
protected array $deprecatedParameters = [];
2728

2829
public function __construct(array $parameters = [])
2930
{
@@ -47,6 +48,11 @@ public function all(): array
4748
return $this->parameters;
4849
}
4950

51+
public function allDeprecated(): array
52+
{
53+
return $this->deprecatedParameters;
54+
}
55+
5056
public function get(string $name): array|bool|string|int|float|\UnitEnum|null
5157
{
5258
if (!\array_key_exists($name, $this->parameters)) {
@@ -81,6 +87,10 @@ public function get(string $name): array|bool|string|int|float|\UnitEnum|null
8187
throw new ParameterNotFoundException($name, null, null, null, $alternatives, $nonNestedAlternative);
8288
}
8389

90+
if (isset($this->deprecatedParameters[$name])) {
91+
trigger_deprecation(...$this->deprecatedParameters[$name]);
92+
}
93+
8494
return $this->parameters[$name];
8595
}
8696

@@ -95,14 +105,28 @@ public function set(string $name, array|bool|string|int|float|\UnitEnum|null $va
95105
$this->parameters[$name] = $value;
96106
}
97107

108+
/**
109+
* Deprecates a service container parameter.
110+
*
111+
* @throws ParameterNotFoundException if the parameter is not defined
112+
*/
113+
public function deprecate(string $name, string $package, string $version, string $message = 'The parameter "%s" is deprecated.')
114+
{
115+
if (!\array_key_exists($name, $this->parameters)) {
116+
throw new ParameterNotFoundException($name);
117+
}
118+
119+
$this->deprecatedParameters[$name] = [$package, $version, $message, $name];
120+
}
121+
98122
public function has(string $name): bool
99123
{
100124
return \array_key_exists($name, $this->parameters);
101125
}
102126

103127
public function remove(string $name)
104128
{
105-
unset($this->parameters[$name]);
129+
unset($this->parameters[$name], $this->deprecatedParameters[$name]);
106130
}
107131

108132
public function resolve()

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

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@
3131
use Symfony\Component\DependencyInjection\ContainerBuilder;
3232
use Symfony\Component\DependencyInjection\ContainerInterface;
3333
use Symfony\Component\DependencyInjection\Definition;
34+
use Symfony\Component\DependencyInjection\Exception\BadMethodCallException;
3435
use Symfony\Component\DependencyInjection\Exception\EnvNotFoundException;
3536
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
3637
use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
38+
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
3739
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
3840
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
3941
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
@@ -42,6 +44,7 @@
4244
use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
4345
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
4446
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
47+
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
4548
use Symfony\Component\DependencyInjection\Reference;
4649
use Symfony\Component\DependencyInjection\ServiceLocator;
4750
use Symfony\Component\DependencyInjection\Tests\Compiler\Foo;
@@ -100,6 +103,109 @@ public function testDefinitions()
100103
}
101104
}
102105

106+
/**
107+
* The test should be kept in the group as it always expects a deprecation.
108+
*
109+
* @group legacy
110+
*/
111+
public function testDeprecateParameter()
112+
{
113+
$builder = new ContainerBuilder();
114+
$builder->setParameter('foo', 'bar');
115+
116+
$builder->deprecateParameter('foo', 'symfony/test', '6.3');
117+
118+
$this->expectDeprecation('Since symfony/test 6.3: The parameter "foo" is deprecated.');
119+
120+
$builder->getParameter('foo');
121+
}
122+
123+
/**
124+
* The test should be kept in the group as it always expects a deprecation.
125+
*
126+
* @group legacy
127+
*/
128+
public function testParameterDeprecationIsTrgiggeredWhenCompiled()
129+
{
130+
$builder = new ContainerBuilder();
131+
$builder->setParameter('foo', '%bar%');
132+
$builder->setParameter('bar', 'baz');
133+
134+
$builder->deprecateParameter('bar', 'symfony/test', '6.3');
135+
136+
$this->expectDeprecation('Since symfony/test 6.3: The parameter "bar" is deprecated.');
137+
138+
$builder->compile();
139+
}
140+
141+
public function testDeprecateParameterThrowsWhenParameterIsUndefined()
142+
{
143+
$builder = new ContainerBuilder();
144+
145+
$this->expectException(ParameterNotFoundException::class);
146+
$this->expectExceptionMessage('You have requested a non-existent parameter "foo".');
147+
148+
$builder->deprecateParameter('foo', 'symfony/test', '6.3');
149+
}
150+
151+
public function testDeprecateParameterThrowsWhenParameterBagIsNotInternal()
152+
{
153+
$builder = new ContainerBuilder(new class() implements ParameterBagInterface {
154+
public function clear()
155+
{
156+
}
157+
158+
public function add(array $parameters)
159+
{
160+
}
161+
162+
public function all(): array
163+
{
164+
return [];
165+
}
166+
167+
public function get(string $name): array|bool|string|int|float|\UnitEnum|null
168+
{
169+
return null;
170+
}
171+
172+
public function remove(string $name)
173+
{
174+
}
175+
176+
public function set(string $name, \UnitEnum|float|int|bool|array|string|null $value)
177+
{
178+
}
179+
180+
public function has(string $name): bool
181+
{
182+
return false;
183+
}
184+
185+
public function resolve()
186+
{
187+
}
188+
189+
public function resolveValue(mixed $value)
190+
{
191+
}
192+
193+
public function escapeValue(mixed $value): mixed
194+
{
195+
return null;
196+
}
197+
198+
public function unescapeValue(mixed $value): mixed
199+
{
200+
return null;
201+
}
202+
});
203+
204+
$this->expectException(BadMethodCallException::class);
205+
206+
$builder->deprecateParameter('foo', 'symfony/test', '6.3');
207+
}
208+
103209
public function testRegister()
104210
{
105211
$builder = new ContainerBuilder();

0 commit comments

Comments
 (0)
0