2015-08-18 00:00:26 +00:00
< ? 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 ;
2018-11-23 12:29:20 +00:00
use Symfony\Component\Config\Loader\FileLoader ;
use Symfony\Component\Config\Resource\FileResource ;
use Symfony\Component\Routing\RouteCollection ;
2015-08-18 00:00:26 +00:00
/**
* 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 ;
/**
* @ throws \RuntimeException
*/
public function __construct ( FileLocatorInterface $locator , AnnotationClassLoader $loader )
{
2018-11-23 12:29:20 +00:00
if ( ! \function_exists ( 'token_get_all' )) {
2015-08-18 00:00:26 +00:00
throw new \RuntimeException ( '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 A RouteCollection instance
*
* @ throws \InvalidArgumentException When the file does not exist or its routes cannot be parsed
*/
public function load ( $file , $type = null )
{
$path = $this -> locator -> locate ( $file );
$collection = new RouteCollection ();
if ( $class = $this -> findClass ( $path )) {
$collection -> addResource ( new FileResource ( $path ));
$collection -> addCollection ( $this -> loader -> load ( $class , $type ));
}
2017-07-03 15:47:07 +00:00
if ( \PHP_VERSION_ID >= 70000 ) {
2016-04-20 16:56:34 +00:00
// PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
gc_mem_caches ();
}
2015-08-18 00:00:26 +00:00
return $collection ;
}
/**
* { @ inheritdoc }
*/
public function supports ( $resource , $type = null )
{
2018-11-23 12:29:20 +00:00
return \is_string ( $resource ) && 'php' === pathinfo ( $resource , PATHINFO_EXTENSION ) && ( ! $type || 'annotation' === $type );
2015-08-18 00:00:26 +00:00
}
/**
* Returns the full class name for the first class in the file .
*
* @ param string $file A PHP file path
*
* @ return string | false Full class name if found , false otherwise
*/
protected function findClass ( $file )
{
$class = false ;
$namespace = false ;
$tokens = token_get_all ( file_get_contents ( $file ));
2018-11-23 12:29:20 +00:00
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 ));
}
2016-04-20 16:56:34 +00:00
for ( $i = 0 ; isset ( $tokens [ $i ]); ++ $i ) {
2015-08-18 00:00:26 +00:00
$token = $tokens [ $i ];
2016-04-20 16:56:34 +00:00
if ( ! isset ( $token [ 1 ])) {
2015-08-18 00:00:26 +00:00
continue ;
}
if ( true === $class && T_STRING === $token [ 0 ]) {
return $namespace . '\\' . $token [ 1 ];
}
if ( true === $namespace && T_STRING === $token [ 0 ]) {
2016-04-20 16:56:34 +00:00
$namespace = $token [ 1 ];
2018-11-23 12:29:20 +00:00
while ( isset ( $tokens [ ++ $i ][ 1 ]) && \in_array ( $tokens [ $i ][ 0 ], array ( T_NS_SEPARATOR , T_STRING ))) {
2016-04-20 16:56:34 +00:00
$namespace .= $tokens [ $i ][ 1 ];
}
$token = $tokens [ $i ];
2015-08-18 00:00:26 +00:00
}
if ( T_CLASS === $token [ 0 ]) {
2018-11-23 12:29:20 +00:00
// Skip usage of ::class constant and anonymous classes
$skipClassToken = false ;
2017-02-03 00:28:38 +00:00
for ( $j = $i - 1 ; $j > 0 ; -- $j ) {
if ( ! isset ( $tokens [ $j ][ 1 ])) {
break ;
}
2018-11-23 12:29:20 +00:00
if ( T_DOUBLE_COLON === $tokens [ $j ][ 0 ] || T_NEW === $tokens [ $j ][ 0 ]) {
$skipClassToken = true ;
2017-02-03 00:28:38 +00:00
break ;
2018-11-23 12:29:20 +00:00
} elseif ( ! \in_array ( $tokens [ $j ][ 0 ], array ( T_WHITESPACE , T_DOC_COMMENT , T_COMMENT ))) {
2017-02-03 00:28:38 +00:00
break ;
}
}
2018-11-23 12:29:20 +00:00
if ( ! $skipClassToken ) {
2017-02-03 00:28:38 +00:00
$class = true ;
}
2015-08-18 00:00:26 +00:00
}
if ( T_NAMESPACE === $token [ 0 ]) {
$namespace = true ;
}
}
return false ;
}
}