From d20c572297faf1f5051798db12e071e7e1472070 Mon Sep 17 00:00:00 2001 From: Adrien Roches Date: Fri, 25 Apr 2025 11:28:54 +0200 Subject: [PATCH 1/5] Move logic to static method --- .../RegisterServiceSubscribersPass.php | 92 +++++++++++-------- 1 file changed, 53 insertions(+), 39 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php b/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php index 87470c39894e4..fd684aa415c22 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php @@ -14,6 +14,7 @@ use Psr\Container\ContainerInterface as PsrContainerInterface; use Symfony\Component\DependencyInjection\Argument\BoundArgument; use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; @@ -38,36 +39,58 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed return parent::processValue($value, $isRoot); } - $serviceMap = []; - $autowire = $value->isAutowired(); + $locatorRef = self::registerLocator($value, $this->container, $this->currentId); - foreach ($value->getTag('container.service_subscriber') as $attributes) { - if (!$attributes) { - $autowire = true; - continue; - } - ksort($attributes); - if ([] !== array_diff(array_keys($attributes), ['id', 'key'])) { - throw new InvalidArgumentException(\sprintf('The "container.service_subscriber" tag accepts only the "key" and "id" attributes, "%s" given for service "%s".', implode('", "', array_keys($attributes)), $this->currentId)); - } - if (!\array_key_exists('id', $attributes)) { - throw new InvalidArgumentException(\sprintf('Missing "id" attribute on "container.service_subscriber" tag with key="%s" for service "%s".', $attributes['key'], $this->currentId)); - } - if (!\array_key_exists('key', $attributes)) { - $attributes['key'] = $attributes['id']; - } - if (isset($serviceMap[$attributes['key']])) { - continue; + $value->addTag('container.service_subscriber.locator', ['id' => (string) $locatorRef]); + + $value->setBindings([ + PsrContainerInterface::class => new BoundArgument($locatorRef, false), + ServiceProviderInterface::class => new BoundArgument($locatorRef, false), + ] + $value->getBindings()); + + return parent::processValue($value); + } + + /** + * @param class-string|Definition $value + */ + public static function registerLocator(string|Definition $value, ContainerBuilder $container, string $currentId): Reference + { + if ($value instanceof Definition) { + $autowire = $value->isAutowired(); + + foreach ($value->getTag('container.service_subscriber') as $attributes) { + if (!$attributes) { + $autowire = true; + continue; + } + ksort($attributes); + if ([] !== array_diff(array_keys($attributes), ['id', 'key'])) { + throw new InvalidArgumentException(\sprintf('The "container.service_subscriber" tag accepts only the "key" and "id" attributes, "%s" given for service "%s".', implode('", "', array_keys($attributes)), $currentId)); + } + if (!\array_key_exists('id', $attributes)) { + throw new InvalidArgumentException(\sprintf('Missing "id" attribute on "container.service_subscriber" tag with key="%s" for service "%s".', $attributes['key'], $currentId)); + } + if (!\array_key_exists('key', $attributes)) { + $attributes['key'] = $attributes['id']; + } + if (isset($serviceMap[$attributes['key']])) { + continue; + } + $serviceMap[$attributes['key']] = new Reference($attributes['id']); } - $serviceMap[$attributes['key']] = new Reference($attributes['id']); + $class = $value->getClass(); + } else { + $class = $value; } - $class = $value->getClass(); - if (!$r = $this->container->getReflectionClass($class)) { - throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $this->currentId)); + $serviceMap = []; + + if (!$r = $container->getReflectionClass($class)) { + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $currentId)); } if (!$r->isSubclassOf(ServiceSubscriberInterface::class)) { - throw new InvalidArgumentException(\sprintf('Service "%s" must implement interface "%s".', $this->currentId, ServiceSubscriberInterface::class)); + throw new InvalidArgumentException(\sprintf('Service "%s" must implement interface "%s".', $currentId, ServiceSubscriberInterface::class)); } $class = $r->name; $subscriberMap = []; @@ -87,7 +110,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed } if (!\is_string($type) || !preg_match('/(?(DEFINE)(?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+))(?(DEFINE)(?(?&cn)(?:\\\\(?&cn))*+))^\??(?&fqcn)(?:(?:\|(?&fqcn))*+|(?:&(?&fqcn))*+)$/', $type)) { - throw new InvalidArgumentException(\sprintf('"%s::getSubscribedServices()" must return valid PHP types for service "%s" key "%s", "%s" returned.', $class, $this->currentId, $key, \is_string($type) ? $type : get_debug_type($type))); + throw new InvalidArgumentException(\sprintf('"%s::getSubscribedServices()" must return valid PHP types for service "%s" key "%s", "%s" returned.', $class, $currentId, $key, \is_string($type) ? $type : get_debug_type($type))); } $optionalBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; if ('?' === $type[0]) { @@ -100,7 +123,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed } if (!isset($serviceMap[$key])) { if (!$autowire) { - throw new InvalidArgumentException(\sprintf('Service "%s" misses a "container.service_subscriber" tag with "key"/"id" attributes corresponding to entry "%s" as returned by "%s::getSubscribedServices()".', $this->currentId, $key, $class)); + throw new InvalidArgumentException(\sprintf('Service "%s" misses a "container.service_subscriber" tag with "key"/"id" attributes corresponding to entry "%s" as returned by "%s::getSubscribedServices()".', $currentId, $key, $class)); } $serviceMap[$key] = new Reference($type); } @@ -113,9 +136,9 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed } } - if (null !== $name && !$this->container->has($name) && !$this->container->has($type.' $'.$name)) { + if (null !== $name && !$container->has($name) && !$container->has($type.' $'.$name)) { $camelCaseName = lcfirst(str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $name)))); - $name = $this->container->has($type.' $'.$camelCaseName) ? $camelCaseName : $name; + $name = $container->has($type.' $'.$camelCaseName) ? $camelCaseName : $name; } $subscriberMap[$key] = new TypedReference((string) $serviceMap[$key], $type, $optionalBehavior, $name, $attributes); @@ -124,18 +147,9 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed if ($serviceMap = array_keys($serviceMap)) { $message = \sprintf(1 < \count($serviceMap) ? 'keys "%s" do' : 'key "%s" does', str_replace('%', '%%', implode('", "', $serviceMap))); - throw new InvalidArgumentException(\sprintf('Service %s not exist in the map returned by "%s::getSubscribedServices()" for service "%s".', $message, $class, $this->currentId)); + throw new InvalidArgumentException(\sprintf('Service %s not exist in the map returned by "%s::getSubscribedServices()" for service "%s".', $message, $class, $currentId)); } - $locatorRef = ServiceLocatorTagPass::register($this->container, $subscriberMap, $this->currentId); - - $value->addTag('container.service_subscriber.locator', ['id' => (string) $locatorRef]); - - $value->setBindings([ - PsrContainerInterface::class => new BoundArgument($locatorRef, false), - ServiceProviderInterface::class => new BoundArgument($locatorRef, false), - ] + $value->getBindings()); - - return parent::processValue($value); + return ServiceLocatorTagPass::register($container, $subscriberMap, $currentId); } } From 09de28b6700e875df209494634f7a3f756861692 Mon Sep 17 00:00:00 2001 From: Adrien Roches Date: Fri, 25 Apr 2025 11:36:07 +0200 Subject: [PATCH 2/5] fix code to comply with tests --- .../Compiler/RegisterServiceSubscribersPass.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php b/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php index fd684aa415c22..d691781d2257e 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php @@ -56,6 +56,8 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed */ public static function registerLocator(string|Definition $value, ContainerBuilder $container, string $currentId): Reference { + $serviceMap = []; + if ($value instanceof Definition) { $autowire = $value->isAutowired(); @@ -79,13 +81,12 @@ public static function registerLocator(string|Definition $value, ContainerBuilde } $serviceMap[$attributes['key']] = new Reference($attributes['id']); } + $class = $value->getClass(); } else { $class = $value; } - $serviceMap = []; - if (!$r = $container->getReflectionClass($class)) { throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $currentId)); } From 90935d4926ab4bc565b754ae8ce87fb31b8426cb Mon Sep 17 00:00:00 2001 From: Adrien Roches Date: Fri, 25 Apr 2025 13:52:16 +0200 Subject: [PATCH 3/5] Make definition optional --- .../RegisterServiceSubscribersPass.php | 10 +- .../RegisterServiceSubscribersPass.php.orig | 160 ++++++++++++++++++ 2 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php.orig diff --git a/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php b/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php index d691781d2257e..a99f196fecc6a 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php @@ -39,7 +39,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed return parent::processValue($value, $isRoot); } - $locatorRef = self::registerLocator($value, $this->container, $this->currentId); + $locatorRef = self::registerLocator($this->container, $this->currentId, $value); $value->addTag('container.service_subscriber.locator', ['id' => (string) $locatorRef]); @@ -54,10 +54,14 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed /** * @param class-string|Definition $value */ - public static function registerLocator(string|Definition $value, ContainerBuilder $container, string $currentId): Reference + public static function registerLocator(ContainerBuilder $container, string $currentId, string|Definition|null $value = null): Reference { $serviceMap = []; + if (null === $value) { + $value = $container->getDefinition($currentId); + } + if ($value instanceof Definition) { $autowire = $value->isAutowired(); @@ -148,7 +152,7 @@ public static function registerLocator(string|Definition $value, ContainerBuilde if ($serviceMap = array_keys($serviceMap)) { $message = \sprintf(1 < \count($serviceMap) ? 'keys "%s" do' : 'key "%s" does', str_replace('%', '%%', implode('", "', $serviceMap))); - throw new InvalidArgumentException(\sprintf('Service %s not exist in the map returned by "%s::getSubscribedServices()" for service "%s".', $message, $class, $currentId)); + throw new InvalidArgumentException(\sprintf('Service "%s" not exist in the map returned by "%s::getSubscribedServices()" for service "%s".', $message, $class, $currentId)); } return ServiceLocatorTagPass::register($container, $subscriberMap, $currentId); diff --git a/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php.orig b/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php.orig new file mode 100644 index 0000000000000..add19cf1a0e7f --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php.orig @@ -0,0 +1,160 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Compiler; + +use Psr\Container\ContainerInterface as PsrContainerInterface; +use Symfony\Component\DependencyInjection\Argument\BoundArgument; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\TypedReference; +use Symfony\Contracts\Service\Attribute\SubscribedService; +use Symfony\Contracts\Service\ServiceProviderInterface; +use Symfony\Contracts\Service\ServiceSubscriberInterface; + +/** + * Compiler pass to register tagged services that require a service locator. + * + * @author Nicolas Grekas + */ +class RegisterServiceSubscribersPass extends AbstractRecursivePass +{ + protected bool $skipScalars = true; + + protected function processValue(mixed $value, bool $isRoot = false): mixed + { + if (!$value instanceof Definition || $value->isAbstract() || $value->isSynthetic() || !$value->hasTag('container.service_subscriber')) { + return parent::processValue($value, $isRoot); + } + + $locatorRef = self::registerLocator($this->container, $this->currentId, $value); + + $value->addTag('container.service_subscriber.locator', ['id' => (string) $locatorRef]); + + $value->setBindings([ + PsrContainerInterface::class => new BoundArgument($locatorRef, false), + ServiceProviderInterface::class => new BoundArgument($locatorRef, false), + ] + $value->getBindings()); + + return parent::processValue($value); + } + + /** + * @param class-string|Definition $value + */ + public static function registerLocator(ContainerBuilder $container, string $currentId, string|Definition|null $value = null): Reference + { + $serviceMap = []; + + if (null === $value) { + $value = $container->getDefinition($currentId); + } + + if ($value instanceof Definition) { + $autowire = $value->isAutowired(); + + foreach ($value->getTag('container.service_subscriber') as $attributes) { + if (!$attributes) { + $autowire = true; + continue; + } + ksort($attributes); + if ([] !== array_diff(array_keys($attributes), ['id', 'key'])) { + throw new InvalidArgumentException(\sprintf('The "container.service_subscriber" tag accepts only the "key" and "id" attributes, "%s" given for service "%s".', implode('", "', array_keys($attributes)), $currentId)); + } + if (!\array_key_exists('id', $attributes)) { + throw new InvalidArgumentException(\sprintf('Missing "id" attribute on "container.service_subscriber" tag with key="%s" for service "%s".', $attributes['key'], $currentId)); + } + if (!\array_key_exists('key', $attributes)) { + $attributes['key'] = $attributes['id']; + } + if (isset($serviceMap[$attributes['key']])) { + continue; + } + $serviceMap[$attributes['key']] = new Reference($attributes['id']); + } + + $class = $value->getClass(); + } else { + $class = $value; + } + + if (!$r = $container->getReflectionClass($class)) { + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $currentId)); + } + if (!$r->isSubclassOf(ServiceSubscriberInterface::class)) { + throw new InvalidArgumentException(\sprintf('Service "%s" must implement interface "%s".', $currentId, ServiceSubscriberInterface::class)); + } + $class = $r->name; + $subscriberMap = []; + + foreach ($class::getSubscribedServices() as $key => $type) { + $attributes = []; + + if (!isset($serviceMap[$key]) && $type instanceof Autowire) { + $subscriberMap[$key] = $type; + continue; + } + + if ($type instanceof SubscribedService) { + $key = $type->key ?? $key; + $attributes = $type->attributes; + $type = ($type->nullable ? '?' : '').($type->type ?? throw new InvalidArgumentException(\sprintf('When "%s::getSubscribedServices()" returns "%s", a type must be set.', $class, SubscribedService::class))); + } + + if (!\is_string($type) || !preg_match('/(?(DEFINE)(?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+))(?(DEFINE)(?(?&cn)(?:\\\\(?&cn))*+))^\??(?&fqcn)(?:(?:\|(?&fqcn))*+|(?:&(?&fqcn))*+)$/', $type)) { + throw new InvalidArgumentException(\sprintf('"%s::getSubscribedServices()" must return valid PHP types for service "%s" key "%s", "%s" returned.', $class, $currentId, $key, \is_string($type) ? $type : get_debug_type($type))); + } + $optionalBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; + if ('?' === $type[0]) { + $type = substr($type, 1); + $optionalBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; + } + if (\is_int($name = $key)) { + $key = $type; + $name = null; + } + if (!isset($serviceMap[$key])) { + if (!$autowire) { + throw new InvalidArgumentException(\sprintf('Service "%s" misses a "container.service_subscriber" tag with "key"/"id" attributes corresponding to entry "%s" as returned by "%s::getSubscribedServices()".', $currentId, $key, $class)); + } + $serviceMap[$key] = new Reference($type); + } + + if ($name) { + if (false !== $i = strpos($name, '::get')) { + $name = lcfirst(substr($name, 5 + $i)); + } elseif (str_contains($name, '::')) { + $name = null; + } + } + + if (null !== $name && !$container->has($name) && !$container->has($type.' $'.$name)) { + $camelCaseName = lcfirst(str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $name)))); + $name = $container->has($type.' $'.$camelCaseName) ? $camelCaseName : $name; + } + + $subscriberMap[$key] = new TypedReference((string) $serviceMap[$key], $type, $optionalBehavior, $name, $attributes); + unset($serviceMap[$key]); + } + + if ($serviceMap = array_keys($serviceMap)) { + $message = \sprintf(1 < \count($serviceMap) ? 'keys "%s" do' : 'key "%s" does', str_replace('%', '%%', implode('", "', $serviceMap))); + throw new InvalidArgumentException(\sprintf('Service %s not exist in the map returned by "%s::getSubscribedServices()" for service "%s".', $message, $class, $currentId)); + } + + return ServiceLocatorTagPass::register($container, $subscriberMap, $currentId); + } +} From 2460a2eb9b269ed5a38900e8a5783b2b08beaa4c Mon Sep 17 00:00:00 2001 From: Adrien Roches Date: Fri, 25 Apr 2025 13:53:07 +0200 Subject: [PATCH 4/5] Remove old file --- .../RegisterServiceSubscribersPass.php.orig | 160 ------------------ 1 file changed, 160 deletions(-) delete mode 100644 src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php.orig diff --git a/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php.orig b/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php.orig deleted file mode 100644 index add19cf1a0e7f..0000000000000 --- a/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php.orig +++ /dev/null @@ -1,160 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Compiler; - -use Psr\Container\ContainerInterface as PsrContainerInterface; -use Symfony\Component\DependencyInjection\Argument\BoundArgument; -use Symfony\Component\DependencyInjection\Attribute\Autowire; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\TypedReference; -use Symfony\Contracts\Service\Attribute\SubscribedService; -use Symfony\Contracts\Service\ServiceProviderInterface; -use Symfony\Contracts\Service\ServiceSubscriberInterface; - -/** - * Compiler pass to register tagged services that require a service locator. - * - * @author Nicolas Grekas - */ -class RegisterServiceSubscribersPass extends AbstractRecursivePass -{ - protected bool $skipScalars = true; - - protected function processValue(mixed $value, bool $isRoot = false): mixed - { - if (!$value instanceof Definition || $value->isAbstract() || $value->isSynthetic() || !$value->hasTag('container.service_subscriber')) { - return parent::processValue($value, $isRoot); - } - - $locatorRef = self::registerLocator($this->container, $this->currentId, $value); - - $value->addTag('container.service_subscriber.locator', ['id' => (string) $locatorRef]); - - $value->setBindings([ - PsrContainerInterface::class => new BoundArgument($locatorRef, false), - ServiceProviderInterface::class => new BoundArgument($locatorRef, false), - ] + $value->getBindings()); - - return parent::processValue($value); - } - - /** - * @param class-string|Definition $value - */ - public static function registerLocator(ContainerBuilder $container, string $currentId, string|Definition|null $value = null): Reference - { - $serviceMap = []; - - if (null === $value) { - $value = $container->getDefinition($currentId); - } - - if ($value instanceof Definition) { - $autowire = $value->isAutowired(); - - foreach ($value->getTag('container.service_subscriber') as $attributes) { - if (!$attributes) { - $autowire = true; - continue; - } - ksort($attributes); - if ([] !== array_diff(array_keys($attributes), ['id', 'key'])) { - throw new InvalidArgumentException(\sprintf('The "container.service_subscriber" tag accepts only the "key" and "id" attributes, "%s" given for service "%s".', implode('", "', array_keys($attributes)), $currentId)); - } - if (!\array_key_exists('id', $attributes)) { - throw new InvalidArgumentException(\sprintf('Missing "id" attribute on "container.service_subscriber" tag with key="%s" for service "%s".', $attributes['key'], $currentId)); - } - if (!\array_key_exists('key', $attributes)) { - $attributes['key'] = $attributes['id']; - } - if (isset($serviceMap[$attributes['key']])) { - continue; - } - $serviceMap[$attributes['key']] = new Reference($attributes['id']); - } - - $class = $value->getClass(); - } else { - $class = $value; - } - - if (!$r = $container->getReflectionClass($class)) { - throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $currentId)); - } - if (!$r->isSubclassOf(ServiceSubscriberInterface::class)) { - throw new InvalidArgumentException(\sprintf('Service "%s" must implement interface "%s".', $currentId, ServiceSubscriberInterface::class)); - } - $class = $r->name; - $subscriberMap = []; - - foreach ($class::getSubscribedServices() as $key => $type) { - $attributes = []; - - if (!isset($serviceMap[$key]) && $type instanceof Autowire) { - $subscriberMap[$key] = $type; - continue; - } - - if ($type instanceof SubscribedService) { - $key = $type->key ?? $key; - $attributes = $type->attributes; - $type = ($type->nullable ? '?' : '').($type->type ?? throw new InvalidArgumentException(\sprintf('When "%s::getSubscribedServices()" returns "%s", a type must be set.', $class, SubscribedService::class))); - } - - if (!\is_string($type) || !preg_match('/(?(DEFINE)(?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+))(?(DEFINE)(?(?&cn)(?:\\\\(?&cn))*+))^\??(?&fqcn)(?:(?:\|(?&fqcn))*+|(?:&(?&fqcn))*+)$/', $type)) { - throw new InvalidArgumentException(\sprintf('"%s::getSubscribedServices()" must return valid PHP types for service "%s" key "%s", "%s" returned.', $class, $currentId, $key, \is_string($type) ? $type : get_debug_type($type))); - } - $optionalBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; - if ('?' === $type[0]) { - $type = substr($type, 1); - $optionalBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; - } - if (\is_int($name = $key)) { - $key = $type; - $name = null; - } - if (!isset($serviceMap[$key])) { - if (!$autowire) { - throw new InvalidArgumentException(\sprintf('Service "%s" misses a "container.service_subscriber" tag with "key"/"id" attributes corresponding to entry "%s" as returned by "%s::getSubscribedServices()".', $currentId, $key, $class)); - } - $serviceMap[$key] = new Reference($type); - } - - if ($name) { - if (false !== $i = strpos($name, '::get')) { - $name = lcfirst(substr($name, 5 + $i)); - } elseif (str_contains($name, '::')) { - $name = null; - } - } - - if (null !== $name && !$container->has($name) && !$container->has($type.' $'.$name)) { - $camelCaseName = lcfirst(str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $name)))); - $name = $container->has($type.' $'.$camelCaseName) ? $camelCaseName : $name; - } - - $subscriberMap[$key] = new TypedReference((string) $serviceMap[$key], $type, $optionalBehavior, $name, $attributes); - unset($serviceMap[$key]); - } - - if ($serviceMap = array_keys($serviceMap)) { - $message = \sprintf(1 < \count($serviceMap) ? 'keys "%s" do' : 'key "%s" does', str_replace('%', '%%', implode('", "', $serviceMap))); - throw new InvalidArgumentException(\sprintf('Service %s not exist in the map returned by "%s::getSubscribedServices()" for service "%s".', $message, $class, $currentId)); - } - - return ServiceLocatorTagPass::register($container, $subscriberMap, $currentId); - } -} From 26d700894aa56ca41440e6911f05b3fa08756974 Mon Sep 17 00:00:00 2001 From: Adrien Roches Date: Fri, 25 Apr 2025 14:03:24 +0200 Subject: [PATCH 5/5] Fix message --- .../Compiler/RegisterServiceSubscribersPass.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php b/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php index a99f196fecc6a..add19cf1a0e7f 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php @@ -152,7 +152,7 @@ public static function registerLocator(ContainerBuilder $container, string $curr if ($serviceMap = array_keys($serviceMap)) { $message = \sprintf(1 < \count($serviceMap) ? 'keys "%s" do' : 'key "%s" does', str_replace('%', '%%', implode('", "', $serviceMap))); - throw new InvalidArgumentException(\sprintf('Service "%s" not exist in the map returned by "%s::getSubscribedServices()" for service "%s".', $message, $class, $currentId)); + throw new InvalidArgumentException(\sprintf('Service %s not exist in the map returned by "%s::getSubscribedServices()" for service "%s".', $message, $class, $currentId)); } return ServiceLocatorTagPass::register($container, $subscriberMap, $currentId);