5 * Contains \Drupal\Console\Command\ContainerDebugCommand.
8 namespace Drupal\Console\Command\Debug;
10 use Symfony\Component\Console\Input\InputInterface;
11 use Symfony\Component\Console\Output\OutputInterface;
12 use Symfony\Component\Console\Input\InputArgument;
13 use Symfony\Component\Console\Input\InputOption;
14 use Drupal\Console\Core\Command\ContainerAwareCommand;
15 use Symfony\Component\Yaml\Yaml;
18 * Class ContainerCommand
20 * @package Drupal\Console\Command\Debug
22 class ContainerCommand extends ContainerAwareCommand
27 protected function configure()
30 ->setName('debug:container')
31 ->setDescription($this->trans('commands.debug.container.description'))
35 InputOption::VALUE_NONE,
36 $this->trans('commands.debug.container.arguments.service')
40 InputArgument::OPTIONAL,
41 $this->trans('commands.debug.container.arguments.service')
44 InputArgument::OPTIONAL,
45 $this->trans('commands.debug.container.arguments.method')
48 InputArgument::OPTIONAL,
49 $this->trans('commands.debug.container.arguments.arguments')
53 InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL,
54 $this->trans('commands.debug.container.options.tag')
56 ->setAliases(['dco']);
62 protected function execute(InputInterface $input, OutputInterface $output)
64 $service = $input->getArgument('service');
65 $parameters = $input->getOption('parameters');
66 $tag = $input->getOption('tag');
67 $method = $input->getArgument('method');
68 $args = $input->getArgument('arguments');
71 $parameterList = $this->getParameterList();
72 ksort($parameterList);
73 $this->getIo()->write(Yaml::dump(['parameters' => $parameterList], 4, 2));
80 $callbackRow = $this->getCallbackReturnList($service, $method, $args);
81 $this->getIo()->table($tableHeader, $callbackRow, 'compact');
87 $tableRows = $this->getServiceDetail($service);
88 $this->getIo()->table($tableHeader, $tableRows, 'compact');
94 $this->trans('commands.debug.container.messages.service-id'),
95 $this->trans('commands.debug.container.messages.class-name')
97 $tableRows = $this->getServiceList($tag);
98 $this->getIo()->table($tableHeader, $tableRows, 'compact');
104 private function getCallbackReturnList($service, $method, $args)
107 $parsedArgs = json_decode($args, true);
108 if (!is_array($parsedArgs)) {
109 $parsedArgs = explode(",", $args);
114 $serviceInstance = \Drupal::service($service);
116 if (!method_exists($serviceInstance, $method)) {
117 throw new \Symfony\Component\DependencyInjection\Exception\BadMethodCallException($this->trans('commands.debug.container.errors.method-not-exists'));
119 return $serviceDetail;
122 '<fg=green>'.$this->trans('commands.debug.container.messages.service').'</>',
123 '<fg=yellow>'.$service.'</>'
126 '<fg=green>'.$this->trans('commands.debug.container.messages.class').'</>',
127 '<fg=yellow>'.get_class($serviceInstance).'</>'
129 $methods = [$method];
130 $this->extendArgumentList($serviceInstance, $methods);
132 '<fg=green>'.$this->trans('commands.debug.container.messages.method').'</>',
133 '<fg=yellow>'.$methods[0].'</>'
137 '<fg=green>'.$this->trans('commands.debug.container.messages.arguments').'</>',
138 json_encode($parsedArgs, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
141 $return = call_user_func_array([$serviceInstance,$method], $parsedArgs);
143 '<fg=green>'.$this->trans('commands.debug.container.messages.return').'</>',
144 json_encode($return, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
146 return $serviceDetail;
149 private function getServiceList($tag)
152 return $this->getServiceListByTag($tag);
156 $serviceDefinitions = $this->container->getDefinitions();
158 foreach ($serviceDefinitions as $serviceId => $serviceDefinition) {
159 $services[] = [$serviceId, $serviceDefinition->getClass()];
161 usort($services, [$this, 'compareService']);
165 private function getServiceListByTag($tag)
169 $serviceDefinitions = $this->container->getDefinitions();
171 foreach ($tag as $tagId) {
172 $serviceIds = array_merge(
174 array_keys($this->container->findTaggedServiceIds($tagId))
178 foreach ($serviceIds as $serviceId) {
179 $serviceDefinition = $serviceDefinitions[$serviceId];
180 if ($serviceDefinition) {
181 $services[] = [$serviceId, $serviceDefinition->getClass()];
185 usort($services, [$this, 'compareService']);
189 private function compareService($a, $b)
191 return strcmp($a[0], $b[0]);
194 private function getServiceDetail($service)
196 $serviceInstance = $this->get($service);
199 if ($serviceInstance) {
201 '<fg=green>'.$this->trans('commands.debug.container.messages.service').'</>',
202 '<fg=yellow>'.$service.'</>'
205 '<fg=green>'.$this->trans('commands.debug.container.messages.class').'</>',
206 '<fg=yellow>'.get_class($serviceInstance).'</>'
208 $interface = str_replace("{ }", "", Yaml::dump(class_implements($serviceInstance)));
209 if (!empty($interface)) {
211 '<fg=green>'.$this->trans('commands.debug.container.messages.interface').'</>',
212 '<fg=yellow>'.$interface.'</>'
215 if ($parent = get_parent_class($serviceInstance)) {
217 '<fg=green>'.$this->trans('commands.debug.container.messages.parent').'</>',
218 '<fg=yellow>'.$parent.'</>'
221 if ($vars = get_class_vars($serviceInstance)) {
223 '<fg=green>'.$this->trans('commands.debug.container.messages.variables').'</>',
224 '<fg=yellow>'.Yaml::dump($vars).'</>'
227 if ($methods = get_class_methods($serviceInstance)) {
229 $this->extendArgumentList($serviceInstance, $methods);
231 '<fg=green>'.$this->trans('commands.debug.container.messages.methods').'</>',
232 '<fg=yellow>'.implode("\n", $methods).'</>'
236 throw new \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException($service);
238 return $serviceDetail;
241 return $serviceDetail;
243 private function extendArgumentList($serviceInstance, &$methods)
245 foreach ($methods as $k => $m) {
246 $reflection = new \ReflectionMethod($serviceInstance, $m);
247 $params = $reflection->getParameters();
250 for ($i = 0; $i < count($params); $i++) {
251 if ($params[$i]->isDefaultValueAvailable()) {
252 $defaultVar = $params[$i]->getDefaultValue();
253 $defaultVar = " = <fg=magenta>".str_replace(["\n","array ("], ["", "array("], var_export($def, true)).'</>';
257 if (method_exists($params[$i], 'hasType') && method_exists($params[$i], 'getType')) {
258 if ($params[$i]->hasType()) {
259 $defaultType = '<fg=white>'.strval($params[$i]->getType()).'</> ';
266 if ($params[$i]->isPassedByReference()) {
267 $parameterReference = '<fg=yellow>&</>';
269 $parameterReference = '';
271 $p[] = $defaultType.$parameterReference.'<fg=red>'.'$</><fg=red>'.$params[$i]->getName().'</>'.$defaultVar;
273 if ($reflection->isPublic()) {
274 $methods[$k] = '<fg=cyan>'.$methods[$k]."</><fg=blue>(</>".implode(', ', $p)."<fg=blue>) </> ";
279 private function getParameterList()
281 $parameters = array_filter(
282 $this->container->getParameterBag()->all(), function ($name) {
283 if (preg_match('/^container\./', $name)) {
286 if (preg_match('/^drupal\./', $name)) {
289 if (preg_match('/^console\./', $name)) {
293 }, ARRAY_FILTER_USE_KEY