PhpAstExtractor.php 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Translation\Extractor;
  11. use PhpParser\NodeTraverser;
  12. use PhpParser\NodeVisitor;
  13. use PhpParser\Parser;
  14. use PhpParser\ParserFactory;
  15. use Symfony\Component\Finder\Finder;
  16. use Symfony\Component\Translation\Extractor\Visitor\AbstractVisitor;
  17. use Symfony\Component\Translation\MessageCatalogue;
  18. /**
  19. * PhpAstExtractor extracts translation messages from a PHP AST.
  20. *
  21. * @author Mathieu Santostefano <msantostefano@protonmail.com>
  22. */
  23. final class PhpAstExtractor extends AbstractFileExtractor implements ExtractorInterface
  24. {
  25. private Parser $parser;
  26. public function __construct(
  27. /**
  28. * @param iterable<AbstractVisitor&NodeVisitor> $visitors
  29. */
  30. private readonly iterable $visitors,
  31. private string $prefix = '',
  32. ) {
  33. if (!class_exists(ParserFactory::class)) {
  34. throw new \LogicException(sprintf('You cannot use "%s" as the "nikic/php-parser" package is not installed. Try running "composer require nikic/php-parser".', static::class));
  35. }
  36. $this->parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
  37. }
  38. public function extract(iterable|string $resource, MessageCatalogue $catalogue): void
  39. {
  40. foreach ($this->extractFiles($resource) as $file) {
  41. $traverser = new NodeTraverser();
  42. /** @var AbstractVisitor&NodeVisitor $visitor */
  43. foreach ($this->visitors as $visitor) {
  44. $visitor->initialize($catalogue, $file, $this->prefix);
  45. $traverser->addVisitor($visitor);
  46. }
  47. $nodes = $this->parser->parse(file_get_contents($file));
  48. $traverser->traverse($nodes);
  49. }
  50. }
  51. public function setPrefix(string $prefix): void
  52. {
  53. $this->prefix = $prefix;
  54. }
  55. protected function canBeExtracted(string $file): bool
  56. {
  57. return 'php' === pathinfo($file, \PATHINFO_EXTENSION) && $this->isFile($file);
  58. }
  59. protected function extractFromDirectory(array|string $resource): iterable|Finder
  60. {
  61. if (!class_exists(Finder::class)) {
  62. throw new \LogicException(sprintf('You cannot use "%s" as the "symfony/finder" package is not installed. Try running "composer require symfony/finder".', static::class));
  63. }
  64. return (new Finder())->files()->name('*.php')->in($resource);
  65. }
  66. }