Skip to content

Commit 957f908

Browse files
committed
Introducing container non-empty parameters
1 parent 6c100c9 commit 957f908

File tree

15 files changed

+517
-8
lines changed

15 files changed

+517
-8
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ public function load(array $configs, ContainerBuilder $container): void
307307
if (isset($config['secret'])) {
308308
$container->setParameter('kernel.secret', $config['secret']);
309309
}
310+
$container->setNonEmptyParameter('kernel.secret', 'A non-empty value for the parameter "kernel.secret" is required. Did you forget to configure the "framework.secret" option?');
310311

311312
$container->setParameter('kernel.http_method_override', $config['http_method_override']);
312313
$container->setParameter('kernel.trust_x_sendfile_type_header', $config['trust_x_sendfile_type_header']);

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"ext-xml": "*",
2222
"symfony/cache": "^6.4|^7.0",
2323
"symfony/config": "^6.4|^7.0",
24-
"symfony/dependency-injection": "^7.1",
24+
"symfony/dependency-injection": "^7.2",
2525
"symfony/deprecation-contracts": "^2.5|^3",
2626
"symfony/error-handler": "^6.4|^7.0",
2727
"symfony/event-dispatcher": "^6.4|^7.0",

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
7.2
5+
---
6+
7+
* Enable non-empty parameters with `ParameterBag::setNonEmpty()` and `ContainerBuilder::setNonEmptyParameter()` methods
8+
49
7.1
510
---
611

src/Symfony/Component/DependencyInjection/Container.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ public function compile(): void
8686

8787
$this->parameterBag = new FrozenParameterBag(
8888
$this->parameterBag->all(),
89-
$this->parameterBag instanceof ParameterBag ? $this->parameterBag->allDeprecated() : []
89+
$this->parameterBag instanceof ParameterBag ? $this->parameterBag->allDeprecated() : [],
90+
$this->parameterBag instanceof ParameterBag ? $this->parameterBag->allNonEmpty() : [],
9091
);
9192

9293
$this->compiled = true;

src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,10 @@ public function merge(self $container): void
622622
foreach ($otherBag->allDeprecated() as $name => $deprecated) {
623623
$parameterBag->deprecate($name, ...$deprecated);
624624
}
625+
626+
foreach ($otherBag->allNonEmpty() as $name => $message) {
627+
$parameterBag->setNonEmpty($name, $message);
628+
}
625629
}
626630

