From 83ec00c8a0b08d00fd1c0b46579af908f5478b97 Mon Sep 17 00:00:00 2001 From: Lewis Dale Date: Fri, 10 Mar 2023 09:47:55 +0000 Subject: [PATCH] Extend router a little, add routes for sending and receiving webmentions --- index.php | 31 ++++++++++++-- src/Router/Method.php | 10 +++++ src/Router/Request.php | 1 + src/Router/Router.php | 88 ++++++++++++++++++++++----------------- src/Router/StatusCode.php | 13 ++++++ src/Webmention.php | 1 - 6 files changed, 101 insertions(+), 43 deletions(-) diff --git a/index.php b/index.php index 791c814..0b8dbf4 100644 --- a/index.php +++ b/index.php @@ -2,18 +2,41 @@ require_once __DIR__ . "/vendor/autoload.php"; +use Lewisdale\Webmentions\Endpoint; +use Lewisdale\Webmentions\Exceptions\InvalidTargetException; +use Lewisdale\Webmentions\Exceptions\InvalidUrlException; +use Lewisdale\Webmentions\Router\Request; use Lewisdale\Webmentions\Router\Router; use Lewisdale\Webmentions\Router\Response; +use Lewisdale\Webmentions\Router\StatusCode; use Lewisdale\Webmentions\Webmention; $mentioner = new Webmention(); -// $mentioner->sendForPage("https://lewisdale.dev/post/bringing-my-omg-lol-now-page-into-eleventy/"); - $router = new Router(); -$router->get("/send", function($req, Response $response) { - return "

Hello world

"; +$router->post("/send", function(Request $req, Response $response) use ($webmention) { + $source = $req->query["source"]; + $webmention->sendForPage($source); +}); + +$router->post("/endpoint", function(Request $req, Response $response) { + $source = $req->post['source']; + $target = $req->post['target']; + + $endpoint = new Endpoint(); + + try { + $endpoint->receiveWebmention($source, $target); + } catch (InvalidUrlException $e) { + $response->status_code = StatusCode::BadRequest; + return "Source and target must be valid URLs"; + } catch (InvalidTargetException $e) { + $response->status_code = StatusCode::BadRequest; + return "Target must be on the domain lewisdale.dev"; + } + + $response->status_code = StatusCode::Created; }); $router->dispatch(); diff --git a/src/Router/Method.php b/src/Router/Method.php index 2db42ed..eb42d43 100644 --- a/src/Router/Method.php +++ b/src/Router/Method.php @@ -8,4 +8,14 @@ enum Method { // Fallback method case UNKNOWN; + + public static function from(string $str) : self + { + switch ($str) + { + case "GET": return Method::GET; + case "POST": return Method::POST; + default: return METHOD::UNKNOWN; + } + } }; \ No newline at end of file diff --git a/src/Router/Request.php b/src/Router/Request.php index 80f4bb0..1447749 100644 --- a/src/Router/Request.php +++ b/src/Router/Request.php @@ -8,6 +8,7 @@ class Request { public readonly string $uri, public readonly Method $method, public readonly array $post = [], + public readonly array $query = [], ) {} } diff --git a/src/Router/Router.php b/src/Router/Router.php index 388af46..d47ef79 100644 --- a/src/Router/Router.php +++ b/src/Router/Router.php @@ -2,6 +2,33 @@ namespace Lewisdale\Webmentions\Router; +use Exception; + +/** + * This is a dumb, custom Router I slapped together as a way of reminding myself how to PHP. + * + * It's not great, and currently on supports two methods: GET and POST. + * + * Usage is as follows: + * + * ``` + * $router = new Lewisdale\Webmentions\Router\Router(); + * $router->get('/a/get/route', function($request, $response) { + * $response->status_code = StatusCode::OK; + * return "Hello world!"; + * }); + * + * $router->get('/a/json/route', function($request, $response) { + * return $response->json(new MyClass()); + * }); + * + * $router->dispatch(); + * ``` + * + * TL;DR? Don't use this. There are some good routing libraries already. + * + * But if you're reading this, it's already too late. + */ class Router { private array $routes; @@ -25,30 +52,16 @@ class Router { $this->routes[] = new Route(Method::POST, $this->format_route($route), $fn); } - private function method_to_enum(string $method): Method { - switch ($method) { - case "GET": - return Method::GET; - case "POST": - return Method::POST; - default: - return Method::UNKNOWN; - } - } - private function get_params(array $matches): array { - array_shift($matches); - $results = array(); - - foreach ($matches as $match) { - $results[] = $match[0]; - } - return $results; + return array_map( + function($match) { return $match[0]; }, + array_shift($matches) + ); } public function dispatch() { $uri = $_SERVER['REQUEST_URI']; - $method = $this->method_to_enum($_SERVER['REQUEST_METHOD']); + $method = Method::from($_SERVER['REQUEST_METHOD']); $num_matched = 0; @@ -61,8 +74,13 @@ class Router { $num_matched++; $fn = $route->fn; $params = $this->get_params($matches); - $response->status_code = StatusCode::Ok; - $response->body .= $fn(new Request($params, $uri, $method, $_POST), $response); + $response->status_code = StatusCode::Ok; // Default status code to OK for the "average" route + try { + $response->body .= $fn($this->construct_request_object($params), $response); + } catch (Exception) { + $response->status_code = StatusCode::InternalError; + // TODO: Log the error + } } } } @@ -75,28 +93,22 @@ class Router { $this->respond($response); } - private function map_status_code(StatusCode $code): int { - switch ($code) { - case StatusCode::NotFound: - return 404; - case StatusCode::Ok: - return 200; - case StatusCode::InternalError: - return 500; - case StatusCode::Redirect: - return 300; - case StatusCode::BadRequest: - return 400; - default: - return 501; - } - } private function respond(Response $response) { - http_response_code($this->map_status_code($response->status_code)); + http_response_code($response->status_code->code()); echo $response->body; } + + private function construct_request_object(array $params) + { + $uri = $_SERVER['REQUEST_URI']; + $method = Method::from($_SERVER['REQUEST_METHOD']); + $query = $_GET; + $post = $_POST; + + return new Request($params, $uri, $method, $post, $query); + } } ?> \ No newline at end of file diff --git a/src/Router/StatusCode.php b/src/Router/StatusCode.php index effe9a4..057224b 100644 --- a/src/Router/StatusCode.php +++ b/src/Router/StatusCode.php @@ -8,6 +8,19 @@ enum StatusCode { case Redirect; case InternalError; case BadRequest; + case Created; + + public function code() : int + { + return match($this) { + StatusCode::NotFound => 404, + StatusCode::Ok => 200, + StatusCode::InternalError => 500, + StatusCode::Redirect => 301, + StatusCode::BadRequest => 400, + StatusCode::Created => 201, + }; + } } ?> \ No newline at end of file diff --git a/src/Webmention.php b/src/Webmention.php index 9372fc3..078550a 100644 --- a/src/Webmention.php +++ b/src/Webmention.php @@ -2,7 +2,6 @@ namespace Lewisdale\Webmentions; -use Lewisdale\Webmentions\Gateways\WebmentionGatewayInterface; use Symfony\Component\DomCrawler\Crawler; use Symfony\Component\HttpClient\HttpClient; use Symfony\Contracts\HttpClient\HttpClientInterface;