summaryrefslogtreecommitdiff
path: root/src/http/Router.php
blob: db75f8167758bc9359439f15f7b1e2d9c8f748f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<?php

namespace App\http;

use App\http\Support\RouteLoader;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Generator\UrlGenerator;
use Symfony\Component\Routing\Loader\AnnotationFileLoader;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;

class Router
{
  public static Request $request;
  public static RequestContext $context;
  public static RouteCollection $routes;

  public static function init(Request $request): void
  {
    self::$request = $request;

    self::$context = new RequestContext();
    self::$context->fromRequest($request);

    self::$routes = new RouteCollection();
    $loader = new AnnotationFileLoader(new FileLocator(), new RouteLoader());
    $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(__DIR__ . '/Controller'));
    foreach ($iterator as $file) {
      /**@var \SplFileInfo $file*/
      if (in_array($file->getFilename(), ['.', '..'])) continue;

      $collection = $loader->load($file->getPathname(), 'attribute');
      self::$routes->addCollection($collection);
    }
  }

  public static function execute(): Response
  {
    try {
      $matcher = new UrlMatcher(self::$routes, self::$context);
      $match = $matcher->matchRequest(self::$request);

      foreach ($match as $key => $value) {
        if (str_starts_with($key, '_')) continue;

        self::$request->query->set($key, $value);
      }

      /**@var \ReflectionClass $class*/
      $class = $match['_']['class'];
      /**@var \ReflectionMethod $method*/
      $method = $match['_']['method'];

      return ($class->newInstance())->{$method->getName()}(self::$request);
    } catch (ResourceNotFoundException $exception) {
      return new Response('404', 404);
    } catch (MethodNotAllowedException $exception) {
      return new Response('403', 403);
    } catch (\Exception $exception) {
      return new Response('500: ' . $exception->getMessage(), 500);
    }
  }

  /**
   * @param string $name
   * @param array $parameters
   * @param int $referenceType
   */
  public static function generate(string $name, array $parameters = [], int $referenceType = 1): string
  {
    $generator = new UrlGenerator(self::$routes, self::$context);

    return $generator->generate($name, $parameters, $referenceType);
  }
}