xref: /webtrees/app/Http/Middleware/Router.php (revision a992e8c1f5cff3fba48e8b69ec698e4e21142dc8)
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\View;
24use Fisharebest\Webtrees\Webtrees;
25use Middleland\Dispatcher;
26use Psr\Http\Message\ResponseInterface;
27use Psr\Http\Message\ServerRequestInterface;
28use Psr\Http\Server\MiddlewareInterface;
29use Psr\Http\Server\RequestHandlerInterface;
30
31use function app;
32use function array_map;
33
34/**
35 * Simple class to help migrate to a third-party routing library.
36 */
37class Router implements MiddlewareInterface, RequestMethodInterface
38{
39    /** @var string[][] */
40    private $routes = [
41        self::METHOD_GET  => [],
42        self::METHOD_POST => [],
43    ];
44
45    /** @var ModuleService */
46    private $module_service;
47
48    /**
49     * Router constructor.
50     *
51     * @param ModuleService $module_service
52     */
53    public function __construct(ModuleService $module_service)
54    {
55        $this->module_service = $module_service;
56    }
57
58    /**
59     * @param string $route
60     * @param string $url
61     * @param string $handler
62     *
63     * @return Router
64     */
65    public function get(string $route, string $url, string $handler): Router
66    {
67        return $this->add(self::METHOD_GET, $route, $handler);
68    }
69
70    /**
71     * @param string $method
72     * @param string $route
73     * @param string $handler
74     *
75     * @return Router
76     */
77    private function add(string $method, string $route, string $handler): Router
78    {
79        $this->routes[$method][$route] = $handler;
80
81        return $this;
82    }
83
84    /**
85     * @param string $route
86     * @param string $url
87     * @param string $handler
88     *
89     * @return Router
90     */
91    public function post(string $route, string $url, string $handler): Router
92    {
93        return $this->add(self::METHOD_POST, $route, $handler);
94    }
95
96    /**
97     * @param ServerRequestInterface  $request
98     * @param RequestHandlerInterface $handler
99     *
100     * @return ResponseInterface
101     */
102    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
103    {
104        // Save the router in the container, as we'll need it to generate URLs.
105        app()->instance(self::class, $this);
106
107        // Load the routing table.
108        require Webtrees::ROOT_DIR . 'routes/web.php';
109
110        // Match the request to a route.
111        $method  = $request->getMethod();
112        $route   = $request->getQueryParams()['route'] ?? '';
113        $routing = $this->routes[$method][$route] ?? '';
114
115        // Bind the request into the container and the layout
116        app()->instance(ServerRequestInterface::class, $request);
117        View::share('request', $request);
118
119        // No route matched?
120        if ($routing === '') {
121            return $handler->handle($request);
122        }
123
124        // Firstly, apply the route middleware
125        $route_middleware = [];
126        $route_middleware = array_map('app', $route_middleware);
127
128        // Secondly, apply any module middleware
129        $module_middleware = $this->module_service->findByInterface(MiddlewareInterface::class)->all();
130
131        // Finally, run the handler using middleware
132        $handler_middleware = [new WrapHandler($routing)];
133
134        $middleware = array_merge($route_middleware, $module_middleware, $handler_middleware);
135
136        $dispatcher = new Dispatcher($middleware, app());
137
138        return $dispatcher->dispatch($request);
139    }
140}
141