2010-07-21 16:43:12 +01:00
< ? php
/*
2011-01-15 13:29:43 +00:00
* This file is part of the Symfony package .
2010-07-21 16:43:12 +01:00
*
2011-03-06 11:40:06 +00:00
* ( c ) Fabien Potencier < fabien @ symfony . com >
2010-07-21 16:43:12 +01:00
*
2011-01-15 13:29:43 +00:00
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
2010-07-21 16:43:12 +01:00
*/
2011-01-15 13:29:43 +00:00
namespace Symfony\Component\Routing\Loader ;
use Symfony\Component\Routing\RouteCollection ;
2011-02-10 15:15:51 +00:00
use Symfony\Component\Config\Resource\FileResource ;
use Symfony\Component\Config\Loader\FileLoader ;
2012-11-12 15:14:50 +00:00
use Symfony\Component\Config\FileLocatorInterface ;
2011-01-15 13:29:43 +00:00
2010-07-21 16:43:12 +01:00
/**
* AnnotationFileLoader loads routing information from annotations set
* on a PHP class and its methods .
*
2011-03-06 11:40:06 +00:00
* @ author Fabien Potencier < fabien @ symfony . com >
2010-07-21 16:43:12 +01:00
*/
class AnnotationFileLoader extends FileLoader
{
2011-03-23 20:40:54 +00:00
protected $loader ;
2010-07-21 16:43:12 +01:00
/**
2012-12-16 12:02:54 +00:00
* @ throws \RuntimeException
2010-07-21 16:43:12 +01:00
*/
2014-02-11 07:51:18 +00:00
public function __construct ( FileLocatorInterface $locator , AnnotationClassLoader $loader )
2010-07-21 16:43:12 +01:00
{
if ( ! function_exists ( 'token_get_all' )) {
2010-12-06 06:48:44 +00:00
throw new \RuntimeException ( 'The Tokenizer extension is required for the routing annotation loaders.' );
2010-07-21 16:43:12 +01:00
}
2014-02-11 07:51:18 +00:00
parent :: __construct ( $locator );
2010-07-21 16:43:12 +01:00
$this -> loader = $loader ;
}
/**
* Loads from annotations from a file .
*
2012-11-12 15:14:50 +00:00
* @ param string $file A PHP file path
* @ param string | null $type The resource type
2010-07-21 16:43:12 +01:00
*
* @ return RouteCollection A RouteCollection instance
*
2010-12-06 06:48:44 +00:00
* @ throws \InvalidArgumentException When the file does not exist or its routes cannot be parsed
2010-07-21 16:43:12 +01:00
*/
2010-12-06 06:48:44 +00:00
public function load ( $file , $type = null )
2010-07-21 16:43:12 +01:00
{
2011-02-10 15:15:51 +00:00
$path = $this -> locator -> locate ( $file );
2010-07-21 16:43:12 +01:00
$collection = new RouteCollection ();
if ( $class = $this -> findClass ( $path )) {
$collection -> addResource ( new FileResource ( $path ));
2010-12-06 06:48:44 +00:00
$collection -> addCollection ( $this -> loader -> load ( $class , $type ));
2010-07-21 16:43:12 +01:00
}
2017-05-21 10:14:40 +01:00
// PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
gc_mem_caches ();
2010-07-21 16:43:12 +01:00
return $collection ;
}
/**
2012-05-05 00:43:00 +01:00
* { @ inheritdoc }
2010-07-21 16:43:12 +01:00
*/
2010-12-06 06:48:44 +00:00
public function supports ( $resource , $type = null )
2010-07-21 16:43:12 +01:00
{
2010-12-06 06:48:44 +00:00
return is_string ( $resource ) && 'php' === pathinfo ( $resource , PATHINFO_EXTENSION ) && ( ! $type || 'annotation' === $type );
2010-07-21 16:43:12 +01:00
}
2010-12-06 06:48:44 +00:00
/**
* Returns the full class name for the first class in the file .
*
* @ param string $file A PHP file path
*
2011-04-15 20:12:02 +01:00
* @ return string | false Full class name if found , false otherwise
2010-12-06 06:48:44 +00:00
*/
2011-03-23 20:40:54 +00:00
protected function findClass ( $file )
2010-07-21 16:43:12 +01:00
{
$class = false ;
$namespace = false ;
$tokens = token_get_all ( file_get_contents ( $file ));
2016-05-25 11:12:27 +01: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-01-14 13:08:57 +00:00
for ( $i = 0 ; isset ( $tokens [ $i ]); ++ $i ) {
2011-08-30 18:36:17 +01:00
$token = $tokens [ $i ];
2016-01-14 13:08:57 +00:00
if ( ! isset ( $token [ 1 ])) {
2010-07-21 16:43:12 +01:00
continue ;
}
if ( true === $class && T_STRING === $token [ 0 ]) {
return $namespace . '\\' . $token [ 1 ];
}
if ( true === $namespace && T_STRING === $token [ 0 ]) {
2016-01-14 13:08:57 +00:00
$namespace = $token [ 1 ];
while ( isset ( $tokens [ ++ $i ][ 1 ]) && in_array ( $tokens [ $i ][ 0 ], array ( T_NS_SEPARATOR , T_STRING ))) {
$namespace .= $tokens [ $i ][ 1 ];
}
$token = $tokens [ $i ];
2010-07-21 16:43:12 +01:00
}
if ( T_CLASS === $token [ 0 ]) {
2016-05-29 11:13:06 +01:00
// Skip usage of ::class constant
$isClassConstant = false ;
for ( $j = $i - 1 ; $j > 0 ; -- $j ) {
if ( ! isset ( $tokens [ $j ][ 1 ])) {
break ;
}
if ( T_DOUBLE_COLON === $tokens [ $j ][ 0 ]) {
$isClassConstant = true ;
break ;
} elseif ( ! in_array ( $tokens [ $j ][ 0 ], array ( T_WHITESPACE , T_DOC_COMMENT , T_COMMENT ))) {
break ;
}
}
if ( ! $isClassConstant ) {
$class = true ;
}
2010-07-21 16:43:12 +01:00
}
if ( T_NAMESPACE === $token [ 0 ]) {
$namespace = true ;
}
}
return false ;
}
}