xref: /webtrees/app/Http/Middleware/Router.php (revision d403609d9adfb78373074e21cba0e7fd0ec71fde)
1<?php
2
3/**
4 * webtrees: online genealogy
5 * Copyright (C) 2019 webtrees development team
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17declare(strict_types=1);
18
19namespace Fisharebest\Webtrees\Http\Middleware;
20
21use Fig\Http\Message\RequestMethodInterface;
22use Fisharebest\Webtrees\Services\ModuleService;
23use Fisharebest\Webtrees\Webtrees;
24use Middleland\Dispatcher;
25use Psr\Http\Message\ResponseInterface;
26use Psr\Http\Message\ServerRequestInterface;
27use Psr\Http\Server\MiddlewareInterface;
28use Psr\Http\Server\RequestHandlerInterface;
29
30use function app;
31use function array_map;
32
33/**
34 * Simple class to help migrate to a third-party routing library.
35 */
36class Router implements MiddlewareInterface, RequestMethodInterface
37{
38    /** @var string[][] */
39    private $routes = [
40        self::METHOD_GET  => [],
41        self::METHOD_POST => [],
42    ];
43
44    /** @var ModuleService */
45    private $module_service;
46
47    /**
48     * Router constructor.
49     *
50     * @param ModuleService $module_service
51     */
52    public function __construct(ModuleService $module_service)
53    {
54        $this->module_service = $module_service;
55    }
56
57    /**
58     * @param string $route
59     * @param string $url
60     * @param string $handler
61     *
62     * @return Router
63     */
64    public function get(string $route, string $url, string $handler): Router
65    {
66        return $this->add(self::METHOD_GET, $route, $handler);
67    }
68
69    /**
70     * @param string $method
71     * @param string $route
72     * @param string $handler
73     *
74     * @return Router
75     */
76    private function add(string $method, string $route, string $handler): Router
77    {
78        $this->routes[$method][$route] = $handler;
79
80        return $this;
81    }
82
83    /**
84     * @param string $route
85     * @param string $url
86     * @param string $handler
87     *
88     * @return Router
89     */
90    public function post(string $route, string $url, string $handler): Router
91    {
92        return $this->add(self::METHOD_POST, $route, $handler);
93    }
94
95    /**
96     * @param ServerRequestInterface  $request
97     * @param RequestHandlerInterface $handler
98     *
99     * @return ResponseInterface
100     */
101    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
102    {
103        // Save the router in the container, as we'll need it to generate URLs.
104        app()->instance(self::class, $this);
105
106        // Load the routing table.
107        require Webtrees::ROOT_DIR . 'routes/web.php';
108
109        // Match the request to a route.
110        $method  = $request->getMethod();
111        $route   = $request->getQueryParams()['route'] ?? '';
112        $routing = $this->routes[$method][$route] ?? '';
113
114        // Bind the request into the container
115        app()->instance(ServerRequestInterface::class, $request);
116
117        // No route matched?
118        if ($routing === '') {
119            return $handler->handle($request);
120        }
121
122        // Firstly, apply the route middleware
123        $route_middleware = [];
124        $route_middleware = array_map('app', $route_middleware);
125
126        // Secondly, apply any module middleware
127        $module_middleware = $this->module_service->findByInterface(MiddlewareInterface::class)->all();
128
129        // Finally, run the handler using middleware
130        $handler_middleware = [new WrapHandler($routing)];
131
132        $middleware = array_merge($route_middleware, $module_middleware, $handler_middleware);
133
134        $dispatcher = new Dispatcher($middleware, app());
135
136        return $dispatcher->dispatch($request);
137    }
138}
139