|
1 <?php |
|
2 |
|
3 /* |
|
4 * This file is part of the Symfony package. |
|
5 * |
|
6 * (c) Fabien Potencier <fabien@symfony.com> |
|
7 * |
|
8 * For the full copyright and license information, please view the LICENSE |
|
9 * file that was distributed with this source code. |
|
10 */ |
|
11 |
|
12 namespace Symfony\Component\Routing\Loader; |
|
13 |
|
14 use Symfony\Component\Routing\RouteCollection; |
|
15 use Symfony\Component\Config\Resource\FileResource; |
|
16 use Symfony\Component\Config\Loader\FileLoader; |
|
17 use Symfony\Component\Config\FileLocator; |
|
18 |
|
19 /** |
|
20 * AnnotationFileLoader loads routing information from annotations set |
|
21 * on a PHP class and its methods. |
|
22 * |
|
23 * @author Fabien Potencier <fabien@symfony.com> |
|
24 */ |
|
25 class AnnotationFileLoader extends FileLoader |
|
26 { |
|
27 protected $loader; |
|
28 |
|
29 /** |
|
30 * Constructor. |
|
31 * |
|
32 * @param FileLocator $locator A FileLocator instance |
|
33 * @param AnnotationClassLoader $loader An AnnotationClassLoader instance |
|
34 * @param string|array $paths A path or an array of paths where to look for resources |
|
35 */ |
|
36 public function __construct(FileLocator $locator, AnnotationClassLoader $loader, $paths = array()) |
|
37 { |
|
38 if (!function_exists('token_get_all')) { |
|
39 throw new \RuntimeException('The Tokenizer extension is required for the routing annotation loaders.'); |
|
40 } |
|
41 |
|
42 parent::__construct($locator, $paths); |
|
43 |
|
44 $this->loader = $loader; |
|
45 } |
|
46 |
|
47 /** |
|
48 * Loads from annotations from a file. |
|
49 * |
|
50 * @param string $file A PHP file path |
|
51 * @param string $type The resource type |
|
52 * |
|
53 * @return RouteCollection A RouteCollection instance |
|
54 * |
|
55 * @throws \InvalidArgumentException When the file does not exist or its routes cannot be parsed |
|
56 */ |
|
57 public function load($file, $type = null) |
|
58 { |
|
59 $path = $this->locator->locate($file); |
|
60 |
|
61 $collection = new RouteCollection(); |
|
62 if ($class = $this->findClass($path)) { |
|
63 $collection->addResource(new FileResource($path)); |
|
64 $collection->addCollection($this->loader->load($class, $type)); |
|
65 } |
|
66 |
|
67 return $collection; |
|
68 } |
|
69 |
|
70 /** |
|
71 * Returns true if this class supports the given resource. |
|
72 * |
|
73 * @param mixed $resource A resource |
|
74 * @param string $type The resource type |
|
75 * |
|
76 * @return Boolean True if this class supports the given resource, false otherwise |
|
77 */ |
|
78 public function supports($resource, $type = null) |
|
79 { |
|
80 return is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'annotation' === $type); |
|
81 } |
|
82 |
|
83 /** |
|
84 * Returns the full class name for the first class in the file. |
|
85 * |
|
86 * @param string $file A PHP file path |
|
87 * |
|
88 * @return string|false Full class name if found, false otherwise |
|
89 */ |
|
90 protected function findClass($file) |
|
91 { |
|
92 $class = false; |
|
93 $namespace = false; |
|
94 $tokens = token_get_all(file_get_contents($file)); |
|
95 while ($token = array_shift($tokens)) { |
|
96 if (!is_array($token)) { |
|
97 continue; |
|
98 } |
|
99 |
|
100 if (true === $class && T_STRING === $token[0]) { |
|
101 return $namespace.'\\'.$token[1]; |
|
102 } |
|
103 |
|
104 if (true === $namespace && T_STRING === $token[0]) { |
|
105 $namespace = ''; |
|
106 do { |
|
107 $namespace .= $token[1]; |
|
108 $token = array_shift($tokens); |
|
109 } while ($tokens && is_array($token) && in_array($token[0], array(T_NS_SEPARATOR, T_STRING))); |
|
110 } |
|
111 |
|
112 if (T_CLASS === $token[0]) { |
|
113 $class = true; |
|
114 } |
|
115 |
|
116 if (T_NAMESPACE === $token[0]) { |
|
117 $namespace = true; |
|
118 } |
|
119 } |
|
120 |
|
121 return false; |
|
122 } |
|
123 } |