627631
if ($this->trackResources) {
@@ -715,6 +719,15 @@ public function deprecateParameter(string $name, string $package, string $versio
715719
$this->parameterBag->deprecate($name, $package, $version, $message);
716720
}
717721

722+
public function setNonEmptyParameter(string $name, string $message = 'A non-empty value for the parameter "%s" is required.'): void
723+
{
724+
if (!$this->parameterBag instanceof ParameterBag) {
725+
throw new BadMethodCallException(\sprintf('The parameter bag must be an instance of "%s" to call "%s".', ParameterBag::class, __METHOD__));
726+
}
727+
728+
$this->parameterBag->setNonEmpty($name, $message);
729+
}
730+
718731
/**
719732
* Compiles the container.
720733
*

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

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,13 +1260,17 @@ class $class extends $baseClass
12601260
{
12611261
private const DEPRECATED_PARAMETERS = [];
12621262
1263+
private const NONEMPTY_PARAMETERS = [];
1264+
12631265
protected \$parameters = [];
12641266
12651267
public function __construct()
12661268
{
12671269
12681270
EOF;
12691271
$code = str_replace(" private const DEPRECATED_PARAMETERS = [];\n\n", $this->addDeprecatedParameters(), $code);
1272+
$code = str_replace(" private const NONEMPTY_PARAMETERS = [];\n\n", $this->addNonEmptyParameters(), $code);
1273+
12701274
if ($this->asFiles) {
12711275
$code = str_replace('__construct()', '__construct(private array $buildParameters = [], protected string $containerDir = __DIR__)', $code);
12721276

@@ -1431,6 +1435,24 @@ private function addDeprecatedParameters(): string
14311435
return " private const DEPRECATED_PARAMETERS = [\n{$code} ];\n\n";
14321436
}
14331437

1438+
private function addNonEmptyParameters(): string
1439+
{
1440+
if (!($bag = $this->container->getParameterBag()) instanceof ParameterBag) {
1441+
return '';
1442+
}
1443+
1444+
if (!$nonEmpty = $bag->allNonEmpty()) {
1445+
return '';
1446+
}
1447+
$code = '';
1448+
ksort($nonEmpty);
1449+
foreach ($nonEmpty as $param => $message) {
1450+
$code .= ' '.$this->doExport($param).' => '.$this->doExport($message).",\n";
1451+
}
1452+
1453+
return " private const NONEMPTY_PARAMETERS = [\n{$code} ];\n\n";
1454+
}
1455+
14341456
private function addMethodMap(): string
14351457
{
14361458
$code = '';
@@ -1565,14 +1587,16 @@ private function addInlineRequires(bool $hasProxyClasses): string
15651587

15661588
private function addDefaultParametersMethod(): string
15671589
{
1568-
if (!$this->container->getParameterBag()->all()) {
1590+
$bag = $this->container->getParameterBag();
1591+
1592+
if (!$bag->all() && (!$bag instanceof ParameterBag || !$bag->allNonEmpty())) {
15691593
return '';
15701594
}
15711595

15721596
$php = [];
15731597
$dynamicPhp = [];
15741598

1575-
foreach ($this->container->getParameterBag()->all() as $key => $value) {
1599+
foreach ($bag->all() as $key => $value) {
15761600
if ($key !== $resolvedKey = $this->container->resolveEnvPlaceholders($key)) {
15771601
throw new InvalidArgumentException(\sprintf('Parameter name cannot use env parameters: "%s".', $resolvedKey));
15781602
}
@@ -1602,12 +1626,16 @@ public function getParameter(string $name): array|bool|string|int|float|\UnitEnu
16021626
}
16031627
16041628
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || \array_key_exists($name, $this->parameters))) {
1605-
throw new ParameterNotFoundException($name);
1629+
throw new ParameterNotFoundException($name, extraMessage: self::NONEMPTY_PARAMETERS[$name] ?? null);
16061630
}
16071631
if (isset($this->loadedDynamicParameters[$name])) {
16081632
return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name);
16091633
}
16101634
1635+
if (isset(self::NONEMPTY_PARAMETERS[$name]) && (null === $this->parameters[$name] || '' === $this->parameters[$name])) {
1636+
throw new \Symfony\Component\DependencyInjection\Exception\EmptyParameterValueException(self::NONEMPTY_PARAMETERS[$name]);
1637+
}
1638+
16111639
return $this->parameters[$name];
16121640
}
16131641
@@ -1635,7 +1663,7 @@ public function getParameterBag(): ParameterBagInterface
16351663
foreach ($this->buildParameters as $name => $value) {
16361664
$parameters[$name] = $value;
16371665
}
1638-
$this->parameterBag = new FrozenParameterBag($parameters, self::DEPRECATED_PARAMETERS);
1666+
$this->parameterBag = new FrozenParameterBag($parameters, self::DEPRECATED_PARAMETERS, nonEmptyParameters: self::NONEMPTY_PARAMETERS);
16391667
}
16401668
16411669
return $this->parameterBag;
@@ -1647,11 +1675,17 @@ public function getParameterBag(): ParameterBagInterface
16471675
$code = preg_replace('/^.*buildParameters.*\n.*\n.*\n\n?/m', '', $code);
16481676
}
16491677

1650-
if (!($bag = $this->container->getParameterBag()) instanceof ParameterBag || !$bag->allDeprecated()) {
1678+
if (!$bag instanceof ParameterBag || !$bag->allDeprecated()) {
16511679
$code = preg_replace("/\n.*DEPRECATED_PARAMETERS.*\n.*\n.*\n/m", '', $code, 1);
16521680
$code = str_replace(', self::DEPRECATED_PARAMETERS', '', $code);
16531681
}
16541682

1683+
if (!$bag instanceof ParameterBag || !$bag->allNonEmpty()) {
1684+
$code = str_replace(', extraMessage: self::NONEMPTY_PARAMETERS[$name] ?? null', '', $code);
1685+
$code = str_replace(', nonEmptyParameters: self::NONEMPTY_PARAMETERS', '', $code);
1686+
$code = preg_replace("/\n.*NONEMPTY_PARAMETERS.*\n.*\n.*\n/m", '', $code, 1);
1687+
}
1688+
16551689
if ($dynamicPhp) {
16561690
$loadedDynamicParameters = $this->exportParameters(array_combine(array_keys($dynamicPhp), array_fill(0, \count($dynamicPhp), false)), '', 8);
16571691
$getDynamicParameter = <<<'EOF'
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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\Exception;
13+
14+
use Psr\Container\NotFoundExceptionInterface;
15+
16+
/**
17+
* This exception is thrown when an existent parameter with an empty value is used.
18+
*
19+
* @author Yonel Ceruto <open@yceruto.dev>
20+
*/
21+
class EmptyParameterValueException extends InvalidArgumentException implements NotFoundExceptionInterface
22+
{
23+
}

src/Symfony/Component/DependencyInjection/Exception/ParameterNotFoundException.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public function __construct(
3636
private array $alternatives = [],
3737
private ?string $nonNestedAlternative = null,
3838
private ?string $sourceExtensionName = null,
39+
private ?string $extraMessage = null,
3940
) {
4041
parent::__construct('', 0, $previous);
4142

@@ -66,6 +67,10 @@ public function updateRepr(): void
6667
} elseif (null !== $this->nonNestedAlternative) {
6768
$this->message .= ' You cannot access nested array items, do you want to inject "'.$this->nonNestedAlternative.'" instead?';
6869
}
70+
71+
if ($this->extraMessage) {
72+
$this->message .= ' '.$this->extraMessage;
73+
}
6974
}
7075

