Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions UPGRADE-7.4.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Config

* Deprecate accessing the internal scope of the loader in PHP config files, use only its public API instead
* Deprecate setting a default value to a node that is required, and vice versa
* Deprecate generating fluent methods in config builders

Console
-------
Expand All @@ -40,6 +41,15 @@ DependencyInjection
* Deprecate `ExtensionInterface::getXsdValidationBasePath()` and `getNamespace()`;
bundles that need to support older versions of Symfony can keep the methods
but need to add the `@deprecated` annotation on them
* Deprecate the fluent PHP format for semantic configuration, instantiate builders inline with the config array as argument and return them instead:
```diff
-return function (AcmeConfig $config) {
- $config->color('red');
-}
+return new AcmeConfig([
+ 'color' => 'red',
+]);
```

DoctrineBridge
--------------
Expand Down
3 changes: 2 additions & 1 deletion src/Symfony/Component/Config/Builder/ClassBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public function __construct(
private string $namespace,
string $name,
private NodeInterface $node,
public readonly bool $isRoot = false,
) {
$this->name = ucfirst($this->camelCase($name)).'Config';
}
Expand Down Expand Up @@ -73,7 +74,7 @@ public function build(): string
$use .= \sprintf('use %s;', $statement)."\n";
}

$implements = [] === $this->implements ? '' : 'implements '.implode(', ', $this->implements);
$implements = $this->implements ? 'implements '.implode(', ', $this->implements) : '';
$body = '';
foreach ($this->properties as $property) {
$body .= ' '.$property->getContent()."\n";
Expand Down
84 changes: 59 additions & 25 deletions src/Symfony/Component/Config/Builder/ConfigBuilderGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public function build(ConfigurationInterface $configuration): \Closure
$this->classes = [];

$rootNode = $configuration->getConfigTreeBuilder()->buildTree();
$rootClass = new ClassBuilder('Symfony\\Config', $rootNode->getName(), $rootNode);
$rootClass = new ClassBuilder('Symfony\\Config', $rootNode->getName(), $rootNode, true);

$path = $this->getFullPath($rootClass);
if (!is_file($path)) {
Expand All @@ -68,7 +68,7 @@ public function NAME(): string
$this->writeClasses();
}

return function () use ($path, $rootClass) {
return static function () use ($path, $rootClass) {
require_once $path;
$className = $rootClass->getFqcn();

Expand All @@ -94,6 +94,9 @@ private function writeClasses(): void
if ($class->getProperties()) {
$class->addProperty('_usedProperties', null, '[]');
}
if ($class->isRoot) {
$class->addProperty('_hasDeprecatedCalls', null, 'false');
}
$this->buildSetExtraKey($class);

file_put_contents($this->getFullPath($class), $class->build());
Expand Down Expand Up @@ -134,10 +137,13 @@ private function handleArrayNode(ArrayNode $node, ClassBuilder $class, string $n
if ($acceptScalar) {
$comment = \sprintf(" * @template TValue of %s\n * @param TValue \$value\n%s", $paramType, $comment);
$comment .= \sprintf(' * @return %s|$this'."\n", $childClass->getFqcn());
$comment .= \sprintf(' * @psalm-return (TValue is array ? %s : static)'."\n ", $childClass->getFqcn());
$comment .= \sprintf(' * @psalm-return (TValue is array ? %s : static)'."\n", $childClass->getFqcn());
}
if ($class->isRoot) {
$comment .= " * @deprecated since Symfony 7.4\n";
}
if ('' !== $comment) {
$comment = "/**\n$comment*/\n";
$comment = "/**\n$comment */\n";
}

$property = $class->addProperty(
Expand All @@ -146,7 +152,7 @@ private function handleArrayNode(ArrayNode $node, ClassBuilder $class, string $n
);
$body = $acceptScalar ? '
COMMENTpublic function NAME(PARAM_TYPE $value = []): CLASS|static
{
{DEPRECATED_BODY
if (!\is_array($value)) {
$this->_usedProperties[\'PROPERTY\'] = true;
$this->PROPERTY = $value;
Expand All @@ -164,7 +170,7 @@ private function handleArrayNode(ArrayNode $node, ClassBuilder $class, string $n
return $this->PROPERTY;
}' : '
COMMENTpublic function NAME(array $value = []): CLASS
{
{DEPRECATED_BODY
if (null === $this->PROPERTY) {
$this->_usedProperties[\'PROPERTY\'] = true;
$this->PROPERTY = new CLASS($value);
Expand All @@ -176,6 +182,7 @@ private function handleArrayNode(ArrayNode $node, ClassBuilder $class, string $n
}';
$class->addUse(InvalidConfigurationException::class);
$class->addMethod($node->getName(), $body, [
'DEPRECATED_BODY' => $class->isRoot ? "\n \$this->_hasDeprecatedCalls = true;" : '',
'COMMENT' => $comment,
'PROPERTY' => $property->getName(),
'CLASS' => $childClass->getFqcn(),
Expand All @@ -195,15 +202,17 @@ private function handleVariableNode(VariableNode $node, ClassBuilder $class): vo
/**
COMMENT *
* @return $this
*/
*DEPRECATED_ANNOTATION/
public function NAME(mixed $valueDEFAULT): static
{
{DEPRECATED_BODY
$this->_usedProperties[\'PROPERTY\'] = true;
$this->PROPERTY = $value;

return $this;
}';
$class->addMethod($node->getName(), $body, [
'DEPRECATED_BODY' => $class->isRoot ? "\n \$this->_hasDeprecatedCalls = true;" : '',
'DEPRECATED_ANNOTATION' => $class->isRoot ? " @deprecated since Symfony 7.4\n *" : '',
'PROPERTY' => $property->getName(),
'COMMENT' => $comment,
'DEFAULT' => $node->hasDefaultValue() ? ' = '.var_export($node->getDefaultValue(), true) : '',
Expand Down Expand Up @@ -232,16 +241,18 @@ private function handlePrototypedArrayNode(PrototypedArrayNode $node, ClassBuild
* @param ParamConfigurator|list<ParamConfigurator|PROTOTYPE_TYPE>EXTRA_TYPE $value
*
* @return $this
*/
*DEPRECATED_ANNOTATION/
public function NAME(PARAM_TYPE $value): static
{
{DEPRECATED_BODY
$this->_usedProperties[\'PROPERTY\'] = true;
$this->PROPERTY = $value;

return $this;
}';

$class->addMethod($node->getName(), $body, [
'DEPRECATED_BODY' => $class->isRoot ? "\n \$this->_hasDeprecatedCalls = true;" : '',
'DEPRECATED_ANNOTATION' => $class->isRoot ? " @deprecated since Symfony 7.4\n *" : '',
'PROPERTY' => $property->getName(),
'PROTOTYPE_TYPE' => implode('|', $prototypeParameterTypes),
'EXTRA_TYPE' => $nodeTypesWithoutArray ? '|'.implode('|', $nodeTypesWithoutArray) : '',
Expand All @@ -251,16 +262,18 @@ public function NAME(PARAM_TYPE $value): static
$body = '
/**
* @return $this
*/
*DEPRECATED_ANNOTATION/
public function NAME(string $VAR, TYPE $VALUE): static
{
{DEPRECATED_BODY
$this->_usedProperties[\'PROPERTY\'] = true;
$this->PROPERTY[$VAR] = $VALUE;

return $this;
}';

$class->addMethod($methodName, $body, [
'DEPRECATED_BODY' => $class->isRoot ? "\n \$this->_hasDeprecatedCalls = true;" : '',
'DEPRECATED_ANNOTATION' => $class->isRoot ? " @deprecated since Symfony 7.4\n *" : '',
'PROPERTY' => $property->getName(),
'TYPE' => ['mixed'] !== $prototypeParameterTypes ? 'ParamConfigurator|'.implode('|', $prototypeParameterTypes) : 'mixed',
'VAR' => '' === $key ? 'key' : $key,
Expand Down Expand Up @@ -290,16 +303,19 @@ public function NAME(string $VAR, TYPE $VALUE): static
if ($acceptScalar) {
$comment = \sprintf(" * @template TValue of %s\n * @param TValue \$value\n%s", $paramType, $comment);
$comment .= \sprintf(' * @return %s|$this'."\n", $childClass->getFqcn());
$comment .= \sprintf(' * @psalm-return (TValue is array ? %s : static)'."\n ", $childClass->getFqcn());
$comment .= \sprintf(' * @psalm-return (TValue is array ? %s : static)'."\n", $childClass->getFqcn());
}
if ($class->isRoot) {
$comment .= " * @deprecated since Symfony 7.4\n";
}
if ('' !== $comment) {
$comment = "/**\n$comment*/\n";
$comment = "/**\n$comment */\n";
}

if ($noKey) {
$body = $acceptScalar ? '
COMMENTpublic function NAME(PARAM_TYPE $value = []): CLASS|static
{
{DEPRECATED_BODY
$this->_usedProperties[\'PROPERTY\'] = true;
if (!\is_array($value)) {
$this->PROPERTY[] = $value;
Expand All @@ -310,12 +326,13 @@ public function NAME(string $VAR, TYPE $VALUE): static
return $this->PROPERTY[] = new CLASS($value);
}' : '
COMMENTpublic function NAME(array $value = []): CLASS
{
{DEPRECATED_BODY
$this->_usedProperties[\'PROPERTY\'] = true;

return $this->PROPERTY[] = new CLASS($value);
}';
$class->addMethod($methodName, $body, [
'DEPRECATED_BODY' => $class->isRoot ? "\n \$this->_hasDeprecatedCalls = true;" : '',
'COMMENT' => $comment,
'PROPERTY' => $property->getName(),
'CLASS' => $childClass->getFqcn(),
Expand All @@ -324,7 +341,7 @@ public function NAME(string $VAR, TYPE $VALUE): static
} else {
$body = $acceptScalar ? '
COMMENTpublic function NAME(string $VAR, PARAM_TYPE $VALUE = []): CLASS|static
{
{DEPRECATED_BODY
if (!\is_array($VALUE)) {
$this->_usedProperties[\'PROPERTY\'] = true;
$this->PROPERTY[$VAR] = $VALUE;
Expand All @@ -342,7 +359,7 @@ public function NAME(string $VAR, TYPE $VALUE): static
return $this->PROPERTY[$VAR];
}' : '
COMMENTpublic function NAME(string $VAR, array $VALUE = []): CLASS
{
{DEPRECATED_BODY
if (!isset($this->PROPERTY[$VAR])) {
$this->_usedProperties[\'PROPERTY\'] = true;
$this->PROPERTY[$VAR] = new CLASS($VALUE);
Expand All @@ -354,7 +371,9 @@ public function NAME(string $VAR, TYPE $VALUE): static
}';
$class->addUse(InvalidConfigurationException::class);
$class->addMethod($methodName, str_replace('$value', '$VAR', $body), [
'COMMENT' => $comment, 'PROPERTY' => $property->getName(),
'DEPRECATED_BODY' => $class->isRoot ? "\n \$this->_hasDeprecatedCalls = true;" : '',
'COMMENT' => $comment,
'PROPERTY' => $property->getName(),
'CLASS' => $childClass->getFqcn(),
'VAR' => '' === $key ? 'key' : $key,
'VALUE' => 'value' === $key ? 'data' : 'value',
Expand All @@ -374,16 +393,21 @@ private function handleScalarNode(ScalarNode $node, ClassBuilder $class): void
$body = '
/**
COMMENT * @return $this
*/
*DEPRECATED_ANNOTATION/
public function NAME($value): static
{
{DEPRECATED_BODY
$this->_usedProperties[\'PROPERTY\'] = true;
$this->PROPERTY = $value;

return $this;
}';

$class->addMethod($node->getName(), $body, ['PROPERTY' => $property->getName(), 'COMMENT' => $comment]);
$class->addMethod($node->getName(), $body, [
'DEPRECATED_BODY' => $class->isRoot ? "\n \$this->_hasDeprecatedCalls = true;" : '',
'DEPRECATED_ANNOTATION' => $class->isRoot ? " @deprecated since Symfony 7.4\n *" : '',
'PROPERTY' => $property->getName(),
'COMMENT' => $comment,
]);
}

private function getParameterTypes(NodeInterface $node): array
Expand Down Expand Up @@ -509,6 +533,13 @@ private function buildToArray(ClassBuilder $class): void

$extraKeys = $class->shouldAllowExtraKeys() ? ' + $this->_extraKeys' : '';

if ($class->isRoot) {
$body .= "
if (\$this->_hasDeprecatedCalls) {
trigger_deprecation('symfony/config', '7.4', 'Calling any fluent method on \"%s\" is deprecated; pass the configuration to the constructor instead.', \$this::class);
}";
}

$class->addMethod('toArray', '
public function NAME(): array
{
Expand Down Expand Up @@ -583,13 +614,16 @@ private function buildSetExtraKey(ClassBuilder $class): void
* @param ParamConfigurator|mixed $value
*
* @return $this
*/
*DEPRECATED_ANNOTATION/
public function NAME(string $key, mixed $value): static
{
{DEPRECATED_BODY
$this->_extraKeys[$key] = $value;

return $this;
}');
}', [
'DEPRECATED_BODY' => $class->isRoot ? "\n \$this->_hasDeprecatedCalls = true;" : '',
'DEPRECATED_ANNOTATION' => $class->isRoot ? " @deprecated since Symfony 7.4\n *" : '',
]);
}

private function getSubNamespace(ClassBuilder $rootClass): string
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/Config/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ CHANGELOG
* Add array-shapes to generated config builders
* Deprecate accessing the internal scope of the loader in PHP config files, use only its public API instead
* Deprecate setting a default value to a node that is required, and vice versa
* Deprecate generating fluent methods in config builders

7.3
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,35 @@

use Symfony\Config\AddToListConfig;

return static function (AddToListConfig $config) {
$config->translator()->fallbacks(['sv', 'fr', 'es']);
$config->translator()->source('\\Acme\\Foo', 'yellow');
$config->translator()->source('\\Acme\\Bar', 'green');

$config->messenger([
return new AddToListConfig([
'translator' => [
'fallbacks' => ['sv', 'fr', 'es'],
'sources' => [
'\\Acme\\Foo' => 'yellow',
'\\Acme\\Bar' => 'green',
],
],
'messenger' => [
'routing' => [
'Foo\\MyArrayMessage' => [
'senders' => ['workqueue'],
],
'Foo\\Message' => [
'senders' => ['workqueue'],
],
'Foo\\DoubleMessage' => [
'senders' => ['sync', 'workqueue'],
],
],
]);
$config->messenger()
->routing('Foo\\Message')->senders(['workqueue']);
$config->messenger()
->routing('Foo\\DoubleMessage')->senders(['sync', 'workqueue']);

$config->messenger()->receiving()
->color('blue')
->priority(10);
$config->messenger()->receiving()
->color('red')
->priority(5);
};
'receiving' => [
[
'color' => 'blue',
'priority' => 10,
],
[
'color' => 'red',
'priority' => 5,
],
],
],
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

use Symfony\Config\AddToListConfig;

return static function (AddToListConfig $config) {
$config->translator()->fallbacks(['sv', 'fr', 'es']);
$config->translator()->source('\\Acme\\Foo', 'yellow');
$config->translator()->source('\\Acme\\Bar', 'green');

$config->messenger([
'routing' => [
'Foo\\MyArrayMessage' => [
'senders' => ['workqueue'],
],
],
]);
$config->messenger()
->routing('Foo\\Message')->senders(['workqueue']);
$config->messenger()
->routing('Foo\\DoubleMessage')->senders(['sync', 'workqueue']);

$config->messenger()->receiving()
->color('blue')
->priority(10);
$config->messenger()->receiving()
->color('red')
->priority(5);
};
Loading
Loading