[ Index ] |
PHP Cross Reference of phpBB-3.3.14-deutsch |
[Summary view] [Print] [Text view]
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\Exception\InvalidArgumentException; 16 use Symfony\Component\Console\Exception\RuntimeException; 17 use Symfony\Component\Console\Input\InputArgument; 18 use Symfony\Component\Console\Input\InputInterface; 19 use Symfony\Component\Console\Input\InputOption; 20 use Symfony\Component\Console\Output\OutputInterface; 21 use Symfony\Component\Console\Style\SymfonyStyle; 22 use Symfony\Component\Finder\Finder; 23 use Twig\Environment; 24 use Twig\Error\Error; 25 use Twig\Loader\ArrayLoader; 26 use Twig\Source; 27 28 /** 29 * Command that will validate your template syntax and output encountered errors. 30 * 31 * @author Marc Weistroff <marc.weistroff@sensiolabs.com> 32 * @author Jérôme Tamarelle <jerome@tamarelle.net> 33 */ 34 class LintCommand extends Command 35 { 36 protected static $defaultName = 'lint:twig'; 37 38 private $twig; 39 40 /** 41 * @param Environment $twig 42 */ 43 public function __construct($twig = null) 44 { 45 if (!$twig instanceof Environment) { 46 @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); 47 48 parent::__construct($twig); 49 50 return; 51 } 52 53 parent::__construct(); 54 55 $this->twig = $twig; 56 } 57 58 public function setTwigEnvironment(Environment $twig) 59 { 60 @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.4 and will be removed in 4.0.', __METHOD__), \E_USER_DEPRECATED); 61 62 $this->twig = $twig; 63 } 64 65 /** 66 * @return Environment $twig 67 */ 68 protected function getTwigEnvironment() 69 { 70 @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.4 and will be removed in 4.0.', __METHOD__), \E_USER_DEPRECATED); 71 72 return $this->twig; 73 } 74 75 protected function configure() 76 { 77 $this 78 ->setDescription('Lints a template and outputs encountered errors') 79 ->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt') 80 ->addArgument('filename', InputArgument::IS_ARRAY) 81 ->setHelp(<<<'EOF' 82 The <info>%command.name%</info> command lints a template and outputs to STDOUT 83 the first encountered syntax error. 84 85 You can validate the syntax of contents passed from STDIN: 86 87 <info>cat filename | php %command.full_name%</info> 88 89 Or the syntax of a file: 90 91 <info>php %command.full_name% filename</info> 92 93 Or of a whole directory: 94 95 <info>php %command.full_name% dirname</info> 96 <info>php %command.full_name% dirname --format=json</info> 97 98 EOF 99 ) 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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Nov 25 19:05:08 2024 | Cross-referenced by PHPXref 0.7.1 |