migration symfony 5 4 (#300)

* symfony 5.4 (diff dev)

* symfony 5.4 (working)

* symfony 5.4 (update autoload)

* symfony 5.4 (remove swiftmailer mailer implementation)

* symfony 5.4 (php doc and split Global accessor class)


### Impacted packages:

composer require php:">=7.2.5 <8.0.0" symfony/console:5.4.* symfony/dotenv:5.4.* symfony/framework-bundle:5.4.* symfony/twig-bundle:5.4.* symfony/yaml:5.4.* --update-with-dependencies

composer require symfony/stopwatch:5.4.* symfony/web-profiler-bundle:5.4.* --dev --update-with-dependencies
This commit is contained in:
bdalsass
2022-06-16 09:13:24 +02:00
committed by GitHub
parent abb13b70b9
commit 79da71ecf8
2178 changed files with 87439 additions and 59451 deletions

View File

@@ -12,9 +12,10 @@
namespace Symfony\Component\HttpKernel\DependencyInjection;
use Composer\Autoload\ClassLoader;
use Symfony\Component\Debug\DebugClassLoader;
use Symfony\Component\Debug\DebugClassLoader as LegacyDebugClassLoader;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\ErrorHandler\DebugClassLoader;
use Symfony\Component\HttpKernel\Kernel;
/**
@@ -36,23 +37,17 @@ class AddAnnotatedClassesToCachePass implements CompilerPassInterface
*/
public function process(ContainerBuilder $container)
{
$classes = [];
$annotatedClasses = [];
foreach ($container->getExtensions() as $extension) {
if ($extension instanceof Extension) {
if (\PHP_VERSION_ID < 70000) {
$classes = array_merge($classes, $extension->getClassesToCompile());
}
$annotatedClasses = array_merge($annotatedClasses, $extension->getAnnotatedClassesToCompile());
$annotatedClasses[] = $extension->getAnnotatedClassesToCompile();
}
}
$annotatedClasses = array_merge($this->kernel->getAnnotatedClassesToCompile(), ...$annotatedClasses);
$existingClasses = $this->getClassesInComposerClassMaps();
if (\PHP_VERSION_ID < 70000) {
$classes = $container->getParameterBag()->resolveValue($classes);
$this->kernel->setClassCache($this->expandClasses($classes, $existingClasses));
}
$annotatedClasses = $container->getParameterBag()->resolveValue($annotatedClasses);
$this->kernel->setAnnotatedClassCache($this->expandClasses($annotatedClasses, $existingClasses));
}
@@ -62,16 +57,14 @@ class AddAnnotatedClassesToCachePass implements CompilerPassInterface
*
* @param array $patterns The class patterns to expand
* @param array $classes The existing classes to match against the patterns
*
* @return array A list of classes derived from the patterns
*/
private function expandClasses(array $patterns, array $classes)
private function expandClasses(array $patterns, array $classes): array
{
$expanded = [];
// Explicit classes declared in the patterns are returned directly
foreach ($patterns as $key => $pattern) {
if ('\\' !== substr($pattern, -1) && false === strpos($pattern, '*')) {
if (!str_ends_with($pattern, '\\') && !str_contains($pattern, '*')) {
unset($patterns[$key]);
$expanded[] = ltrim($pattern, '\\');
}
@@ -91,7 +84,7 @@ class AddAnnotatedClassesToCachePass implements CompilerPassInterface
return array_unique($expanded);
}
private function getClassesInComposerClassMaps()
private function getClassesInComposerClassMaps(): array
{
$classes = [];
@@ -100,7 +93,7 @@ class AddAnnotatedClassesToCachePass implements CompilerPassInterface
continue;
}
if ($function[0] instanceof DebugClassLoader) {
if ($function[0] instanceof DebugClassLoader || $function[0] instanceof LegacyDebugClassLoader) {
$function = $function[0]->getClassLoader();
}
@@ -112,7 +105,7 @@ class AddAnnotatedClassesToCachePass implements CompilerPassInterface
return array_keys($classes);
}
private function patternsToRegexps($patterns)
private function patternsToRegexps(array $patterns): array
{
$regexps = [];
@@ -134,12 +127,12 @@ class AddAnnotatedClassesToCachePass implements CompilerPassInterface
return $regexps;
}
private function matchAnyRegexps($class, $regexps)
private function matchAnyRegexps(string $class, array $regexps): bool
{
$isTest = false !== strpos($class, 'Test');
$isTest = str_contains($class, 'Test');
foreach ($regexps as $regex) {
if ($isTest && false === strpos($regex, 'Test')) {
if ($isTest && !str_contains($regex, 'Test')) {
continue;
}

View File

@@ -1,25 +0,0 @@
<?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.
*/
namespace Symfony\Component\HttpKernel\DependencyInjection;
@trigger_error('The '.__NAMESPACE__.'\AddClassesToCachePass class is deprecated since Symfony 3.3 and will be removed in 4.0.', \E_USER_DEPRECATED);
/**
* Sets the classes to compile in the cache for the container.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since version 3.3, to be removed in 4.0.
*/
class AddClassesToCachePass extends AddAnnotatedClassesToCachePass
{
}

View File

@@ -15,6 +15,9 @@ use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver;
use Symfony\Component\Stopwatch\Stopwatch;
/**
* Gathers and configures the argument value resolvers.
@@ -27,11 +30,17 @@ class ControllerArgumentValueResolverPass implements CompilerPassInterface
private $argumentResolverService;
private $argumentValueResolverTag;
private $traceableResolverStopwatch;
public function __construct($argumentResolverService = 'argument_resolver', $argumentValueResolverTag = 'controller.argument_value_resolver')
public function __construct(string $argumentResolverService = 'argument_resolver', string $argumentValueResolverTag = 'controller.argument_value_resolver', string $traceableResolverStopwatch = 'debug.stopwatch')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->argumentResolverService = $argumentResolverService;
$this->argumentValueResolverTag = $argumentValueResolverTag;
$this->traceableResolverStopwatch = $traceableResolverStopwatch;
}
public function process(ContainerBuilder $container)
@@ -40,9 +49,20 @@ class ControllerArgumentValueResolverPass implements CompilerPassInterface
return;
}
$resolvers = $this->findAndSortTaggedServices($this->argumentValueResolverTag, $container);
if ($container->getParameter('kernel.debug') && class_exists(Stopwatch::class) && $container->has($this->traceableResolverStopwatch)) {
foreach ($resolvers as $resolverReference) {
$id = (string) $resolverReference;
$container->register("debug.$id", TraceableValueResolver::class)
->setDecoratedService($id)
->setArguments([new Reference("debug.$id.inner"), new Reference($this->traceableResolverStopwatch)]);
}
}
$container
->getDefinition($this->argumentResolverService)
->replaceArgument(1, new IteratorArgument($this->findAndSortTaggedServices($this->argumentValueResolverTag, $container)))
->replaceArgument(1, new IteratorArgument($resolvers))
;
}
}

View File

@@ -20,51 +20,18 @@ use Symfony\Component\DependencyInjection\Extension\Extension as BaseExtension;
*/
abstract class Extension extends BaseExtension
{
private $classes = [];
private $annotatedClasses = [];
/**
* Gets the classes to cache.
*
* @return array An array of classes
*
* @deprecated since version 3.3, to be removed in 4.0.
*/
public function getClassesToCompile()
{
if (\PHP_VERSION_ID >= 70000) {
@trigger_error(__METHOD__.'() is deprecated since Symfony 3.3, to be removed in 4.0.', \E_USER_DEPRECATED);
}
return $this->classes;
}
/**
* Gets the annotated classes to cache.
*
* @return array An array of classes
* @return array
*/
public function getAnnotatedClassesToCompile()
{
return $this->annotatedClasses;
}
/**
* Adds classes to the class cache.
*
* @param array $classes An array of class patterns
*
* @deprecated since version 3.3, to be removed in 4.0.
*/
public function addClassesToCompile(array $classes)
{
if (\PHP_VERSION_ID >= 70000) {
@trigger_error(__METHOD__.'() is deprecated since Symfony 3.3, to be removed in 4.0.', \E_USER_DEPRECATED);
}
$this->classes = array_merge($this->classes, $classes);
}
/**
* Adds annotated classes to the class cache.
*

View File

@@ -28,12 +28,12 @@ class FragmentRendererPass implements CompilerPassInterface
private $handlerService;
private $rendererTag;
/**
* @param string $handlerService Service name of the fragment handler in the container
* @param string $rendererTag Tag name used for fragments
*/
public function __construct($handlerService = 'fragment.handler', $rendererTag = 'kernel.fragment_renderer')
public function __construct(string $handlerService = 'fragment.handler', string $rendererTag = 'kernel.fragment_renderer')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->handlerService = $handlerService;
$this->rendererTag = $rendererTag;
}

View File

@@ -23,52 +23,24 @@ use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
class LazyLoadingFragmentHandler extends FragmentHandler
{
private $container;
/**
* @deprecated since version 3.3, to be removed in 4.0
*/
private $rendererIds = [];
private $initialized = [];
/**
* @param ContainerInterface $container A container
* @param RequestStack $requestStack The Request stack that controls the lifecycle of requests
* @param bool $debug Whether the debug mode is enabled or not
* @var array<string, bool>
*/
public function __construct(ContainerInterface $container, RequestStack $requestStack, $debug = false)
private $initialized = [];
public function __construct(ContainerInterface $container, RequestStack $requestStack, bool $debug = false)
{
$this->container = $container;
parent::__construct($requestStack, [], $debug);
}
/**
* Adds a service as a fragment renderer.
*
* @param string $name The service name
* @param string $renderer The render service id
*
* @deprecated since version 3.3, to be removed in 4.0
*/
public function addRendererService($name, $renderer)
{
@trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0.', __METHOD__), \E_USER_DEPRECATED);
$this->rendererIds[$name] = $renderer;
}
/**
* {@inheritdoc}
*/
public function render($uri, $renderer = 'inline', array $options = [])
public function render($uri, string $renderer = 'inline', array $options = [])
{
// BC 3.x, to be removed in 4.0
if (isset($this->rendererIds[$renderer])) {
$this->addRenderer($this->container->get($this->rendererIds[$renderer]));
unset($this->rendererIds[$renderer]);
return parent::render($uri, $renderer, $options);
}
if (!isset($this->initialized[$renderer]) && $this->container->has($renderer)) {
$this->addRenderer($this->container->get($renderer));
$this->initialized[$renderer] = true;

View File

@@ -23,6 +23,9 @@ class MergeExtensionConfigurationPass extends BaseMergeExtensionConfigurationPas
{
private $extensions;
/**
* @param string[] $extensions
*/
public function __construct(array $extensions)
{
$this->extensions = $extensions;

View File

@@ -12,6 +12,7 @@
namespace Symfony\Component\HttpKernel\DependencyInjection;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Attribute\Target;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
@@ -23,6 +24,7 @@ use Symfony\Component\DependencyInjection\LazyProxy\ProxyHelper;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\TypedReference;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
/**
* Creates the service-locators required by ServiceValueResolver.
@@ -33,22 +35,37 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
{
private $resolverServiceId;
private $controllerTag;
private $controllerLocator;
private $notTaggedControllerResolverServiceId;
public function __construct($resolverServiceId = 'argument_resolver.service', $controllerTag = 'controller.service_arguments')
public function __construct(string $resolverServiceId = 'argument_resolver.service', string $controllerTag = 'controller.service_arguments', string $controllerLocator = 'argument_resolver.controller_locator', string $notTaggedControllerResolverServiceId = 'argument_resolver.not_tagged_controller')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->resolverServiceId = $resolverServiceId;
$this->controllerTag = $controllerTag;
$this->controllerLocator = $controllerLocator;
$this->notTaggedControllerResolverServiceId = $notTaggedControllerResolverServiceId;
}
public function process(ContainerBuilder $container)
{
if (false === $container->hasDefinition($this->resolverServiceId)) {
if (false === $container->hasDefinition($this->resolverServiceId) && false === $container->hasDefinition($this->notTaggedControllerResolverServiceId)) {
return;
}
$parameterBag = $container->getParameterBag();
$controllers = [];
$publicAliases = [];
foreach ($container->getAliases() as $id => $alias) {
if ($alias->isPublic() && !$alias->isPrivate()) {
$publicAliases[(string) $alias][] = $id;
}
}
foreach ($container->findTaggedServiceIds($this->controllerTag, true) as $id => $tags) {
$def = $container->getDefinition($id);
$def->setPublic(true);
@@ -95,7 +112,7 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
if (!isset($methods[$action = strtolower($attributes['action'])])) {
throw new InvalidArgumentException(sprintf('Invalid "action" attribute on tag "%s" for service "%s": no public "%s()" method found on class "%s".', $this->controllerTag, $id, $attributes['action'], $class));
}
list($r, $parameters) = $methods[$action];
[$r, $parameters] = $methods[$action];
$found = false;
foreach ($parameters as $p) {
@@ -113,43 +130,51 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
}
}
foreach ($methods as list($r, $parameters)) {
foreach ($methods as [$r, $parameters]) {
/** @var \ReflectionMethod $r */
// create a per-method map of argument-names to service/type-references
$args = [];
foreach ($parameters as $p) {
/** @var \ReflectionParameter $p */
$type = $target = ProxyHelper::getTypeHint($r, $p, true);
$type = ltrim($target = (string) ProxyHelper::getTypeHint($r, $p), '\\');
$invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
if (isset($arguments[$r->name][$p->name])) {
$target = $arguments[$r->name][$p->name];
if ('?' !== $target[0]) {
$invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
$invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE;
} elseif ('' === $target = (string) substr($target, 1)) {
throw new InvalidArgumentException(sprintf('A "%s" tag must have non-empty "id" attributes for service "%s".', $this->controllerTag, $id));
} elseif ($p->allowsNull() && !$p->isOptional()) {
$invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE;
}
} elseif (isset($bindings[$bindingName = '$'.$p->name]) || isset($bindings[$bindingName = $type])) {
} elseif (isset($bindings[$bindingName = $type.' $'.$name = Target::parseName($p)]) || isset($bindings[$bindingName = '$'.$name]) || isset($bindings[$bindingName = $type])) {
$binding = $bindings[$bindingName];
list($bindingValue, $bindingId) = $binding->getValues();
[$bindingValue, $bindingId, , $bindingType, $bindingFile] = $binding->getValues();
$binding->setValues([$bindingValue, $bindingId, true, $bindingType, $bindingFile]);
if (!$bindingValue instanceof Reference) {
continue;
$args[$p->name] = new Reference('.value.'.$container->hash($bindingValue));
$container->register((string) $args[$p->name], 'mixed')
->setFactory('current')
->addArgument([$bindingValue]);
} else {
$args[$p->name] = $bindingValue;
}
$binding->setValues([$bindingValue, $bindingId, true]);
$args[$p->name] = $bindingValue;
continue;
} elseif (!$type || !$autowire) {
} elseif (!$type || !$autowire || '\\' !== $target[0]) {
continue;
} elseif (is_subclass_of($type, \UnitEnum::class)) {
// do not attempt to register enum typed arguments if not already present in bindings
continue;
} elseif (!$p->allowsNull()) {
$invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE;
}
if (Request::class === $type) {
if (Request::class === $type || SessionInterface::class === $type) {
continue;
}
@@ -161,19 +186,38 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
$message .= ' Did you forget to add a use statement?';
}
throw new InvalidArgumentException($message);
}
$container->register($erroredId = '.errored.'.$container->hash($message), $type)
->addError($message);
$args[$p->name] = $type ? new TypedReference($target, $type, $r->class, $invalidBehavior) : new Reference($target, $invalidBehavior);
$args[$p->name] = new Reference($erroredId, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE);
} else {
$target = ltrim($target, '\\');
$args[$p->name] = $type ? new TypedReference($target, $type, $invalidBehavior, Target::parseName($p)) : new Reference($target, $invalidBehavior);
}
}
// register the maps as a per-method service-locators
if ($args) {
$controllers[$id.':'.$r->name] = ServiceLocatorTagPass::register($container, $args);
$controllers[$id.'::'.$r->name] = ServiceLocatorTagPass::register($container, $args);
foreach ($publicAliases[$id] ?? [] as $alias) {
$controllers[$alias.'::'.$r->name] = clone $controllers[$id.'::'.$r->name];
}
}
}
}
$container->getDefinition($this->resolverServiceId)
->replaceArgument(0, ServiceLocatorTagPass::register($container, $controllers));
$controllerLocatorRef = ServiceLocatorTagPass::register($container, $controllers);
if ($container->hasDefinition($this->resolverServiceId)) {
$container->getDefinition($this->resolverServiceId)
->replaceArgument(0, $controllerLocatorRef);
}
if ($container->hasDefinition($this->notTaggedControllerResolverServiceId)) {
$container->getDefinition($this->notTaggedControllerResolverServiceId)
->replaceArgument(0, $controllerLocatorRef);
}
$container->setAlias($this->controllerLocator, (string) $controllerLocatorRef);
}
}

View File

@@ -0,0 +1,62 @@
<?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.
*/
namespace Symfony\Component\HttpKernel\DependencyInjection;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* Register all services that have the "kernel.locale_aware" tag into the listener.
*
* @author Pierre Bobiet <pierrebobiet@gmail.com>
*/
class RegisterLocaleAwareServicesPass implements CompilerPassInterface
{
private $listenerServiceId;
private $localeAwareTag;
public function __construct(string $listenerServiceId = 'locale_aware_listener', string $localeAwareTag = 'kernel.locale_aware')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->listenerServiceId = $listenerServiceId;
$this->localeAwareTag = $localeAwareTag;
}
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition($this->listenerServiceId)) {
return;
}
$services = [];
foreach ($container->findTaggedServiceIds($this->localeAwareTag) as $id => $tags) {
$services[] = new Reference($id);
}
if (!$services) {
$container->removeDefinition($this->listenerServiceId);
return;
}
$container
->getDefinition($this->listenerServiceId)
->setArgument(0, new IteratorArgument($services))
;
}
}

View File

@@ -21,21 +21,20 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
*/
class RemoveEmptyControllerArgumentLocatorsPass implements CompilerPassInterface
{
private $resolverServiceId;
private $controllerLocator;
public function __construct($resolverServiceId = 'argument_resolver.service')
public function __construct(string $controllerLocator = 'argument_resolver.controller_locator')
{
$this->resolverServiceId = $resolverServiceId;
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->controllerLocator = $controllerLocator;
}
public function process(ContainerBuilder $container)
{
if (false === $container->hasDefinition($this->resolverServiceId)) {
return;
}
$serviceResolver = $container->getDefinition($this->resolverServiceId);
$controllerLocator = $container->getDefinition((string) $serviceResolver->getArgument(0));
$controllerLocator = $container->findDefinition($this->controllerLocator);
$controllers = $controllerLocator->getArgument(0);
foreach ($controllers as $controller => $argumentRef) {
@@ -47,19 +46,23 @@ class RemoveEmptyControllerArgumentLocatorsPass implements CompilerPassInterface
} else {
// any methods listed for call-at-instantiation cannot be actions
$reason = false;
$action = substr(strrchr($controller, ':'), 1);
$id = substr($controller, 0, -1 - \strlen($action));
[$id, $action] = explode('::', $controller);
if ($container->hasAlias($id)) {
continue;
}
$controllerDef = $container->getDefinition($id);
foreach ($controllerDef->getMethodCalls() as list($method)) {
foreach ($controllerDef->getMethodCalls() as [$method]) {
if (0 === strcasecmp($action, $method)) {
$reason = sprintf('Removing method "%s" of service "%s" from controller candidates: the method is called at instantiation, thus cannot be an action.', $action, $id);
break;
}
}
if (!$reason) {
if ($controllerDef->getClass() === $id) {
$controllers[$id.'::'.$action] = $argumentRef;
}
// see Symfony\Component\HttpKernel\Controller\ContainerControllerResolver
$controllers[$id.':'.$action] = $argumentRef;
if ('__invoke' === $action) {
$controllers[$id] = $argumentRef;
}

View File

@@ -25,8 +25,12 @@ class ResettableServicePass implements CompilerPassInterface
{
private $tagName;
public function __construct($tagName = 'kernel.reset')
public function __construct(string $tagName = 'kernel.reset')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->tagName = $tagName;
}
@@ -43,16 +47,25 @@ class ResettableServicePass implements CompilerPassInterface
foreach ($container->findTaggedServiceIds($this->tagName, true) as $id => $tags) {
$services[$id] = new Reference($id, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE);
$attributes = $tags[0];
if (!isset($attributes['method'])) {
throw new RuntimeException(sprintf('Tag "%s" requires the "method" attribute to be set.', $this->tagName));
foreach ($tags as $attributes) {
if (!isset($attributes['method'])) {
throw new RuntimeException(sprintf('Tag "%s" requires the "method" attribute to be set.', $this->tagName));
}
if (!isset($methods[$id])) {
$methods[$id] = [];
}
if ('ignore' === ($attributes['on_invalid'] ?? null)) {
$attributes['method'] = '?'.$attributes['method'];
}
$methods[$id][] = $attributes['method'];
}
$methods[$id] = $attributes['method'];
}
if (empty($services)) {
if (!$services) {
$container->removeAlias('services_resetter');
$container->removeDefinition('services_resetter');

View File

@@ -11,6 +11,8 @@
namespace Symfony\Component\HttpKernel\DependencyInjection;
use Symfony\Contracts\Service\ResetInterface;
/**
* Resets provided services.
*
@@ -19,11 +21,15 @@ namespace Symfony\Component\HttpKernel\DependencyInjection;
*
* @internal
*/
class ServicesResetter
class ServicesResetter implements ResetInterface
{
private $resettableServices;
private $resetMethods;
/**
* @param \Traversable<string, object> $resettableServices
* @param array<string, string|string[]> $resetMethods
*/
public function __construct(\Traversable $resettableServices, array $resetMethods)
{
$this->resettableServices = $resettableServices;
@@ -33,7 +39,13 @@ class ServicesResetter
public function reset()
{
foreach ($this->resettableServices as $id => $service) {
$service->{$this->resetMethods[$id]}();
foreach ((array) $this->resetMethods[$id] as $resetMethod) {
if ('?' === $resetMethod[0] && !method_exists($service, $resetMethod = substr($resetMethod, 1))) {
continue;
}
$service->$resetMethod();
}
}
}
}