vendor/symfony/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * This file is part of the Symfony package.
       
     5  *
       
     6  * (c) Fabien Potencier <fabien@symfony.com>
       
     7  *
       
     8  * For the full copyright and license information, please view the LICENSE
       
     9  * file that was distributed with this source code.
       
    10  */
       
    11 
       
    12 namespace Symfony\Bundle\FrameworkBundle\Command;
       
    13 
       
    14 use Symfony\Component\Console\Input\InputArgument;
       
    15 use Symfony\Component\Console\Input\InputOption;
       
    16 use Symfony\Component\Console\Input\InputInterface;
       
    17 use Symfony\Component\Console\Output\OutputInterface;
       
    18 use Symfony\Component\Console\Output\Output;
       
    19 use Symfony\Component\DependencyInjection\Alias;
       
    20 use Symfony\Component\DependencyInjection\Definition;
       
    21 use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
       
    22 use Symfony\Component\DependencyInjection\ContainerBuilder;
       
    23 use Symfony\Component\Config\FileLocator;
       
    24 
       
    25 /**
       
    26  * A console command for retrieving information about services
       
    27  *
       
    28  * @author Ryan Weaver <ryan@thatsquality.com>
       
    29  */
       
    30 class ContainerDebugCommand extends ContainerAwareCommand
       
    31 {
       
    32     /**
       
    33      * @var ContainerBuilder
       
    34      */
       
    35     private $containerBuilder;
       
    36 
       
    37     /**
       
    38      * @see Command
       
    39      */
       
    40     protected function configure()
       
    41     {
       
    42         $this
       
    43             ->setDefinition(array(
       
    44                 new InputArgument('name', InputArgument::OPTIONAL, 'A service name (foo)  or search (foo*)'),
       
    45                 new InputOption('show-private', null, InputOption::VALUE_NONE, 'Use to show public *and* private services'),
       
    46             ))
       
    47             ->setName('container:debug')
       
    48             ->setDescription('Displays current services for an application')
       
    49             ->setHelp(<<<EOF
       
    50 The <info>container:debug</info> command displays all configured <comment>public</comment> services:
       
    51 
       
    52   <info>container:debug</info>
       
    53 
       
    54 To get specific information about a service, specify its name:
       
    55 
       
    56   <info>container:debug validator</info>
       
    57 
       
    58 By default, private services are hidden. You can display all services by
       
    59 using the --show-private flag:
       
    60 
       
    61   <info>container:debug --show-private</info>
       
    62 EOF
       
    63             )
       
    64         ;
       
    65     }
       
    66 
       
    67     /**
       
    68      * @see Command
       
    69      */
       
    70     protected function execute(InputInterface $input, OutputInterface $output)
       
    71     {
       
    72         $name = $input->getArgument('name');
       
    73 
       
    74         $this->containerBuilder = $this->getContainerBuilder();
       
    75         $serviceIds = $this->containerBuilder->getServiceIds();
       
    76 
       
    77         // sort so that it reads like an index of services
       
    78         asort($serviceIds);
       
    79 
       
    80         if ($name) {
       
    81             $this->outputService($output, $name);
       
    82         } else {
       
    83             $this->outputServices($output, $serviceIds, $input->getOption('show-private'));
       
    84         }
       
    85     }
       
    86 
       
    87     protected function outputServices(OutputInterface $output, $serviceIds, $showPrivate = false)
       
    88     {
       
    89         // set the label to specify public or public+private
       
    90         if ($showPrivate) {
       
    91             $label = '<comment>Public</comment> and <comment>private</comment> services';
       
    92         } else {
       
    93             $label = '<comment>Public</comment> services';
       
    94         }
       
    95 
       
    96         $output->writeln($this->getHelper('formatter')->formatSection('container', $label));
       
    97 
       
    98         // loop through to get space needed and filter private services
       
    99         $maxName = 4;
       
   100         $maxScope = 6;
       
   101         foreach ($serviceIds as $key => $serviceId) {
       
   102             $definition = $this->resolveServiceDefinition($serviceId);
       
   103 
       
   104             if ($definition instanceof Definition) {
       
   105                 // filter out private services unless shown explicitly
       
   106                 if (!$showPrivate && !$definition->isPublic()) {
       
   107                     unset($serviceIds[$key]);
       
   108                     continue;
       
   109                 }
       
   110 
       
   111                 if (strlen($definition->getScope()) > $maxScope) {
       
   112                     $maxScope = strlen($definition->getScope());
       
   113                 }
       
   114             }
       
   115 
       
   116             if (strlen($serviceId) > $maxName) {
       
   117                 $maxName = strlen($serviceId);
       
   118             }
       
   119         }
       
   120         $format  = '%-'.$maxName.'s %-'.$maxScope.'s %s';
       
   121 
       
   122         // the title field needs extra space to make up for comment tags
       
   123         $format1  = '%-'.($maxName + 19).'s %-'.($maxScope + 19).'s %s';
       
   124         $output->writeln(sprintf($format1, '<comment>Name</comment>', '<comment>Scope</comment>', '<comment>Class Name</comment>'));
       
   125 
       
   126         foreach ($serviceIds as $serviceId) {
       
   127             $definition = $this->resolveServiceDefinition($serviceId);
       
   128 
       
   129             if ($definition instanceof Definition) {
       
   130                 $output->writeln(sprintf($format, $serviceId, $definition->getScope(), $definition->getClass()));
       
   131             } elseif ($definition instanceof Alias) {
       
   132                 $alias = $definition;
       
   133                 $output->writeln(sprintf($format, $serviceId, 'n/a', sprintf('<comment>alias for</comment> <info>%s</info>', (string) $alias)));
       
   134             } else {
       
   135                 // we have no information (happens with "service_container")
       
   136                 $service = $definition;
       
   137                 $output->writeln(sprintf($format, $serviceId, '', get_class($service)));
       
   138             }
       
   139         }
       
   140     }
       
   141 
       
   142     /**
       
   143      * Renders detailed service information about one service
       
   144      */
       
   145     protected function outputService(OutputInterface $output, $serviceId)
       
   146     {
       
   147         $definition = $this->resolveServiceDefinition($serviceId);
       
   148 
       
   149         $label = sprintf('Information for service <info>%s</info>', $serviceId);
       
   150         $output->writeln($this->getHelper('formatter')->formatSection('container', $label));
       
   151         $output->writeln('');
       
   152 
       
   153         if ($definition instanceof Definition) {
       
   154             $output->writeln(sprintf('<comment>Service Id</comment>   %s', $serviceId));
       
   155             $output->writeln(sprintf('<comment>Class</comment>        %s', $definition->getClass()));
       
   156 
       
   157             $tags = $definition->getTags() ? implode(', ', array_keys($definition->getTags())) : '-';
       
   158             $output->writeln(sprintf('<comment>Tags</comment>         %s', $tags));
       
   159 
       
   160             $output->writeln(sprintf('<comment>Scope</comment>        %s', $definition->getScope()));
       
   161 
       
   162             $public = $definition->isPublic() ? 'yes' : 'no';
       
   163             $output->writeln(sprintf('<comment>Public</comment>       %s', $public));
       
   164         } elseif ($definition instanceof Alias) {
       
   165             $alias = $definition;
       
   166             $output->writeln(sprintf('This service is an alias for the service <info>%s</info>', (string) $alias));
       
   167         } else {
       
   168             // edge case (but true for "service_container", all we have is the service itself
       
   169             $service = $definition;
       
   170             $output->writeln(sprintf('<comment>Service Id</comment>   %s', $serviceId));
       
   171             $output->writeln(sprintf('<comment>Class</comment>        %s', get_class($service)));
       
   172         }
       
   173     }
       
   174 
       
   175     /**
       
   176      * Loads the ContainerBuilder from the cache.
       
   177      *
       
   178      * @return ContainerBuilder
       
   179      */
       
   180     private function getContainerBuilder()
       
   181     {
       
   182         if (!$this->getApplication()->getKernel()->isDebug()) {
       
   183             throw new \LogicException(sprintf('Debug information about the container is only available in debug mode.'));
       
   184         }
       
   185 
       
   186         if (!file_exists($cachedFile = $this->getContainer()->getParameter('debug.container.dump'))) {
       
   187             throw new \LogicException(sprintf('Debug information about the container could not be found. Please clear the cache and try again.'));
       
   188         }
       
   189 
       
   190         $container = new ContainerBuilder();
       
   191 
       
   192         $loader = new XmlFileLoader($container, new FileLocator());
       
   193         $loader->load($cachedFile);
       
   194 
       
   195         return $container;
       
   196     }
       
   197 
       
   198     /**
       
   199      * Given an array of service IDs, this returns the array of corresponding
       
   200      * Definition and Alias objects that those ids represent.
       
   201      *
       
   202      * @param string $serviceId The service id to resolve
       
   203      * @return \Symfony\Component\DependencyInjection\Definition|\Symfony\Component\DependencyInjection\Alias
       
   204      */
       
   205     private function resolveServiceDefinition($serviceId)
       
   206     {
       
   207         if ($this->containerBuilder->hasDefinition($serviceId)) {
       
   208             return $this->containerBuilder->getDefinition($serviceId);
       
   209         }
       
   210 
       
   211         // Some service IDs don't have a Definition, they're simply an Alias
       
   212         if ($this->containerBuilder->hasAlias($serviceId)) {
       
   213             return $this->containerBuilder->getAlias($serviceId);
       
   214         }
       
   215 
       
   216         // the service has been injected in some special way, just return the service
       
   217         return $this->containerBuilder->get($serviceId);
       
   218     }
       
   219 }