[ Index ] |
PHP Cross Reference of phpBB-3.2.11-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\Input\InputArgument; 16 use Symfony\Component\Console\Input\InputInterface; 17 use Symfony\Component\Console\Input\InputOption; 18 use Symfony\Component\Console\Output\OutputInterface; 19 use Symfony\Component\Console\Style\SymfonyStyle; 20 use Symfony\Component\Finder\Finder; 21 use Twig\Environment; 22 use Twig\Error\Error; 23 use Twig\Loader\ArrayLoader; 24 use Twig\Source; 25 26 /** 27 * Command that will validate your template syntax and output encountered errors. 28 * 29 * @author Marc Weistroff <marc.weistroff@sensiolabs.com> 30 * @author Jérôme Tamarelle <jerome@tamarelle.net> 31 */ 32 class LintCommand extends Command 33 { 34 private $twig; 35 36 /** 37 * {@inheritdoc} 38 */ 39 public function __construct($name = 'lint:twig') 40 { 41 parent::__construct($name); 42 } 43 44 public function setTwigEnvironment(Environment $twig) 45 { 46 $this->twig = $twig; 47 } 48 49 /** 50 * @return Environment $twig 51 */ 52 protected function getTwigEnvironment() 53 { 54 return $this->twig; 55 } 56 57 protected function configure() 58 { 59 $this 60 ->setAliases(array('twig:lint')) 61 ->setDescription('Lints a template and outputs encountered errors') 62 ->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt') 63 ->addArgument('filename', InputArgument::IS_ARRAY) 64 ->setHelp(<<<'EOF' 65 The <info>%command.name%</info> command lints a template and outputs to STDOUT 66 the first encountered syntax error. 67 68 You can validate the syntax of contents passed from STDIN: 69 70 <info>cat filename | php %command.full_name%</info> 71 72 Or the syntax of a file: 73 74 <info>php %command.full_name% filename</info> 75 76 Or of a whole directory: 77 78 <info>php %command.full_name% dirname</info> 79 <info>php %command.full_name% dirname --format=json</info> 80 81 EOF 82 ) 83 ; 84 } 85 86 protected function execute(InputInterface $input, OutputInterface $output) 87 { 88 $io = new SymfonyStyle($input, $output); 89 90 if (false !== strpos($input->getFirstArgument(), ':l')) { 91 $io->caution('The use of "twig:lint" command is deprecated since version 2.7 and will be removed in 3.0. Use the "lint:twig" instead.'); 92 } 93 94 if (null === $twig = $this->getTwigEnvironment()) { 95 $io->error('The Twig environment needs to be set.'); 96 97 return 1; 98 } 99 100 $filenames = $input->getArgument('filename'); 101 102 if (0 === \count($filenames)) { 103 if (0 !== ftell(STDIN)) { 104 throw new \RuntimeException('Please provide a filename or pipe template content to STDIN.'); 105 } 106 107 $template = ''; 108 while (!feof(STDIN)) { 109 $template .= fread(STDIN, 1024); 110 } 111 112 return $this->display($input, $output, $io, array($this->validate($twig, $template, uniqid('sf_', true)))); 113 } 114 115 $filesInfo = $this->getFilesInfo($twig, $filenames); 116 117 return $this->display($input, $output, $io, $filesInfo); 118 } 119 120 private function getFilesInfo(Environment $twig, array $filenames) 121 { 122 $filesInfo = array(); 123 foreach ($filenames as $filename) { 124 foreach ($this->findFiles($filename) as $file) { 125 $filesInfo[] = $this->validate($twig, file_get_contents($file), $file); 126 } 127 } 128 129 return $filesInfo; 130 } 131 132 protected function findFiles($filename) 133 { 134 if (is_file($filename)) { 135 return array($filename); 136 } elseif (is_dir($filename)) { 137 return Finder::create()->files()->in($filename)->name('*.twig'); 138 } 139 140 throw new \RuntimeException(sprintf('File or directory "%s" is not readable', $filename)); 141 } 142 143 private function validate(Environment $twig, $template, $file) 144 { 145 $realLoader = $twig->getLoader(); 146 try { 147 $temporaryLoader = new ArrayLoader(array((string) $file => $template)); 148 $twig->setLoader($temporaryLoader); 149 $nodeTree = $twig->parse($twig->tokenize(new Source($template, (string) $file))); 150 $twig->compile($nodeTree); 151 $twig->setLoader($realLoader); 152 } catch (Error $e) { 153 $twig->setLoader($realLoader); 154 155 return array('template' => $template, 'file' => $file, 'valid' => false, 'exception' => $e); 156 } 157 158 return array('template' => $template, 'file' => $file, 'valid' => true); 159 } 160 161 private function display(InputInterface $input, OutputInterface $output, SymfonyStyle $io, $files) 162 { 163 switch ($input->getOption('format')) { 164 case 'txt': 165 return $this->displayTxt($output, $io, $files); 166 case 'json': 167 return $this->displayJson($output, $files); 168 default: 169 throw new \InvalidArgumentException(sprintf('The format "%s" is not supported.', $input->getOption('format'))); 170 } 171 } 172 173 private function displayTxt(OutputInterface $output, SymfonyStyle $io, $filesInfo) 174 { 175 $errors = 0; 176 177 foreach ($filesInfo as $info) { 178 if ($info['valid'] && $output->isVerbose()) { 179 $io->comment('<info>OK</info>'.($info['file'] ? sprintf(' in %s', $info['file']) : '')); 180 } elseif (!$info['valid']) { 181 ++$errors; 182 $this->renderException($io, $info['template'], $info['exception'], $info['file']); 183 } 184 } 185 186 if (0 === $errors) { 187 $io->success(sprintf('All %d Twig files contain valid syntax.', \count($filesInfo))); 188 } else { 189 $io->warning(sprintf('%d Twig files have valid syntax and %d contain errors.', \count($filesInfo) - $errors, $errors)); 190 } 191 192 return min($errors, 1); 193 } 194 195 private function displayJson(OutputInterface $output, $filesInfo) 196 { 197 $errors = 0; 198 199 array_walk($filesInfo, function (&$v) use (&$errors) { 200 $v['file'] = (string) $v['file']; 201 unset($v['template']); 202 if (!$v['valid']) { 203 $v['message'] = $v['exception']->getMessage(); 204 unset($v['exception']); 205 ++$errors; 206 } 207 }); 208 209 $output->writeln(json_encode($filesInfo, \defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES : 0)); 210 211 return min($errors, 1); 212 } 213 214 private function renderException(OutputInterface $output, $template, Error $exception, $file = null) 215 { 216 $line = $exception->getTemplateLine(); 217 218 if ($file) { 219 $output->text(sprintf('<error> ERROR </error> in %s (line %s)', $file, $line)); 220 } else { 221 $output->text(sprintf('<error> ERROR </error> (line %s)', $line)); 222 } 223 224 foreach ($this->getContext($template, $line) as $lineNumber => $code) { 225 $output->text(sprintf( 226 '%s %-6s %s', 227 $lineNumber === $line ? '<error> >> </error>' : ' ', 228 $lineNumber, 229 $code 230 )); 231 if ($lineNumber === $line) { 232 $output->text(sprintf('<error> >> %s</error> ', $exception->getRawMessage())); 233 } 234 } 235 } 236 237 private function getContext($template, $line, $context = 3) 238 { 239 $lines = explode("\n", $template); 240 241 $position = max(0, $line - $context); 242 $max = min(\count($lines), $line - 1 + $context); 243 244 $result = array(); 245 while ($position < $max) { 246 $result[$position + 1] = $lines[$position]; 247 ++$position; 248 } 249 250 return $result; 251 } 252 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 11 20:33:01 2020 | Cross-referenced by PHPXref 0.7.1 |