diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php index aed608053a5c2..b9431863b8b63 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php @@ -21,6 +21,7 @@ use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; +use Symfony\Component\DependencyInjection\Loader\UndefinedExtensionHandler; use Symfony\Component\ExpressionLanguage\Expression; /** @@ -58,7 +59,7 @@ final public function extension(string $namespace, array $config, bool $prepend if (!$this->container->hasExtension($namespace)) { $extensions = array_filter(array_map(fn (ExtensionInterface $ext) => $ext->getAlias(), $this->container->getExtensions())); - throw new InvalidArgumentException(sprintf('There is no extension able to load the configuration for "%s" (in "%s"). Looked for namespace "%s", found "%s".', $namespace, $this->file, $namespace, $extensions ? implode('", "', $extensions) : 'none')); + throw new InvalidArgumentException(UndefinedExtensionHandler::getErrorMessage($namespace, $this->file, $namespace, $extensions)); } $this->container->loadFromExtension($namespace, static::processValue($config)); diff --git a/src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php index 9acaa8cffbfbc..8450555f06397 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php @@ -183,7 +183,7 @@ private function configBuilder(string $namespace): ConfigBuilderInterface if (!$this->container->hasExtension($alias)) { $extensions = array_filter(array_map(fn (ExtensionInterface $ext) => $ext->getAlias(), $this->container->getExtensions())); - throw new InvalidArgumentException(sprintf('There is no extension able to load the configuration for "%s". Looked for namespace "%s", found "%s".', $namespace, $alias, $extensions ? implode('", "', $extensions) : 'none')); + throw new InvalidArgumentException(UndefinedExtensionHandler::getErrorMessage($namespace, null, $alias, $extensions)); } $extension = $this->container->getExtension($alias); diff --git a/src/Symfony/Component/DependencyInjection/Loader/UndefinedExtensionHandler.php b/src/Symfony/Component/DependencyInjection/Loader/UndefinedExtensionHandler.php new file mode 100644 index 0000000000000..953104effe64a --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Loader/UndefinedExtensionHandler.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Loader; + +class UndefinedExtensionHandler +{ + private const BUNDLE_EXTENSIONS = [ + 'debug' => 'DebugBundle', + 'doctrine' => 'DoctrineBundle', + 'doctrine_migrations' => 'DoctrineMigrationsBundle', + 'framework' => 'FrameworkBundle', + 'maker' => 'MakerBundle', + 'monolog' => 'MonologBundle', + 'security' => 'SecurityBundle', + 'twig' => 'TwigBundle', + 'twig_component' => 'TwigComponentBundle', + 'ux_icons' => 'UXIconsBundle', + 'web_profiler' => 'WebProfilerBundle', + ]; + + public static function getErrorMessage(string $extensionName, ?string $loadingFilePath, string $namespaceOrAlias, array $foundExtensionNamespaces): string + { + $message = ''; + if (isset(self::BUNDLE_EXTENSIONS[$extensionName])) { + $message .= sprintf('Did you forget to install or enable the %s? ', self::BUNDLE_EXTENSIONS[$extensionName]); + } + + $message .= match (true) { + \is_string($loadingFilePath) => sprintf('There is no extension able to load the configuration for "%s" (in "%s"). ', $extensionName, $loadingFilePath), + default => sprintf('There is no extension able to load the configuration for "%s". ', $extensionName), + }; + + $message .= sprintf('Looked for namespace "%s", found "%s".', $namespaceOrAlias, $foundExtensionNamespaces ? implode('", "', $foundExtensionNamespaces) : 'none'); + + return $message; + } +} diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 6fedd9821acee..8c87a848adbec 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -810,7 +810,7 @@ private function validateExtensions(\DOMDocument $dom, string $file): void // can it be handled by an extension? if (!$this->container->hasExtension($node->namespaceURI)) { $extensionNamespaces = array_filter(array_map(fn (ExtensionInterface $ext) => $ext->getNamespace(), $this->container->getExtensions())); - throw new InvalidArgumentException(sprintf('There is no extension able to load the configuration for "%s" (in "%s"). Looked for namespace "%s", found "%s".', $node->tagName, $file, $node->namespaceURI, $extensionNamespaces ? implode('", "', $extensionNamespaces) : 'none')); + throw new InvalidArgumentException(UndefinedExtensionHandler::getErrorMessage($node->tagName, $file, $node->namespaceURI, $extensionNamespaces)); } } } diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index c74e606be3831..56bcd466edcb0 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -804,7 +804,7 @@ private function validate(mixed $content, string $file): ?array if (!$this->container->hasExtension($namespace)) { $extensionNamespaces = array_filter(array_map(fn (ExtensionInterface $ext) => $ext->getAlias(), $this->container->getExtensions())); - throw new InvalidArgumentException(sprintf('There is no extension able to load the configuration for "%s" (in "%s"). Looked for namespace "%s", found "%s".', $namespace, $file, $namespace, $extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none')); + throw new InvalidArgumentException(UndefinedExtensionHandler::getErrorMessage($namespace, $file, $namespace, $extensionNamespaces)); } }