N°8910 - Upgrade Symfony packages (#811)

This commit is contained in:
Benjamin Dalsass
2026-02-23 06:54:26 +01:00
committed by GitHub
parent b91e6c384a
commit 4853ca444e
224 changed files with 4758 additions and 1778 deletions

View File

@@ -6,6 +6,7 @@ CHANGELOG
* Add `HttpClientAssertionsTrait`
* Add `AbstractController::renderBlock()` and `renderBlockView()`
* Remove call to `renderView()` in `AbstractController::render()`
* Add native return type to `Translator` and to `Application::reset()`
* Deprecate the integration of Doctrine annotations, either uninstall the `doctrine/annotations` package or disable the integration by setting `framework.annotations` to `false`
* Enable `json_decode_detailed_errors` context for Serializer by default if `kernel.debug` is true and the `seld/jsonlint` package is installed

View File

@@ -53,14 +53,21 @@ EOF
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$exitCode = Command::SUCCESS;
foreach ($this->pools as $name => $pool) {
$io->comment(\sprintf('Pruning cache pool: <info>%s</info>', $name));
$pool->prune();
if (!$pool->prune()) {
$io->error(\sprintf('Cache pool "%s" could not be pruned.', $name));
$exitCode = Command::FAILURE;
}
}
$io->success('Successfully pruned cache pool(s).');
if (Command::SUCCESS === $exitCode) {
$io->success('Successfully pruned cache pool(s).');
}
return 0;
return $exitCode;
}
}

View File

@@ -161,7 +161,7 @@ EOF
$steps = explode('.', $path);
foreach ($steps as $step) {
if (!\array_key_exists($step, $config)) {
if (!\is_array($config) || !\array_key_exists($step, $config)) {
throw new LogicException(\sprintf('Unable to find configuration for "%s.%s".', $alias, $path));
}

View File

@@ -61,14 +61,13 @@ EOF
}
foreach ($this->vault->list(true) as $name => $value) {
$localValue = $this->localVault->reveal($name);
if (null === $localValue = $this->localVault->reveal($name)) {
continue;
}
if (null !== $localValue && $value !== $localValue) {
if ($value !== $localValue) {
$this->vault->seal($name, $localValue);
} elseif (null !== $message = $this->localVault->getLastMessage()) {
$io->error($message);
return 1;
$io->note($this->vault->getLastMessage());
}
}

View File

@@ -157,6 +157,10 @@ abstract class AbstractController implements ServiceSubscriberInterface
return new JsonResponse($json, $status, $headers, true);
}
if (null === $data) {
return new JsonResponse('null', $status, $headers, true);
}
return new JsonResponse($data, $status, $headers);
}

View File

