From 932ae91c74f67e24a121db1704bc25d89b77a73d Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Tue, 24 Mar 2020 17:20:27 +0100 Subject: [PATCH] [FrameworkBundle] Add file links to named controllers in debug:router --- .../Bundle/FrameworkBundle/CHANGELOG.md | 1 + .../Command/BuildDebugContainerTrait.php | 57 +++++++++++++++++++ .../Command/ContainerDebugCommand.php | 39 +------------ .../Command/RouterDebugCommand.php | 5 ++ .../Console/Descriptor/TextDescriptor.php | 26 +++++++-- 5 files changed, 86 insertions(+), 42 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Command/BuildDebugContainerTrait.php diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 386741c878..d3bee96529 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 5.1.0 ----- + * Added link to source for controllers registered as named services * Added link to source on controller on `router:match`/`debug:router` (when `framework.ide` is configured) * Added `Routing\Loader` and `Routing\Loader\Configurator` namespaces to ease defining routes with default controllers * Added the `framework.router.context` configuration node to configure the `RequestContext` diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/BuildDebugContainerTrait.php b/src/Symfony/Bundle/FrameworkBundle/Command/BuildDebugContainerTrait.php new file mode 100644 index 0000000000..8d6ca98fab --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Command/BuildDebugContainerTrait.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Command; + +use Symfony\Component\Config\ConfigCache; +use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; + +/** + * @internal + * + * @author Robin Chalas + * @author Nicolas Grekas + */ +trait BuildDebugContainerTrait +{ + protected $containerBuilder; + + /** + * Loads the ContainerBuilder from the cache. + * + * @throws \LogicException + */ + protected function getContainerBuilder(): ContainerBuilder + { + if ($this->containerBuilder) { + return $this->containerBuilder; + } + + $kernel = $this->getApplication()->getKernel(); + + if (!$kernel->isDebug() || !(new ConfigCache($kernel->getContainer()->getParameter('debug.container.dump'), true))->isFresh()) { + $buildContainer = \Closure::bind(function () { return $this->buildContainer(); }, $kernel, \get_class($kernel)); + $container = $buildContainer(); + $container->getCompilerPassConfig()->setRemovingPasses([]); + $container->getCompilerPassConfig()->setAfterRemovingPasses([]); + $container->compile(); + } else { + (new XmlFileLoader($container = new ContainerBuilder(), new FileLocator()))->load($kernel->getContainer()->getParameter('debug.container.dump')); + $locatorPass = new ServiceLocatorTagPass(); + $locatorPass->process($container); + } + + return $this->containerBuilder = $container; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php index fb0ec25ec1..7c330dbdf4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php @@ -12,8 +12,6 @@ namespace Symfony\Bundle\FrameworkBundle\Command; use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper; -use Symfony\Component\Config\ConfigCache; -use Symfony\Component\Config\FileLocator; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Input\InputArgument; @@ -21,10 +19,8 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; -use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; -use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; /** @@ -36,12 +32,9 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; */ class ContainerDebugCommand extends Command { - protected static $defaultName = 'debug:container'; + use BuildDebugContainerTrait; - /** - * @var ContainerBuilder|null - */ - protected $containerBuilder; + protected static $defaultName = 'debug:container'; /** * {@inheritdoc} @@ -219,34 +212,6 @@ EOF } } - /** - * Loads the ContainerBuilder from the cache. - * - * @throws \LogicException - */ - protected function getContainerBuilder(): ContainerBuilder - { - if ($this->containerBuilder) { - return $this->containerBuilder; - } - - $kernel = $this->getApplication()->getKernel(); - - if (!$kernel->isDebug() || !(new ConfigCache($kernel->getContainer()->getParameter('debug.container.dump'), true))->isFresh()) { - $buildContainer = \Closure::bind(function () { return $this->buildContainer(); }, $kernel, \get_class($kernel)); - $container = $buildContainer(); - $container->getCompilerPassConfig()->setRemovingPasses([]); - $container->getCompilerPassConfig()->setAfterRemovingPasses([]); - $container->compile(); - } else { - (new XmlFileLoader($container = new ContainerBuilder(), new FileLocator()))->load($kernel->getContainer()->getParameter('debug.container.dump')); - $locatorPass = new ServiceLocatorTagPass(); - $locatorPass->process($container); - } - - return $this->containerBuilder = $container; - } - private function findProperServiceName(InputInterface $input, SymfonyStyle $io, ContainerBuilder $builder, string $name, bool $showHidden): string { $name = ltrim($name, '\\'); diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/RouterDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/RouterDebugCommand.php index 9724e5122e..16acf7a7db 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/RouterDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/RouterDebugCommand.php @@ -33,6 +33,8 @@ use Symfony\Component\Routing\RouterInterface; */ class RouterDebugCommand extends Command { + use BuildDebugContainerTrait; + protected static $defaultName = 'debug:router'; private $router; private $fileLinkFormatter; @@ -79,6 +81,7 @@ EOF $name = $input->getArgument('name'); $helper = new DescriptorHelper($this->fileLinkFormatter); $routes = $this->router->getRouteCollection(); + $container = $this->fileLinkFormatter ? \Closure::fromCallable([$this, 'getContainerBuilder']) : null; if ($name) { if (!($route = $routes->get($name)) && $matchingRoutes = $this->findRouteNameContaining($name, $routes)) { @@ -96,6 +99,7 @@ EOF 'raw_text' => $input->getOption('raw'), 'name' => $name, 'output' => $io, + 'container' => $container, ]); } else { $helper->describe($io, $routes, [ @@ -103,6 +107,7 @@ EOF 'raw_text' => $input->getOption('raw'), 'show_controllers' => $input->getOption('show-controllers'), 'output' => $io, + 'container' => $container, ]); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index b34503192e..13dfd71f51 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -61,11 +61,11 @@ class TextDescriptor extends Descriptor $route->getMethods() ? implode('|', $route->getMethods()) : 'ANY', $route->getSchemes() ? implode('|', $route->getSchemes()) : 'ANY', '' !== $route->getHost() ? $route->getHost() : 'ANY', - $this->formatControllerLink($controller, $route->getPath()), + $this->formatControllerLink($controller, $route->getPath(), $options['container'] ?? null), ]; if ($showControllers) { - $row[] = $controller ? $this->formatControllerLink($controller, $this->formatCallable($controller)) : ''; + $row[] = $controller ? $this->formatControllerLink($controller, $this->formatCallable($controller), $options['container'] ?? null) : ''; } $tableRows[] = $row; @@ -84,7 +84,7 @@ class TextDescriptor extends Descriptor { $defaults = $route->getDefaults(); if (isset($defaults['_controller'])) { - $defaults['_controller'] = $this->formatControllerLink($defaults['_controller'], $this->formatCallable($defaults['_controller'])); + $defaults['_controller'] = $this->formatControllerLink($defaults['_controller'], $this->formatCallable($defaults['_controller']), $options['container'] ?? null); } $tableHeaders = ['Property', 'Value']; @@ -528,7 +528,7 @@ class TextDescriptor extends Descriptor return trim($configAsString); } - private function formatControllerLink($controller, string $anchorText): string + private function formatControllerLink($controller, string $anchorText, callable $getContainer = null): string { if (null === $this->fileLinkFormatter) { return $anchorText; @@ -549,7 +549,23 @@ class TextDescriptor extends Descriptor $r = new \ReflectionFunction($controller); } } catch (\ReflectionException $e) { - return $anchorText; + $id = $controller; + $method = '__invoke'; + + if ($pos = strpos($controller, '::')) { + $id = substr($controller, 0, $pos); + $method = substr($controller, $pos + 2); + } + + if (!$getContainer || !($container = $getContainer()) || !$container->has($id)) { + return $anchorText; + } + + try { + $r = new \ReflectionMethod($container->findDefinition($id)->getClass(), $method); + } catch (\ReflectionException $e) { + return $anchorText; + } } $fileLink = $this->fileLinkFormatter->format($r->getFileName(), $r->getStartLine());