summaryrefslogtreecommitdiff
path: root/src/Router.php
blob: 46e3f4f1fcfbc22a6d696185b329a355a352dcd4 (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
81
82
83
84
85
86
87
88
89
90
<?php

namespace Elements;

use Elements\Controller\Card;
use Elements\Controller\Home;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;

class Router
{
  private ?RouteCollection $routes;
  private array $routeFunctions = [];

  /**
   * Router constructor.
   */
  public function __construct()
  {
    /**@var Request $request*/
    $request = Request::createFromGlobals();
    $response = new Response();

    $this->routes = new RouteCollection();
    $this->addRoute('GET', '/', [Home::class, 'index']);
    $this->addRoute('GET', '/dashboard', [Home::class, 'dashboard']);

    // card
    $this->addRoute('GET', '/card', [Card::class, 'listCards']);
    $this->addRoute('GET', '/card/add', [Card::class, 'addCard']);
    $this->addRoute('GET', '/card/{id}', [Card::class, 'viewCard']);
    $this->addRoute('GET', '/card/{id}/edit', [Card::class, 'editCard']);
    $this->addRoute('GET', '/card/{id}/artwork/{artworkId}', [Card::class, 'viewArtwork']);
    $this->addRoute('POST', '/card/add', [Card::class, 'add']);
    $this->addRoute('POST', '/card/{id}/edit', [Card::class, 'edit']);
    $this->addRoute('POST', '/card/{id}/vote', [Card::class, 'vote']);

    $context = new RequestContext();
    $context->fromRequest($request);
    $matcher = new UrlMatcher($this->routes, $context);

    try {
      $match = $matcher->match($request->getPathInfo());
      $request->attributes->set('route', $match);

      // run controller function
      $content = call_user_func($this->routeFunctions[$match['_route']], $request);

      // set response to new response
      if ($content instanceof Response) {
	$response = $content;
      }

      // set content directly otherwise
      else {
	$response->setContent($content);
      }
    }

    // catch any errors
    catch (AppException $exception) {
      $response->setStatusCode($exception->getCode());
      $response->setContent($exception->getMessage());
    } catch (\Exception $exception) {
      $response->setStatusCode(Response::HTTP_BAD_REQUEST);
      $response->setContent($exception->getMessage());
    }

    $response->send();
  }

  /**
   * @param string|array $methods
   * @param string $path
   * @param callable $function
   */
  public function addRoute(string|array $methods, string $path, array $function)
  {
    $name = "$function[0]::$function[1]";

    $this->routes->add($name, new Route($path, methods: (array)$methods));
    $this->routeFunctions[$name] = $function;
  }
}