8000 moved the logic from debug:twig to the Twig bridge · symfony/symfony@bd01a29 · GitHub
[go: up one dir, main page]

Skip to content

Commit bd01a29

Browse files
committed
moved the logic from debug:twig to the Twig bridge
1 parent c7ae71d commit bd01a29

File tree

2 files changed

+239
-156
lines changed

2 files changed

+239
-156
lines changed
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
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\Bridge\Twig\Command;
13+
14+
use Symfony\Component\Console\Command\Command;
15+
use Symfony\Component\Console\Input\InputArgument;
16+
use Symfony\Component\Console\Input\InputOption;
17+
use Symfony\Component\Console\Input\InputInterface;
18+
use Symfony\Component\Console\Output\OutputInterface;
19+
20+
/**
21+
* Lists twig functions, filters, globals and tests present in the current project
22+
*
23+
* @author Jordi Boggiano <j.boggiano@seld.be>
24+
*/
25+
class DebugCommand extends Command
26+
{
27+
private $twig;
28+
29+
/**
30+
* {@inheritdoc}
31+
*/
32+
public function __construct($name = 'debug:twig')
33+
{
34+
parent::__construct($name);
35+
}
36+
37+
/**
38+
* Sets the twig environment
39+
*
40+
* @param \Twig_Environment $twig
41+
*/
42+
public function setTwigEnvironment(\Twig_Environment $twig)
43+
{
44+
$this->twig = $twig;
45+
}
46+
47+
/**
48+
* @return \Twig_Environment $twig
49+
*/
50+
protected function getTwigEnvironment()
51+
{
52+
return $this->twig;
53+
}
54+
55+
protected function configure()
56+
{
57+
$this
58+
->setDefinition(array(
59+
new InputArgument('filter', InputArgument::OPTIONAL, 'Show details for all entries matching this filter'),
60+
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'Output format: text or json', 'text'),
61+
))
62+
->setDescription('Shows a list of twig functions, filters, globals and tests')
63+
->setHelp(<<<EOF
64+
The <info>%command.name%</info> command outputs a list of twig functions,
65+
filters, globals and tests. Output can be filtered with an optional argument.
66+
67+
<info>php %command.full_name%</info>
68+
69+
The command lists all functions, filters, etc.
70+
71+
<info>php %command.full_name% date</info>
72+
73+
The command lists everything that contains the word date.
74+
75+
<info>php %command.full_name% --format=json</info>
76+
77+
The command lists everything in a machine readable json format.
78+
EOF
79+
)
80+
;
81+
}
82+
83+
protected function execute(InputInterface $input, OutputInterface $output)
84+
{
85+
$twig = $this->getTwigEnvironment();
86+
$types = array('functions', 'filters', 'tests', 'globals');
87+
88+
if ($input->getOption('format') === 'json') {
89+
$data = array();
90+
foreach ($types as $type) {
91+
foreach ($twig->{'get'.ucfirst($type)}() as $name => $entity) {
92+
$data[$type][$name] = $this->getMetadata($type, $entity);
93+
}
94+
}
95+
$data['tests'] = array_keys($data['tests']);
96+
$output->writeln(json_encode($data));
97+
98+
return 0;
99+
}
100+
101+
$filter = $input->getArgument('filter');
102+
103+
foreach ($types as $index => $type) {
104+
$items = array();
105+
foreach ($twig->{'get'.ucfirst($type)}() as $name => $entity) {
106+
if (!$filter || false !== strpos($name, $filter)) {
107+
$items[$name] = $name.$this->getPrettyMetadata($type, $entity);
108+
}
109+
}
110+
111+
if (!$items) {
112+
continue;
113+
}
114+
if ($index > 0) {
115+
$output->writeln('');
116+
}
117+
$output->writeln('<info>'.ucfirst($type).'</info>');
118+
ksort($items);
119+
foreach ($items as $item) {
120+
$output->writeln(' '.$item);
121+
}
122+
}
123+
124+
return 0;
125+
}
126+
127+
private function getMetadata($type, $entity)
128+
{
129+
if ($type === 'globals') {
130+
return $entity;
131+
}
132+
if ($type === 'tests') {
133+
return;
134+
}
135+
if ($type === 'functions' || $type === 'filters') {
136+
$args = array();
137+
$cb = $entity->getCallable();
138+
if (is_null($cb)) {
139+
return;
140+
}
141+
if (is_array($cb)) {
142+
if (!method_exists($cb[0], $cb[1])) {
143+
return;
144+
}
145+
$refl = new \ReflectionMethod($cb[0], $cb[1]);
146+
} elseif (is_object($cb) && is_callable($cb)) {
147+
$refl = new \ReflectionMethod($cb, '__invoke');
148+
} elseif (function_exists($cb)) {
149+
$refl = new \ReflectionFunction($cb);
150+
} elseif (is_string($cb) && preg_match('{^(.+)::(.+)$}', $cb, $m) && method_exists($m[1], $m[2])) {
151+
$refl = new \ReflectionMethod($m[1], $m[2]);
152+
} else {
153+
throw new \UnexpectedValueException('Unsupported callback type');
154+
}
155+
156+
// filter out context/environment args
157+
$args = array_filter($refl->getParameters(), function ($param) use ($entity) {
158+
if ($entity->needsContext() && $param->getName() === 'context') {
159+
return false;
160+
}
161+
162+
return !$param->getClass() || $param->getClass()->getName() !== 'Twig_Environment';
163+
});
164+
165+
// format args
166+
$args = array_map(function ($param) {
167+
if ($param->isDefaultValueAvailable()) {
168+
return $param->getName().' = '.json_encode($param->getDefaultValue());
169+
}
170+
171+
return $param->getName();
172+
}, $args);
173+
174+
if ($type === 'filters') {
175+
// remove the value the filter is applied on
176+
array_shift($args);
177+
}
178+
179+
return $args;
180+
}
181+
}
182+
183+
private function getPrettyMetadata($type, $entity)
184+
{
185+
if ($type === 'tests') {
186+
return '';
187+
}
188+
189+
try {
190+
$meta = $this->getMetadata($type, $entity);
191+
if ($meta === null) {
192+
return '(unknown?)';
193+
}
194+
} catch (\UnexpectedValueException $e) {
195+
return ' <error>'.$e->getMessage().'</error>';
196+
}
197+
198+
if ($type === 'globals') {
199+
if (is_object($meta)) {
200+
return ' = object('.get_class($meta).')';
201+
}
202+
203+
return ' = '.substr(@json_encode($meta), 0, 50);
204+
}
205+
206+
if ($type === 'functions') {
207+
return '('.implode(', ', $meta).')';
208+
}
209+
210+
if ($type === 'filters') {
211+
return $meta ? '('.implode(', ', $meta).')' : '';
212+
}
213+
}
214+
}

0 commit comments

Comments
 (0)
0