| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 | <?php/* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */namespace Symfony\Component\Routing\Loader;use Symfony\Component\Config\FileLocatorInterface;use Symfony\Component\Config\Loader\FileLoader;use Symfony\Component\Config\Resource\FileResource;use Symfony\Component\Routing\RouteCollection;/** * AnnotationFileLoader loads routing information from annotations set * on a PHP class and its methods. * * @author Fabien Potencier <fabien@symfony.com> */class AnnotationFileLoader extends FileLoader{    protected $loader;    public function __construct(FileLocatorInterface $locator, AnnotationClassLoader $loader)    {        if (!\function_exists('token_get_all')) {            throw new \LogicException('The Tokenizer extension is required for the routing annotation loaders.');        }        parent::__construct($locator);        $this->loader = $loader;    }    /**     * Loads from annotations from a file.     *     * @param string      $file A PHP file path     * @param string|null $type The resource type     *     * @return RouteCollection|null     *     * @throws \InvalidArgumentException When the file does not exist or its routes cannot be parsed     */    public function load($file, string $type = null)    {        $path = $this->locator->locate($file);        $collection = new RouteCollection();        if ($class = $this->findClass($path)) {            $refl = new \ReflectionClass($class);            if ($refl->isAbstract()) {                return null;            }            $collection->addResource(new FileResource($path));            $collection->addCollection($this->loader->load($class, $type));        }        gc_mem_caches();        return $collection;    }    /**     * {@inheritdoc}     */    public function supports($resource, string $type = null)    {        return \is_string($resource) && 'php' === pathinfo($resource, \PATHINFO_EXTENSION) && (!$type || 'annotation' === $type);    }    /**     * Returns the full class name for the first class in the file.     *     * @return string|false     */    protected function findClass(string $file)    {        $class = false;        $namespace = false;        $tokens = token_get_all(file_get_contents($file));        if (1 === \count($tokens) && \T_INLINE_HTML === $tokens[0][0]) {            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));        }        $nsTokens = [\T_NS_SEPARATOR => true, \T_STRING => true];        if (\defined('T_NAME_QUALIFIED')) {            $nsTokens[\T_NAME_QUALIFIED] = true;        }        for ($i = 0; isset($tokens[$i]); ++$i) {            $token = $tokens[$i];            if (!isset($token[1])) {                continue;            }            if (true === $class && \T_STRING === $token[0]) {                return $namespace.'\\'.$token[1];            }            if (true === $namespace && isset($nsTokens[$token[0]])) {                $namespace = $token[1];                while (isset($tokens[++$i][1], $nsTokens[$tokens[$i][0]])) {                    $namespace .= $tokens[$i][1];                }                $token = $tokens[$i];            }            if (\T_CLASS === $token[0]) {                // Skip usage of ::class constant and anonymous classes                $skipClassToken = false;                for ($j = $i - 1; $j > 0; --$j) {                    if (!isset($tokens[$j][1])) {                        if ('(' === $tokens[$j] || ',' === $tokens[$j]) {                            $skipClassToken = true;                        }                        break;                    }                    if (\T_DOUBLE_COLON === $tokens[$j][0] || \T_NEW === $tokens[$j][0]) {                        $skipClassToken = true;                        break;                    } elseif (!\in_array($tokens[$j][0], [\T_WHITESPACE, \T_DOC_COMMENT, \T_COMMENT])) {                        break;                    }                }                if (!$skipClassToken) {                    $class = true;                }            }            if (\T_NAMESPACE === $token[0]) {                $namespace = true;            }        }        return false;    }}
 |