Verzeichnisstruktur phpBB-3.3.15
- Veröffentlicht
- 28.08.2024
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
LintCommand.php
001 <?php
002
003 /*
004 * This file is part of the Symfony package.
005 *
006 * (c) Fabien Potencier <fabien@symfony.com>
007 *
008 * For the full copyright and license information, please view the LICENSE
009 * file that was distributed with this source code.
010 */
011
012 namespace Symfony\Bridge\Twig\Command;
013
014 use Symfony\Component\Console\Command\Command;
015 use Symfony\Component\Console\Exception\InvalidArgumentException;
016 use Symfony\Component\Console\Exception\RuntimeException;
017 use Symfony\Component\Console\Input\InputArgument;
018 use Symfony\Component\Console\Input\InputInterface;
019 use Symfony\Component\Console\Input\InputOption;
020 use Symfony\Component\Console\Output\OutputInterface;
021 use Symfony\Component\Console\Style\SymfonyStyle;
022 use Symfony\Component\Finder\Finder;
023 use Twig\Environment;
024 use Twig\Error\Error;
025 use Twig\Loader\ArrayLoader;
026 use Twig\Source;
027
028 /**
029 * Command that will validate your template syntax and output encountered errors.
030 *
031 * @author Marc Weistroff <marc.weistroff@sensiolabs.com>
032 * @author Jérôme Tamarelle <jerome@tamarelle.net>
033 */
034 class LintCommand extends Command
035 {
036 protected static $defaultName = 'lint:twig';
037
038 private $twig;
039
040 /**
041 * @param Environment $twig
042 */
043 public function __construct($twig = null)
044 {
045 if (!$twig instanceof Environment) {
046 @trigger_error(sprintf('Passing a command name as the first argument of "%s()" is deprecated since Symfony 3.4 and support for it will be removed in 4.0. If the command was registered by convention, make it a service instead.', __METHOD__), \E_USER_DEPRECATED);
047
048 parent::__construct($twig);
049
050 return;
051 }
052
053 parent::__construct();
054
055 $this->twig = $twig;
056 }
057
058 public function setTwigEnvironment(Environment $twig)
059 {
060 @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.4 and will be removed in 4.0.', __METHOD__), \E_USER_DEPRECATED);
061
062 $this->twig = $twig;
063 }
064
065 /**
066 * @return Environment $twig
067 */
068 protected function getTwigEnvironment()
069 {
070 @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.4 and will be removed in 4.0.', __METHOD__), \E_USER_DEPRECATED);
071
072 return $this->twig;
073 }
074
075 protected function configure()
076 {
077 $this
078 ->setDescription('Lints a template and outputs encountered errors')
079 ->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt')
080 ->addArgument('filename', InputArgument::IS_ARRAY)
081 ->setHelp(<<<'EOF'
082 The <info>%command.name%</info> command lints a template and outputs to STDOUT
083 the first encountered syntax error.
084
085 You can validate the syntax of contents passed from STDIN:
086
087 <info>cat filename | php %command.full_name%</info>
088
089 Or the syntax of a file:
090
091 <info>php %command.full_name% filename</info>
092
093 Or of a whole directory:
094
095 <info>php %command.full_name% dirname</info>
096 <info>php %command.full_name% dirname --format=json</info>
097
098 EOF
099 )
100 ;
101 }
102
103 protected function execute(InputInterface $input, OutputInterface $output)
104 {
105 $io = new SymfonyStyle($input, $output);
106
107 // BC to be removed in 4.0
108 if (__CLASS__ !== static::class) {
109 $r = new \ReflectionMethod($this, 'getTwigEnvironment');
110 if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
111 @trigger_error(sprintf('Usage of method "%s" is deprecated since Symfony 3.4 and will no longer be supported in 4.0. Construct the command with its required arguments instead.', static::class.'::getTwigEnvironment'), \E_USER_DEPRECATED);
112
113 $this->twig = $this->getTwigEnvironment();
114 }
115 }
116 if (null === $this->twig) {
117 throw new \RuntimeException('The Twig environment needs to be set.');
118 }
119
120 $filenames = $input->getArgument('filename');
121
122 if (0 === \count($filenames)) {
123 if (0 !== ftell(\STDIN)) {
124 throw new RuntimeException('Please provide a filename or pipe template content to STDIN.');
125 }
126
127 $template = '';
128 while (!feof(\STDIN)) {
129 $template .= fread(\STDIN, 1024);
130 }
131
132 return $this->display($input, $output, $io, [$this->validate($template, uniqid('sf_', true))]);
133 }
134
135 $filesInfo = $this->getFilesInfo($filenames);
136
137 return $this->display($input, $output, $io, $filesInfo);
138 }
139
140 private function getFilesInfo(array $filenames)
141 {
142 $filesInfo = [];
143 foreach ($filenames as $filename) {
144 foreach ($this->findFiles($filename) as $file) {
145 $filesInfo[] = $this->validate(file_get_contents($file), $file);
146 }
147 }
148
149 return $filesInfo;
150 }
151
152 protected function findFiles($filename)
153 {
154 if (is_file($filename)) {
155 return [$filename];
156 } elseif (is_dir($filename)) {
157 return Finder::create()->files()->in($filename)->name('*.twig');
158 }
159
160 throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
161 }
162
163 private function validate($template, $file)
164 {
165 $realLoader = $this->twig->getLoader();
166 try {
167 $temporaryLoader = new ArrayLoader([(string) $file => $template]);
168 $this->twig->setLoader($temporaryLoader);
169 $nodeTree = $this->twig->parse($this->twig->tokenize(new Source($template, (string) $file)));
170 $this->twig->compile($nodeTree);
171 $this->twig->setLoader($realLoader);
172 } catch (Error $e) {
173 $this->twig->setLoader($realLoader);
174
175 return ['template' => $template, 'file' => $file, 'line' => $e->getTemplateLine(), 'valid' => false, 'exception' => $e];
176 }
177
178 return ['template' => $template, 'file' => $file, 'valid' => true];
179 }
180
181 private function display(InputInterface $input, OutputInterface $output, SymfonyStyle $io, $files)
182 {
183 switch ($input->getOption('format')) {
184 case 'txt':
185 return $this->displayTxt($output, $io, $files);
186 case 'json':
187 return $this->displayJson($output, $files);
188 default:
189 throw new InvalidArgumentException(sprintf('The format "%s" is not supported.', $input->getOption('format')));
190 }
191 }
192
193 private function displayTxt(OutputInterface $output, SymfonyStyle $io, $filesInfo)
194 {
195 $errors = 0;
196
197 foreach ($filesInfo as $info) {
198 if ($info['valid'] && $output->isVerbose()) {
199 $io->comment('<info>OK</info>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
200 } elseif (!$info['valid']) {
201 ++$errors;
202 $this->renderException($io, $info['template'], $info['exception'], $info['file']);
203 }
204 }
205
206 if (0 === $errors) {
207 $io->success(sprintf('All %d Twig files contain valid syntax.', \count($filesInfo)));
208 } else {
209 $io->warning(sprintf('%d Twig files have valid syntax and %d contain errors.', \count($filesInfo) - $errors, $errors));
210 }
211
212 return min($errors, 1);
213 }
214
215 private function displayJson(OutputInterface $output, $filesInfo)
216 {
217 $errors = 0;
218
219 array_walk($filesInfo, function (&$v) use (&$errors) {
220 $v['file'] = (string) $v['file'];
221 unset($v['template']);
222 if (!$v['valid']) {
223 $v['message'] = $v['exception']->getMessage();
224 unset($v['exception']);
225 ++$errors;
226 }
227 });
228
229 $output->writeln(json_encode($filesInfo, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES));
230
231 return min($errors, 1);
232 }
233
234 private function renderException(OutputInterface $output, $template, Error $exception, $file = null)
235 {
236 $line = $exception->getTemplateLine();
237
238 if ($file) {
239 $output->text(sprintf('<error> ERROR </error> in %s (line %s)', $file, $line));
240 } else {
241 $output->text(sprintf('<error> ERROR </error> (line %s)', $line));
242 }
243
244 foreach ($this->getContext($template, $line) as $lineNumber => $code) {
245 $output->text(sprintf(
246 '%s %-6s %s',
247 $lineNumber === $line ? '<error> >> </error>' : ' ',
248 $lineNumber,
249 $code
250 ));
251 if ($lineNumber === $line) {
252 $output->text(sprintf('<error> >> %s</error> ', $exception->getRawMessage()));
253 }
254 }
255 }
256
257 private function getContext($template, $line, $context = 3)
258 {
259 $lines = explode("\n", $template);
260
261 $position = max(0, $line - $context);
262 $max = min(\count($lines), $line - 1 + $context);
263
264 $result = [];
265 while ($position < $max) {
266 $result[$position + 1] = $lines[$position];
267 ++$position;
268 }
269
270 return $result;
271 }
272 }
273