AnnotationDirectoryLoader.php 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  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\Routing\RouteCollection;
  12. use Symfony\Component\Config\Resource\DirectoryResource;
  13. /**
  14. * AnnotationDirectoryLoader loads routing information from annotations set
  15. * on PHP classes and methods.
  16. *
  17. * @author Fabien Potencier <fabien@symfony.com>
  18. */
  19. class AnnotationDirectoryLoader extends AnnotationFileLoader
  20. {
  21. /**
  22. * Loads from annotations from a directory.
  23. *
  24. * @param string $path A directory path
  25. * @param string|null $type The resource type
  26. *
  27. * @return RouteCollection A RouteCollection instance
  28. *
  29. * @throws \InvalidArgumentException When the directory does not exist or its routes cannot be parsed
  30. */
  31. public function load($path, $type = null)
  32. {
  33. $dir = $this->locator->locate($path);
  34. $collection = new RouteCollection();
  35. $collection->addResource(new DirectoryResource($dir, '/\.php$/'));
  36. $files = iterator_to_array(new \RecursiveIteratorIterator(
  37. new RecursiveCallbackFilterIterator(
  38. new \RecursiveDirectoryIterator($dir),
  39. function (\SplFileInfo $current) {
  40. return '.' !== substr($current->getBasename(), 0, 1);
  41. }
  42. ),
  43. \RecursiveIteratorIterator::LEAVES_ONLY
  44. ));
  45. usort($files, function (\SplFileInfo $a, \SplFileInfo $b) {
  46. return (string) $a > (string) $b ? 1 : -1;
  47. });
  48. foreach ($files as $file) {
  49. if (!$file->isFile() || '.php' !== substr($file->getFilename(), -4)) {
  50. continue;
  51. }
  52. if ($class = $this->findClass($file)) {
  53. $refl = new \ReflectionClass($class);
  54. if ($refl->isAbstract()) {
  55. continue;
  56. }
  57. $collection->addCollection($this->loader->load($class, $type));
  58. }
  59. }
  60. return $collection;
  61. }
  62. /**
  63. * {@inheritdoc}
  64. */
  65. public function supports($resource, $type = null)
  66. {
  67. if (!is_string($resource)) {
  68. return false;
  69. }
  70. try {
  71. $path = $this->locator->locate($resource);
  72. } catch (\Exception $e) {
  73. return false;
  74. }
  75. return is_dir($path) && (!$type || 'annotation' === $type);
  76. }
  77. }
  78. /**
  79. * @internal To be removed as RecursiveCallbackFilterIterator is available since PHP 5.4
  80. */
  81. class RecursiveCallbackFilterIterator extends \FilterIterator implements \RecursiveIterator
  82. {
  83. private $iterator;
  84. private $callback;
  85. public function __construct(\RecursiveIterator $iterator, $callback)
  86. {
  87. $this->iterator = $iterator;
  88. $this->callback = $callback;
  89. parent::__construct($iterator);
  90. }
  91. public function accept()
  92. {
  93. return call_user_func($this->callback, $this->current(), $this->key(), $this->iterator);
  94. }
  95. public function hasChildren()
  96. {
  97. return $this->iterator->hasChildren();
  98. }
  99. public function getChildren()
  100. {
  101. return new static($this->iterator->getChildren(), $this->callback);
  102. }
  103. }