7176
public function getKey(): string
@@ -103,4 +108,16 @@ public function setSourceExtensionName(?string $sourceExtensionName): void
103108

104109
$this->updateRepr();
105110
}
111+
112+
public function getExtraMessage(): ?string
113+
{
114+
return $this->extraMessage;
115+
}
116+
117+
public function setExtraMessage(?string $extraMessage): void
118+
{
119+
$this->extraMessage = $extraMessage;
120+
121+
$this->updateRepr();
122+
}
106123
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class FrozenParameterBag extends ParameterBag
2929
public function __construct(
3030
array $parameters = [],
3131
protected array $deprecatedParameters = [],
32+
protected array $nonEmptyParameters = [],
3233
) {
3334
$this->parameters = $parameters;
3435
$this->resolved = true;
@@ -54,6 +55,11 @@ public function deprecate(string $name, string $package, string $version, string
5455
throw new LogicException('Impossible to call deprecate() on a frozen ParameterBag.');
5556
}
5657

58+
public function setNonEmpty(string $name, string $message = 'A non-empty parameter "%s" is required.'): never
59+
{
60+
throw new LogicException('Impossible to call setNonEmpty() on a frozen ParameterBag.');
61+
}
62+
5763
public function remove(string $name): never
5864
{
5965
throw new LogicException('Impossible to call remove() on a frozen ParameterBag.');

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\DependencyInjection\ParameterBag;
1313

1414
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
15+
use Symfony\Component\DependencyInjection\Exception\EmptyParameterValueException;
1516
use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
1617
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
1718
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
@@ -26,6 +27,7 @@ class ParameterBag implements ParameterBagInterface
2627
protected array $parameters = [];
2728
protected bool $resolved = false;
2829
protected array $deprecatedParameters = [];
30+
protected array $nonEmptyParameters = [];
2931

3032
public function __construct(array $parameters = [])
3133
{
@@ -54,13 +56,22 @@ public function allDeprecated(): array
5456
return $this->deprecatedParameters;
5557
}
5658

59+
public function allNonEmpty(): array
60+
{
61+
return $this->nonEmptyParameters;
62+
}
63+
5764
public function get(string $name): array|bool|string|int|float|\UnitEnum|null
5865
{
5966
if (!\array_key_exists($name, $this->parameters)) {
6067
if (!$name) {
6168
throw new ParameterNotFoundException($name);
6269
}
6370

71+
if (\array_key_exists($name, $this->nonEmptyParameters)) {
72+
throw new ParameterNotFoundException($name, extraMessage: $this->nonEmptyParameters[$name]);
73+
}
74+
6475
$alternatives = [];
6576
foreach ($this->parameters as $key => $parameterValue) {
6677
$lev = levenshtein($name, $key);
@@ -92,6 +103,10 @@ public function get(string $name): array|bool|string|int|float|\UnitEnum|null
92103
trigger_deprecation(...$this->deprecatedParameters[$name]);
93104
}
94105

106+
if (\array_key_exists($name, $this->nonEmptyParameters) && (null === $this->parameters[$name] || '' === $this->parameters[$name])) {
107+
throw new EmptyParameterValueException($this->nonEmptyParameters[$name]);
108+
}
109+
95110
return $this->parameters[$name];
96111
}
97112

@@ -118,14 +133,19 @@ public function deprecate(string $name, string $package, string $version, string
118133
$this->deprecatedParameters[$name] = [$package, $version, $message, $name];
119134
}
120135

136+
public function setNonEmpty(string $name, string $message = 'A non-empty value for the parameter "%s" is required.'): void
137+
{
138+
$this->nonEmptyParameters[$name] = sprintf($message, $name);
139+
}
140+
121141
public function has(string $name): bool
122142
{
123143
return \array_key_exists($name, $this->parameters);
124144
}
125145

126146
public function remove(string $name): void
127147
{
128-
unset($this->parameters[$name], $this->deprecatedParameters[$name]);
148+
unset($this->parameters[$name], $this->deprecatedParameters[$name], $this->nonEmptyParameters[$name]);
129149
}
130150

131151
public function resolve(): void

0 commit comments

Comments
 (0)