@@ -34,7 +34,10 @@ class TestServiceContainerWeakRefPass implements CompilerPassInterface
$definitions = $container->getDefinitions();
foreach ($definitions as $id => $definition) {
if ($id && '.' !== $id[0] && (!$definition->isPublic() || $definition->isPrivate() || $definition->hasTag('container.private')) && !$definition->hasErrors() && !$definition->isAbstract()) {
if ($inner = $definition->getTag('container.decorator')[0]['inner'] ?? null) {
$privateServices[$inner] = new Reference($inner, ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE);
}
if ($id && '.' !== $id[0] && ($definition->isPrivate() || $definition->hasTag('container.private')) && !$definition->hasErrors() && !$definition->isAbstract()) {
$privateServices[$id] = new Reference($id, ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE);
}
}

View File

@@ -358,7 +358,7 @@ class Configuration implements ConfigurationInterface
->arrayNode('workflows')
->canBeEnabled()
->beforeNormalization()
->always(function ($v) {
->always(static function ($v) {
if (\is_array($v) && true === $v['enabled']) {
$workflows = $v;
unset($workflows['enabled']);
@@ -367,7 +367,7 @@ class Configuration implements ConfigurationInterface
$workflows = [];
}
if (1 === \count($workflows) && isset($workflows['workflows']) && !array_is_list($workflows['workflows']) && array_diff(array_keys($workflows['workflows']), ['audit_trail', 'type', 'marking_store', 'supports', 'support_strategy', 'initial_marking', 'places', 'transitions'])) {
if (1 === \count($workflows) && isset($workflows['workflows']) && !array_is_list($workflows['workflows']) && array_diff_key($workflows['workflows'], ['audit_trail' => 1, 'type' => 1, 'marking_store' => 1, 'supports' => 1, 'support_strategy' => 1, 'initial_marking' => 1, 'places' => 1, 'transitions' => 1])) {
$workflows = $workflows['workflows'];
}
@@ -473,27 +473,16 @@ class Configuration implements ConfigurationInterface
throw new InvalidConfigurationException('The "places" option must be an array in workflow configuration.');
}
// It's an indexed array of shape ['place1', 'place2']
if (isset($places[0]) && \is_string($places[0])) {
return array_map(function (string $place) {
return ['name' => $place];
}, $places);
}
// It's an indexed array, we let the validation occur
if (isset($places[0]) && \is_array($places[0])) {
return $places;
}
foreach ($places as $name => $place) {
if (\is_array($place) && \array_key_exists('name', $place)) {
continue;
$normalizedPlaces = [];
foreach ($places as $key => $value) {
if (!\is_array($value)) {
$value = ['name' => $value];
}
$place['name'] = $name;
$places[$name] = $place;
$value['name'] ??= $key;
$normalizedPlaces[] = $value;
}
return array_values($places);
return $normalizedPlaces;
})
->end()
->isRequired()
@@ -516,26 +505,26 @@ class Configuration implements ConfigurationInterface
->end()
->arrayNode('transitions')
->beforeNormalization()
->always()
->then(function ($transitions) {
->always(static function ($transitions) {
if (!\is_array($transitions)) {
throw new InvalidConfigurationException('The "transitions" option must be an array in workflow configuration.');
}
// It's an indexed array, we let the validation occur
if (isset($transitions[0]) && \is_array($transitions[0])) {
return $transitions;
}
foreach ($transitions as $name => $transition) {
if (\is_array($transition) && \array_key_exists('name', $transition)) {
continue;
$normalizedTransitions = [];
foreach ($transitions as $key => $transition) {
if (\is_array($transition)) {
if (\is_string($key = $transition['key'] ?? $key)) {
$transition['name'] ??= $key;
}
if (!($transition['name'] ?? false)) {
throw new InvalidConfigurationException('The "name" option is required for each transition in workflow configuration.');
}
unset($transition['key']);
}
$transition['name'] = $name;
$transitions[$name] = $transition;
$normalizedTransitions[$key] = $transition;
}
return $transitions;
return $normalizedTransitions;
})
->end()
->isRequired()
@@ -552,6 +541,7 @@ class Configuration implements ConfigurationInterface
->example('is_fully_authenticated() and is_granted(\'ROLE_JOURNALIST\') and subject.getTitle() == \'My first article\'')
->end()
->arrayNode('from')
->performNoDeepMerging()
->beforeNormalization()
->ifString()
->then(fn ($v) => [$v])
@@ -562,6 +552,7 @@ class Configuration implements ConfigurationInterface
->end()
->end()
->arrayNode('to')
->performNoDeepMerging()
->beforeNormalization()
->ifString()
->then(fn ($v) => [$v])
@@ -1866,6 +1857,7 @@ class Configuration implements ConfigurationInterface
->end()
->arrayNode('vars')
->info('Associative array: the default vars used to expand the templated URI.')
->useAttributeAsKey('name')
->normalizeKeys(false)
->variablePrototype()->end()
->end()
@@ -1946,6 +1938,7 @@ class Configuration implements ConfigurationInterface
->end()
->arrayNode('extra')
->info('Extra options for specific HTTP client')
->useAttributeAsKey('name')
->normalizeKeys(false)
->variablePrototype()->end()
->end()
@@ -2097,6 +2090,7 @@ class Configuration implements ConfigurationInterface
->end()
->arrayNode('extra')
->info('Extra options for specific HTTP client')
->useAttributeAsKey('name')
->normalizeKeys(false)
->variablePrototype()->end()
->end()

View File

@@ -163,6 +163,7 @@ use Symfony\Component\Serializer\Encoder\EncoderInterface;
use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader;
use Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader;
use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader;
use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\Serializer;
@@ -920,11 +921,11 @@ class FrameworkExtension extends Extension
$container->getDefinition('profiler_listener')
->addArgument($config['collect_parameter']);
if (!$container->getParameter('kernel.debug') || !class_exists(CliRequest::class) || !$container->has('debug.stopwatch')) {
if (!$container->getParameter('kernel.debug') || !$this->hasConsole() || !$container->has('debug.stopwatch') || !class_exists(CliRequest::class)) {
$container->removeDefinition('console_profiler_listener');
}
if (!class_exists(CommandDataCollector::class)) {
if (!$this->hasConsole() || !class_exists(CommandDataCollector::class)) {
$container->removeDefinition('.data_collector.command');
}
}
@@ -972,16 +973,16 @@ class FrameworkExtension extends Extension
$transitionCounter = 0;
foreach ($workflow['transitions'] as $transition) {
if ('workflow' === $type) {
$transitionDefinition = new Definition(Workflow\Transition::class, [$transition['name'], $transition['from'], $transition['to']]);
$transitionId = \sprintf('.%s.transition.%s', $workflowId, $transitionCounter++);
$container->setDefinition($transitionId, $transitionDefinition);
$container->register($transitionId, Workflow\Transition::class)
->setArguments([$transition['name'], $transition['from'], $transition['to']]);
$transitions[] = new Reference($transitionId);
if (isset($transition['guard'])) {
$configuration = new Definition(Workflow\EventListener\GuardExpression::class);
$configuration->addArgument(new Reference($transitionId));
$configuration->addArgument($transition['guard']);
$eventName = \sprintf('workflow.%s.guard.%s', $name, $transition['name']);
$guardsConfiguration[$eventName][] = $configuration;
$guardsConfiguration[$eventName][] = new Definition(
Workflow\EventListener\GuardExpression::class,
[new Reference($transitionId), $transition['guard']]
);
}
if ($transition['metadata']) {
$transitionsMetadataDefinition->addMethodCall('offsetSet', [
@@ -992,16 +993,16 @@ class FrameworkExtension extends Extension
} elseif ('state_machine' === $type) {
foreach ($transition['from'] as $from) {
foreach ($transition['to'] as $to) {
$transitionDefinition = new Definition(Workflow\Transition::class, [$transition['name'], $from, $to]);
$transitionId = \sprintf('.%s.transition.%s', $workflowId, $transitionCounter++);
$container->setDefinition($transitionId, $transitionDefinition);
$container->register($transitionId, Workflow\Transition::class)
->setArguments([$transition['name'], $from, $to]);
$transitions[] = new Reference($transitionId);
if (isset($transition['guard'])) {
$configuration = new Definition(Workflow\EventListener\GuardExpression::class);
$configuration->addArgument(new Reference($transitionId));
$configuration->addArgument($transition['guard']);
$eventName = \sprintf('workflow.%s.guard.%s', $name, $transition['name']);
$guardsConfiguration[$eventName][] = $configuration;
$guardsConfiguration[$eventName][] = new Definition(
Workflow\EventListener\GuardExpression::class,
[new Reference($transitionId), $transition['guard']]
);
}
if ($transition['metadata']) {
$transitionsMetadataDefinition->addMethodCall('offsetSet', [
@@ -1622,11 +1623,11 @@ class FrameworkExtension extends Extension
foreach ($config['providers'] as $provider) {
if ($provider['locales']) {
$locales += $provider['locales'];
$locales = array_merge($locales, $provider['locales']);
}
}
$locales = array_unique($locales);
$locales = array_values(array_unique($locales));
$container->getDefinition('console.command.translation_pull')
->replaceArgument(4, array_merge($transPaths, [$config['default_path']]))
@@ -1954,7 +1955,7 @@ class FrameworkExtension extends Extension
if (isset($config['enable_attributes']) && $config['enable_attributes']) {
$annotationLoader = new Definition(
AttributeLoader::class,
[new Reference('annotation_reader', ContainerInterface::NULL_ON_INVALID_REFERENCE)]
interface_exists(CacheableSupportsMethodInterface::class) ? [new Reference('annotation_reader', ContainerInterface::NULL_ON_INVALID_REFERENCE)] : [],
);
$serializerLoaders[] = $annotationLoader;

View File

@@ -471,7 +471,8 @@
<xsd:element name="metadata" type="metadata" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="guard" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="key" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="place" mixed="true">

View File

@@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Contracts\Service\ResetInterface;
@@ -82,6 +83,18 @@ abstract class KernelTestCase extends TestCase
static::$kernel = $kernel;
static::$booted = true;
// If the cache warmer is registered, it means that the cache has been
// warmed up, so the current container is not fresh anymore. Let's
// reboot a fresh one.
if (self::getContainer()->initialized('cache_warmer')) {
static::ensureKernelShutdown();
$kernel = static::createKernel($options);
$kernel->boot();
static::$kernel = $kernel;
static::$booted = true;
}
return static::$kernel;
}
@@ -135,6 +148,11 @@ abstract class KernelTestCase extends TestCase
static::$kernel->boot();
$container = static::$kernel->getContainer();
$httpCacheDir = null;
if ($container->has('http_cache')) {
$httpCacheDir = static::$kernel->getCacheDir().'/http_cache';
}
if ($container->has('services_resetter')) {
// Instantiate the service because Container::reset() only resets services that have been used
$container->get('services_resetter');
@@ -146,6 +164,10 @@ abstract class KernelTestCase extends TestCase
if ($container instanceof ResetInterface) {
$container->reset();
}
if (null !== $httpCacheDir && is_dir($httpCacheDir)) {
(new Filesystem())->remove($httpCacheDir);
}
}
}
}

View File

@@ -71,15 +71,11 @@ class TestContainer extends Container
$container = $this->getPublicContainer();
$renamedId = $this->renamedIds[$id] ?? $id;
try {
if (!$this->getPrivateContainer()->has($renamedId)) {
$container->set($renamedId, $service);
} catch (InvalidArgumentException $e) {
if (!str_starts_with($e->getMessage(), "The \"$renamedId\" service is private")) {
throw $e;
}
if (isset($container->privates[$renamedId])) {
throw new InvalidArgumentException(\sprintf('The "%s" service is already initialized, you cannot replace it.', $id));
}
} elseif (isset($container->privates[$renamedId])) {
throw new InvalidArgumentException(\sprintf('The "%s" service is already initialized, you cannot replace it.', $id));
} else {
$container->privates[$renamedId] = $service;
}
}