Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 7d61154

Browse filesBrowse files
Seldaekfabpot
authored andcommitted
Add command to list twig functions, filters, globals and tests
1 parent caabd41 commit 7d61154
Copy full SHA for 7d61154

File tree

Expand file treeCollapse file tree

1 file changed

+187
-0
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

1 file changed

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

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.