Passed
Pull Request — master (#32)
by Anatoly
09:33
created

AnnotationRouteLoader::findAnnotations()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 9
c 1
b 0
f 0
dl 0
loc 16
rs 9.9666
ccs 10
cts 10
cp 1
cc 3
nc 3
nop 2
crap 3
1
<?php declare(strict_types=1);
2
3
/**
4
 * It's free open-source software released under the MIT License.
5
 *
6
 * @author Anatoly Fenric <[email protected]>
7
 * @copyright Copyright (c) 2018, Anatoly Fenric
8
 * @license https://github.com/sunrise-php/http-router/blob/master/LICENSE
9
 * @link https://github.com/sunrise-php/http-router
10
 */
11
12
namespace Sunrise\Http\Router\Annotation;
13
14
/**
15
 * Import classes
16
 */
17
use Doctrine\Common\Annotations\SimpleAnnotationReader;
18
use Sunrise\Http\Router\Route as BaseRoute;
19
use RecursiveDirectoryIterator;
20
use RecursiveIteratorIterator;
21
use ReflectionClass;
22
use RegexIterator;
23
use SplPriorityQueue;
24
25
/**
26
 * Import functions
27
 */
28
use function array_diff;
29
use function get_declared_classes;
30
use function iterator_to_array;
31
32
/**
33
 * AnnotationRouteLoader
34
 */
35
class AnnotationRouteLoader
36
{
37
38
    /**
39
     * @var SimpleAnnotationReader
40
     */
41
    private $annotationReader;
42
43
    /**
44
     * @var SplPriorityQueue
45
     */
46
    private $discoveredAnnotations;
47
48
    /**
49
     * Constructor of the class
50
     */
51 17
    public function __construct()
52
    {
53 17
        $this->annotationReader = new SimpleAnnotationReader();
54 17
        $this->annotationReader->addNamespace(__NAMESPACE__);
55
56 17
        $this->discoveredAnnotations = new SplPriorityQueue();
57 17
    }
58
59
    /**
60
     * Builds discovered routes
61
     *
62
     * @param null|callable $objectCreator
63
     *
64
     * @return array
65
     */
66 1
    public function buildRoutes(callable $objectCreator = null) : array
67
    {
68 1
        $routes = [];
69 1
        foreach ($this->discoveredAnnotations as $annotation) {
70 1
            $requestHandlerClass = $annotation->source->getName();
71 1
            $requestHandler = $objectCreator ? $objectCreator($requestHandlerClass) : new $requestHandlerClass;
72
73 1
            $middlewares = [];
74 1
            foreach ($annotation->middlewares as $middlewareClass) {
75 1
                $middlewares[] = $objectCreator ? $objectCreator($middlewareClass) : new $middlewareClass;
76
            }
77
78 1
            $routes[] = new BaseRoute(
79 1
                $annotation->name,
80 1
                $annotation->path,
81 1
                $annotation->methods,
82 1
                $requestHandler,
83 1
                $middlewares,
84 1
                $annotation->attributes
85
            );
86
        }
87
88 1
        return $routes;
89
    }
90
91
    /**
92
     * Discovers routes in the given destination
93
     *
94
     * @param string $destination
95
     *
96
     * @return void
97
     */
98 17
    public function discover(string $destination) : void
99
    {
100 17
        $annotations = $this->findAnnotations($destination, Route::class);
101
102 1
        foreach ($annotations as $annotation) {
103 1
            $this->discoveredAnnotations->insert($annotation, $annotation->priority);
104
        }
105 1
    }
106
107
    /**
108
     * Finds annotations in the given destination
109
     *
110
     * @param string $destination
111
     * @param string $name
112
     *
113
     * @return array
114
     */
115 17
    private function findAnnotations(string $destination, string $name) : array
116
    {
117 17
        $classes = $this->findClasses($destination);
118 17
        $annotations = [];
119
120 17
        foreach ($classes as $class) {
121 17
            $class = new ReflectionClass($class);
122 17
            $annotation = $this->annotationReader->getClassAnnotation($class, $name);
123
124 2
            if ($annotation instanceof $name) {
125 1
                $annotation->source = $class;
126 2
                $annotations[] = $annotation;
127
            }
128
        }
129
130 1
        return $annotations;
131
    }
132
133
    /**
134
     * Finds classes in the given destination
135
     *
136
     * @param string $destination
137
     *
138
     * @return array
139
     */
140 17
    private function findClasses(string $destination) : array
141
    {
142 17
        $files = $this->findFiles($destination);
143 17
        $classes = get_declared_classes();
144
145 17
        foreach ($files as $file) {
146 17
            require_once $file->getRealPath();
147
        }
148
149 17
        return array_diff(get_declared_classes(), $classes);
150
    }
151
152
    /**
153
     * Finds files in the given destination
154
     *
155
     * @param string $destination
156
     *
157
     * @return array
158
     */
159 17
    private function findFiles(string $destination) : array
160
    {
161 17
        $directory = new RecursiveDirectoryIterator($destination);
162 17
        $iterator = new RecursiveIteratorIterator($directory);
163 17
        $files = new RegexIterator($iterator, '/\.php$/');
164
165 17
        return iterator_to_array($files);
166
    }
167
}
168