[ Index ]

PHP Cross Reference of phpBB-3.2.11-deutsch

title

Body

[close]

/vendor/symfony/twig-bridge/Command/ -> LintCommand.php (source)

   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  }


Generated: Wed Nov 11 20:33:01 2020 Cross-referenced by PHPXref 0.7.1