1414/**
1515 * Import classes
1616 */
17- use Doctrine \Common \Annotations \AnnotationException ;
1817use Doctrine \Common \Annotations \SimpleAnnotationReader ;
1918use Psr \Container \ContainerInterface ;
2019use Psr \Http \Server \RequestHandlerInterface ;
2120use Psr \SimpleCache \CacheInterface ;
2221use Sunrise \Http \Router \Annotation \Host ;
2322use Sunrise \Http \Router \Annotation \Middleware ;
23+ use Sunrise \Http \Router \Annotation \Postfix ;
2424use Sunrise \Http \Router \Annotation \Prefix ;
2525use Sunrise \Http \Router \Annotation \Route ;
26- use Sunrise \Http \Router \Exception \InvalidDescriptorException ;
2726use Sunrise \Http \Router \Exception \InvalidLoaderResourceException ;
2827use Sunrise \Http \Router \Exception \UnresolvableReferenceException ;
2928use Sunrise \Http \Router \ReferenceResolver ;
@@ -226,9 +225,6 @@ public function attachArray(array $resources) : void
226225 /**
227226 * {@inheritdoc}
228227 *
229- * @throws InvalidDescriptorException
230- * If one of the found descriptors isn't valid.
231- *
232228 * @throws UnresolvableReferenceException
233229 * If one of the found middlewares cannot be resolved.
234230 */
@@ -262,7 +258,7 @@ public function load() : RouteCollectionInterface
262258
263259 /**
264260 * Gets descriptors from the cache if they are stored in it,
265- * otherwise gets them from the loader resources,
261+ * otherwise collects them from the loader resources,
266262 * and then tries to cache them
267263 *
268264 * @return Route[]
@@ -275,7 +271,7 @@ private function getCachedDescriptors() : array
275271 return $ this ->cache ->get ($ key );
276272 }
277273
278- $ result = $ this ->getDescriptors ();
274+ $ result = $ this ->collectDescriptors ();
279275
280276 if ($ this ->cache ) {
281277 $ this ->cache ->set ($ key , $ result );
@@ -285,11 +281,11 @@ private function getCachedDescriptors() : array
285281 }
286282
287283 /**
288- * Gets descriptors from the loader resources
284+ * Collects descriptors from the loader resources
289285 *
290286 * @return Route[]
291287 */
292- private function getDescriptors () : array
288+ private function collectDescriptors () : array
293289 {
294290 $ result = [];
295291 foreach ($ this ->resources as $ resource ) {
@@ -300,7 +296,7 @@ private function getDescriptors() : array
300296 }
301297 }
302298
303- usort ($ result , function ($ a , $ b ) {
299+ usort ($ result , function (Route $ a , Route $ b ) : int {
304300 return $ b ->priority <=> $ a ->priority ;
305301 });
306302
@@ -316,12 +312,17 @@ private function getDescriptors() : array
316312 */
317313 private function getClassDescriptors (ReflectionClass $ class ) : array
318314 {
315+ if ($ class ->isAbstract ()) {
316+ return [];
317+ }
318+
319319 $ result = [];
320320
321321 if ($ class ->isSubclassOf (RequestHandlerInterface::class)) {
322- $ descriptor = $ this ->getDescriptorFromClassOrMethod ($ class );
323- if (isset ($ descriptor )) {
324- $ this ->supplementDescriptorFromClassOrMethod ($ descriptor , $ class );
322+ $ annotations = $ this ->getAnnotations ($ class , Route::class);
323+ if (isset ($ annotations [0 ])) {
324+ $ descriptor = $ annotations [0 ];
325+ $ this ->supplementDescriptor ($ descriptor , $ class );
325326 $ descriptor ->holder = $ class ->getName ();
326327 $ result [] = $ descriptor ;
327328 }
@@ -335,10 +336,11 @@ private function getClassDescriptors(ReflectionClass $class) : array
335336 continue ;
336337 }
337338
338- $ descriptor = $ this ->getDescriptorFromClassOrMethod ($ method );
339- if (isset ($ descriptor )) {
340- $ this ->supplementDescriptorFromClassOrMethod ($ descriptor , $ class );
341- $ this ->supplementDescriptorFromClassOrMethod ($ descriptor , $ method );
339+ $ annotations = $ this ->getAnnotations ($ method , Route::class);
340+ if (isset ($ annotations [0 ])) {
341+ $ descriptor = $ annotations [0 ];
342+ $ this ->supplementDescriptor ($ descriptor , $ class );
343+ $ this ->supplementDescriptor ($ descriptor , $ method );
342344 $ descriptor ->holder = [$ class ->getName (), $ method ->getName ()];
343345 $ result [] = $ descriptor ;
344346 }
@@ -348,67 +350,87 @@ private function getClassDescriptors(ReflectionClass $class) : array
348350 }
349351
350352 /**
351- * Gets a descriptor from the given class or method
353+ * Supplements the given descriptor from the given class or method with data such as:
354+ * host, path prefix, path postfix and middlewares
352355 *
353- * @param ReflectionClass|ReflectionMethod $classOrMethod
356+ * ```php
357+ * #[Prefix('/api/v1')]
358+ * class SomeController {
354359 *
355- * @return Route|null
360+ * #[Route('foo', path: '/foo')]
361+ * public function foo() {
362+ * // will be available at: /api/v1/foo
363+ * }
364+ *
365+ * #[Route('bar', path: '/bar')]
366+ * public function bar() {
367+ * // will be available at: /api/v1/bar
368+ * }
369+ * }
370+ * ```
371+ *
372+ * @param Route $descriptor
373+ * @param ReflectionClass|ReflectionMethod $reflector
356374 *
357- * @throws InvalidDescriptorException
358- * If the found descriptor isn't valid.
375+ * @return void
359376 */
360- private function getDescriptorFromClassOrMethod ( Reflector $ classOrMethod ) : ? Route
377+ private function supplementDescriptor ( Route $ descriptor , Reflector $ reflector ) : void
361378 {
362- if (8 === PHP_MAJOR_VERSION ) {
363- $ attributes = $ classOrMethod ->getAttributes (Route::class);
364- if (isset ($ attributes [0 ])) {
365- return $ attributes [0 ]->newInstance ();
366- }
379+ $ annotations = $ this ->getAnnotations ($ reflector , Host::class);
380+ if (isset ($ annotations [0 ])) {
381+ $ descriptor ->host = $ annotations [0 ]->value ;
367382 }
368383
369- if ( isset ( $ this ->annotationReader )) {
370- try {
371- return ( $ classOrMethod instanceof ReflectionClass) ?
372- $ this -> annotationReader -> getClassAnnotation ( $ classOrMethod , Route::class) :
373- $ this -> annotationReader -> getMethodAnnotation ( $ classOrMethod , Route::class);
374- } catch ( AnnotationException $ e ) {
375- throw new InvalidDescriptorException ( $ e -> getMessage (), [], 0 , $ e );
376- }
384+ $ annotations = $ this ->getAnnotations ( $ reflector , Prefix::class);
385+ if ( isset ( $ annotations [ 0 ])) {
386+ $ descriptor -> path = $ annotations [ 0 ]-> value . $ descriptor -> path ;
387+ }
388+
389+ $ annotations = $ this -> getAnnotations ( $ reflector , Postfix::class);
390+ if ( isset ( $ annotations [ 0 ])) {
391+ $ descriptor -> path = $ descriptor -> path . $ annotations [ 0 ]-> value ;
377392 }
378393
379- // @codeCoverageIgnoreStart
380- return null ;
381- // @codeCoverageIgnoreEnd
394+ $ annotations = $ this ->getAnnotations ($ reflector , Middleware::class);
395+ foreach ($ annotations as $ annotation ) {
396+ $ descriptor ->middlewares [] = $ annotation ->value ;
397+ }
382398 }
383399
384400 /**
385- * Supplements the given descriptor with a host and middlewares from the given class or method
401+ * Gets annotations from the given class or method
386402 *
387- * @param Route $descriptor
388- * @param ReflectionClass|ReflectionMethod $classOrMethod
403+ * @param ReflectionClass|ReflectionMethod $reflector
404+ * @param class-string<T> $annotationName
389405 *
390- * @return void
406+ * @return array<T>
391407 *
392- * @since 2.11.0
408+ * @template T
393409 */
394- private function supplementDescriptorFromClassOrMethod ( Route $ descriptor , Reflector $ classOrMethod ) : void
410+ private function getAnnotations ( Reflector $ reflector , string $ annotationName ) : array
395411 {
396- if (8 === PHP_MAJOR_VERSION ) {
397- $ attributes = $ classOrMethod ->getAttributes (Host::class);
398- if (isset ($ attributes [0 ])) {
399- $ descriptor ->host = $ attributes [0 ]->newInstance ()->value ;
400- }
412+ $ result = [];
401413
402- $ attributes = $ classOrMethod ->getAttributes (Middleware::class);
414+ if (8 === PHP_MAJOR_VERSION ) {
415+ $ attributes = $ reflector ->getAttributes ($ annotationName );
403416 foreach ($ attributes as $ attribute ) {
404- $ descriptor -> middlewares [] = $ attribute ->newInstance ()-> value ;
417+ $ result [] = $ attribute ->newInstance ();
405418 }
419+ }
420+
421+ if (empty ($ result ) and isset ($ this ->annotationReader )) {
422+ $ annotations = ($ reflector instanceof ReflectionClass) ?
423+ $ this ->annotationReader ->getClassAnnotations ($ reflector ) :
424+ $ this ->annotationReader ->getMethodAnnotations ($ reflector );
406425
407- $ attributes = $ classOrMethod ->getAttributes (Prefix::class);
408- if (isset ($ attributes [0 ])) {
409- $ descriptor ->path = $ attributes [0 ]->newInstance ()->value . $ descriptor ->path ;
426+ foreach ($ annotations as $ annotation ) {
427+ if ($ annotation instanceof $ annotationName ) {
428+ $ result [] = $ annotation ;
429+ }
410430 }
411431 }
432+
433+ return $ result ;
412434 }
413435
414436 /**
0 commit comments