11
11
12
12
namespace Symfony \Bridge \Twig \Command ;
13
13
14
+ if (!defined ('JSON_PRETTY_PRINT ' )) {
15
+ define ('JSON_PRETTY_PRINT ' , 128 );
16
+ }
17
+
14
18
use Symfony \Component \Console \Command \Command ;
15
19
use Symfony \Component \Console \Input \InputInterface ;
20
+ use Symfony \Component \Console \Input \InputOption ;
16
21
use Symfony \Component \Console \Output \OutputInterface ;
17
22
use Symfony \Component \Finder \Finder ;
18
23
@@ -56,23 +61,24 @@ protected function configure()
56
61
{
57
62
$ this
58
63
->setDescription ('Lints a template and outputs encountered errors ' )
64
+ ->addOption ('format ' , null , InputOption::VALUE_REQUIRED , 'The output format ' , 'txt ' )
59
65
->addArgument ('filename ' )
60
66
->setHelp (<<<EOF
61
- The <info>%command.name%</info> command lints a template and outputs to stdout
67
+ The <info>%command.name%</info> command lints a template and outputs to STDOUT
62
68
the first encountered syntax error.
63
69
70
+ You can validate the syntax of a file:
71
+
64
72
<info>php %command.full_name% filename</info>
65
73
66
- The command gets the contents of <comment>filename</comment> and validates its syntax.
74
+ Or of a whole directory:
67
75
68
76
<info>php %command.full_name% dirname</info>
77
+ <info>php %command.full_name% dirname --format=json</info>
69
78
70
- The command finds all twig templates in <comment>dirname</comment> and validates the syntax
71
- of each Twig template.
79
+ You can also pass the template contents from STDIN:
72
80
73
81
<info>cat filename | php %command.full_name%</info>
74
-
75
- The command gets the template contents from stdin and validates its syntax.
76
82
EOF
77
83
)
78
84
;
@@ -81,29 +87,27 @@ protected function configure()
81
87
protected function execute (InputInterface $ input , OutputInterface $ output )
82
88
{
83
89
$ twig = $ this ->getTwigEnvironment ();
84
- $ template = null ;
85
90
$ filename = $ input ->getArgument ('filename ' );
86
91
87
92
if (!$ filename ) {
88
93
if (0 !== ftell (STDIN )) {
89
- throw new \RuntimeException ("Please provide a filename or pipe template content to stdin . " );
94
+ throw new \RuntimeException ("Please provide a filename or pipe template content to STDIN . " );
90
95
}
91
96
97
+ $ template = '' ;
92
98
while (!feof (STDIN )) {
93
99
$ template .= fread (STDIN , 1024 );
94
100
}
95
101
96
- return $ this ->validateTemplate ( $ twig , $ output , $ template );
102
+ return $ this ->display ( $ inp
3419
ut , $ output , array ( $ this -> validate ( $ twig , $ template)) );
97
103
}
98
104
99
- $ files = $ this ->findFiles ($ filename );
100
-
101
- $ errors = 0 ;
102
- foreach ($ files as $ file ) {
103
- $ errors += $ this ->validateTemplate ($ twig , $ output , file_get_contents ($ file ), $ file );
105
+ $ filesInfo = array ();
106
+ foreach ($ this ->findFiles ($ filename ) as $ file ) {
107
+ $ filesInfo [] = $ this ->validate ($ twig , file_get_contents ($ file ), $ file );
104
108
}
105
109
106
- return $ errors > 0 ? 1 : 0 ;
110
+ return $ this -> display ( $ input , $ output , $ filesInfo ) ;
107
111
}
108
112
109
113
protected function findFiles ($ filename )
@@ -117,32 +121,77 @@ protected function findFiles($filename)
117
121
throw new \RuntimeException (sprintf ('File or directory "%s" is not readable ' , $ filename ));
118
122
}
119
123
120
- protected function validateTemplate (\Twig_Environment $ twig, OutputInterface $ output , $ template , $ file = null )
124
+ private function validate (\Twig_Environment $ twig , $ template , $ file = null )
121
125
{
122
126
try {
123
127
$ twig ->parse ($ twig ->tokenize ($ template , $ file ? (string ) $ file : null ));
124
- $ output ->writeln ('<info>OK</info> ' .($ file ? sprintf (' in %s ' , $ file ) : '' ));
125
128
} catch (\Twig_Error $ e ) {
126
- $ this ->renderException ($ output , $ template , $ e , $ file );
129
+ return array ('template ' => $ template , 'file ' => $ file , 'valid ' => false , 'exception ' => $ e );
130
+ }
131
+
132
+ return array ('template ' => $ template , 'file ' => $ file , 'valid ' => true );
133
+ }
134
+
135
+ private function display (InputInterface $ input , OutputInterface $ output , $ files )
136
+ {
137
+ switch ($ input ->getOption ('format ' )) {
138
+ case 'txt ' :
139
+ return $ this ->displayTxt ($ output , $ files );
140
+ case 'json ' :
141
+ return $ this ->displayJson ($ output , $ files );
142
+ default :
143
+ throw new \InvalidArgumentException (sprintf ('The format "%s" is not supported. ' , $ input ->getOption ('format ' )));
144
+ }
145
+ }
127
146
128
- return 1 ;
147
+ private function displayTxt (OutputInterface $ output , $ filesInfo )
148
+ {
149
+ $ errors = 0 ;
150
+
151
+ foreach ($ filesInfo as $ info ) {
152
+ if ($ info ['valid ' ] && $ output ->isVerbose ()) {
153
+ $ output ->writeln ('<info>OK</info> ' .($ info ['file ' ] ? sprintf (' in %s ' , $ info ['file ' ]) : '' ));
154
+ } elseif (!$ info ['valid ' ]) {
155
+ $ errors ++;
156
+ $ this ->renderException ($ output , $ info ['template ' ], $ info ['exception ' ], $ info ['file ' ]);
157
+ }
129
158
}
130
159
131
- return 0 ;
160
+ $ output ->writeln (sprintf ('<comment>%d/%d valid files</comment> ' , count ($ filesInfo ) - $ errors , count ($ filesInfo )));
161
+
162
+ return min ($ errors , 1 );
163
+ }
164
+
165
+ private function displayJson (OutputInterface $ output , $ filesInfo )
166
+ {
167
+ $ errors = 0 ;
168
+
169
+ array_walk ($ filesInfo , function (&$ v ) use (&$ errors ) {
170
+ $ v ['file ' ] = (string ) $ v ['file ' ];
171
+ unset($ v ['template ' ]);
172
+ if (!$ v ['valid ' ]) {
173
+ $ v ['message ' ] = $ v ['exception ' ]->getMessage ();
174
+ unset($ v ['exception ' ]);
175
+ $ errors ++;
176
+ }
177
+ });
178
+
179
+ $ output ->writeln (json_encode ($ filesInfo , JSON_PRETTY_PRINT ));
180
+
181
+ return min ($ errors , 1 );
132
182
}
133
183
134
- protected function renderException (OutputInterface $ output , $ template , \Twig_Error $ exception , $ file = null )
184
+ private function renderException (OutputInterface $ output , $ template , \Twig_Error $ exception , $ file = null )
135
185
{
136
186
$ line = $ exception ->getTemplateLine ();
137
- $ lines = $ this ->getContext ($ template , $ line );
138
187
139
188
if ($ file ) {
140
189
$ output ->writeln (sprintf ("<error>KO</error> in %s (line %s) " , $ file , $ line ));
141
190
} else {
142
191
$ output ->writeln (sprintf ("<error>KO</error> (line %s) " , $ line ));
143
192
}
144
193
145
- foreach ($ lines as $ no => $ code ) {
194
+ foreach ($ this -> getContext ( $ template , $ line ) as $ no => $ code ) {
146
195
$ output ->writeln (sprintf (
147
196
"%s %-6s %s " ,
148
197
$ no == $ line ? '<error>>></error> ' : ' ' ,
@@ -155,7 +204,7 @@ protected function renderException(OutputInterface $output, $template, \Twig_Err
155
204
}
156
205
}
157
206
158
- protected function getContext ($ template , $ line , $ context = 3 )
207
+ private function getContext ($ template , $ line , $ context = 3 )
159
208
{
160
209
$ lines = explode ("\n" , $ template );
161
210
0 commit comments