vendor/symfony/routing/Loader/AnnotationFileLoader.php line 59

Open in your IDE?
  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\Routing\Loader;
  11. use Symfony\Component\Config\FileLocatorInterface;
  12. use Symfony\Component\Config\Loader\FileLoader;
  13. use Symfony\Component\Config\Resource\FileResource;
  14. use Symfony\Component\Routing\RouteCollection;
  15. /**
  16.  * AnnotationFileLoader loads routing information from annotations set
  17.  * on a PHP class and its methods.
  18.  *
  19.  * @author Fabien Potencier <fabien@symfony.com>
  20.  */
  21. class AnnotationFileLoader extends FileLoader
  22. {
  23.     protected $loader;
  24.     /**
  25.      * @throws \RuntimeException
  26.      */
  27.     public function __construct(FileLocatorInterface $locatorAnnotationClassLoader $loader)
  28.     {
  29.         if (!\function_exists('token_get_all')) {
  30.             throw new \LogicException('The Tokenizer extension is required for the routing annotation loaders.');
  31.         }
  32.         parent::__construct($locator);
  33.         $this->loader $loader;
  34.     }
  35.     /**
  36.      * Loads from annotations from a file.
  37.      *
  38.      * @param string      $file A PHP file path
  39.      * @param string|null $type The resource type
  40.      *
  41.      * @return RouteCollection|null A RouteCollection instance
  42.      *
  43.      * @throws \InvalidArgumentException When the file does not exist or its routes cannot be parsed
  44.      */
  45.     public function load($file$type null)
  46.     {
  47.         $path $this->locator->locate($file);
  48.         $collection = new RouteCollection();
  49.         if ($class $this->findClass($path)) {
  50.             $refl = new \ReflectionClass($class);
  51.             if ($refl->isAbstract()) {
  52.                 return null;
  53.             }
  54.             $collection->addResource(new FileResource($path));
  55.             $collection->addCollection($this->loader->load($class$type));
  56.         }
  57.         gc_mem_caches();
  58.         return $collection;
  59.     }
  60.     /**
  61.      * {@inheritdoc}
  62.      */
  63.     public function supports($resource$type null)
  64.     {
  65.         return \is_string($resource) && 'php' === pathinfo($resourcePATHINFO_EXTENSION) && (!$type || 'annotation' === $type);
  66.     }
  67.     /**
  68.      * Returns the full class name for the first class in the file.
  69.      *
  70.      * @param string $file A PHP file path
  71.      *
  72.      * @return string|false Full class name if found, false otherwise
  73.      */
  74.     protected function findClass($file)
  75.     {
  76.         $class false;
  77.         $namespace false;
  78.         $tokens token_get_all(file_get_contents($file));
  79.         if (=== \count($tokens) && T_INLINE_HTML === $tokens[0][0]) {
  80.             throw new \InvalidArgumentException(sprintf('The file "%s" does not contain PHP code. Did you forgot to add the "<?php" start tag at the beginning of the file?'$file));
  81.         }
  82.         for ($i 0; isset($tokens[$i]); ++$i) {
  83.             $token $tokens[$i];
  84.             if (!isset($token[1])) {
  85.                 continue;
  86.             }
  87.             if (true === $class && T_STRING === $token[0]) {
  88.                 return $namespace.'\\'.$token[1];
  89.             }
  90.             if (true === $namespace && T_STRING === $token[0]) {
  91.                 $namespace $token[1];
  92.                 while (isset($tokens[++$i][1]) && \in_array($tokens[$i][0], [T_NS_SEPARATORT_STRING])) {
  93.                     $namespace .= $tokens[$i][1];
  94.                 }
  95.                 $token $tokens[$i];
  96.             }
  97.             if (T_CLASS === $token[0]) {
  98.                 // Skip usage of ::class constant and anonymous classes
  99.                 $skipClassToken false;
  100.                 for ($j $i 1$j 0; --$j) {
  101.                     if (!isset($tokens[$j][1])) {
  102.                         break;
  103.                     }
  104.                     if (T_DOUBLE_COLON === $tokens[$j][0] || T_NEW === $tokens[$j][0]) {
  105.                         $skipClassToken true;
  106.                         break;
  107.                     } elseif (!\in_array($tokens[$j][0], [T_WHITESPACET_DOC_COMMENTT_COMMENT])) {
  108.                         break;
  109.                     }
  110.                 }
  111.                 if (!$skipClassToken) {
  112.                     $class true;
  113.                 }
  114.             }
  115.             if (T_NAMESPACE === $token[0]) {
  116.                 $namespace true;
  117.             }
  118.         }
  119.         return false;
  120.     }
  121. }