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

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.     public function __construct(FileLocatorInterface $locatorAnnotationClassLoader $loader)
  25.     {
  26.         if (!\function_exists('token_get_all')) {
  27.             throw new \LogicException('The Tokenizer extension is required for the routing annotation loaders.');
  28.         }
  29.         parent::__construct($locator);
  30.         $this->loader $loader;
  31.     }
  32.     /**
  33.      * Loads from annotations from a file.
  34.      *
  35.      * @param string      $file A PHP file path
  36.      * @param string|null $type The resource type
  37.      *
  38.      * @return RouteCollection|null
  39.      *
  40.      * @throws \InvalidArgumentException When the file does not exist or its routes cannot be parsed
  41.      */
  42.     public function load($filestring $type null)
  43.     {
  44.         $path $this->locator->locate($file);
  45.         $collection = new RouteCollection();
  46.         if ($class $this->findClass($path)) {
  47.             $refl = new \ReflectionClass($class);
  48.             if ($refl->isAbstract()) {
  49.                 return null;
  50.             }
  51.             $collection->addResource(new FileResource($path));
  52.             $collection->addCollection($this->loader->load($class$type));
  53.         }
  54.         gc_mem_caches();
  55.         return $collection;
  56.     }
  57.     /**
  58.      * {@inheritdoc}
  59.      */
  60.     public function supports($resourcestring $type null)
  61.     {
  62.         return \is_string($resource) && 'php' === pathinfo($resource\PATHINFO_EXTENSION) && (!$type || 'annotation' === $type);
  63.     }
  64.     /**
  65.      * Returns the full class name for the first class in the file.
  66.      *
  67.      * @return string|false
  68.      */
  69.     protected function findClass(string $file)
  70.     {
  71.         $class false;
  72.         $namespace false;
  73.         $tokens token_get_all(file_get_contents($file));
  74.         if (=== \count($tokens) && \T_INLINE_HTML === $tokens[0][0]) {
  75.             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));
  76.         }
  77.         $nsTokens = [\T_NS_SEPARATOR => true\T_STRING => true];
  78.         if (\defined('T_NAME_QUALIFIED')) {
  79.             $nsTokens[\T_NAME_QUALIFIED] = true;
  80.         }
  81.         for ($i 0; isset($tokens[$i]); ++$i) {
  82.             $token $tokens[$i];
  83.             if (!isset($token[1])) {
  84.                 continue;
  85.             }
  86.             if (true === $class && \T_STRING === $token[0]) {
  87.                 return $namespace.'\\'.$token[1];
  88.             }
  89.             if (true === $namespace && isset($nsTokens[$token[0]])) {
  90.                 $namespace $token[1];
  91.                 while (isset($tokens[++$i][1], $nsTokens[$tokens[$i][0]])) {
  92.                     $namespace .= $tokens[$i][1];
  93.                 }
  94.                 $token $tokens[$i];
  95.             }
  96.             if (\T_CLASS === $token[0]) {
  97.                 // Skip usage of ::class constant and anonymous classes
  98.                 $skipClassToken false;
  99.                 for ($j $i 1$j 0; --$j) {
  100.                     if (!isset($tokens[$j][1])) {
  101.                         if ('(' === $tokens[$j] || ',' === $tokens[$j]) {
  102.                             $skipClassToken true;
  103.                         }
  104.                         break;
  105.                     }
  106.                     if (\T_DOUBLE_COLON === $tokens[$j][0] || \T_NEW === $tokens[$j][0]) {
  107.                         $skipClassToken true;
  108.                         break;
  109.                     } elseif (!\in_array($tokens[$j][0], [\T_WHITESPACE\T_DOC_COMMENT\T_COMMENT])) {
  110.                         break;
  111.                     }
  112.                 }
  113.                 if (!$skipClassToken) {
  114.                     $class true;
  115.                 }
  116.             }
  117.             if (\T_NAMESPACE === $token[0]) {
  118.                 $namespace true;
  119.             }
  120.         }
  121.         return false;
  122.     }
  123. }