xref: /webtrees/app/Http/Middleware/Router.php (revision 82e92bfae343d705cca07385d9e2dc90a3d85621)
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    /**
59     * @param string $path
60     * @param string $handler
61     *
62     * @return Router
63     */
64    public function get(string $path, string $handler): Router
65    {
66        return $this->add(self::METHOD_GET, $path, $handler);
67    }
68
69    /**
70     * @param string $method
71     * @param string $path
72     * @param string $handler
73     *
74     * @return Router
75     */
76    private function add(string $method, string $path, string $handler): Router
77    {
78        $this->routes[$method][$path] = $handler;
79
80        return $this;
81    }
82
83    /**
84     * @param string $path
85     * @param string $handler
86     *
87     * @return Router
88     */
89    public function post(string $path, string $handler): Router
90    {
91        return $this->add(self::METHOD_POST, $path, $handler);
92    }
93
94    /**
95     * @param ServerRequestInterface  $request
96     * @param RequestHandlerInterface $handler
97     *
98     * @return ResponseInterface
99     */
100    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
101    {
102        // Save the router in the container, as we'll need it to generate URLs.
103        app()->instance(self::class, $this);
104
105        // Load the routing table.
106        require Webtrees::ROOT_DIR . 'routes/web.php';
107
108        // Match the request to a route.
109        $method  = $request->getMethod();
110        $route   = $request->getQueryParams()['route'] ?? '';
111        $routing = $this->routes[$method][$route] ?? '';
112
113        // Bind the request into the container
114        app()->instance(ServerRequestInterface::class, $request);
115
116        // No route matched?
117        if ($routing === '') {
118            return $handler->handle($request);
119        }
120
121        // Firstly, apply the route middleware
122        $route_middleware = [];
123        $route_middleware = array_map('app', $route_middleware);
124
125        // Secondly, apply any module middleware
126        $module_middleware = $this->module_service->findByInterface(MiddlewareInterface::class)->all();
127
128        // Finally, run the handler using middleware
129        $handler_middleware = [new WrapHandler($routing)];
130
131        $middleware = array_merge($route_middleware, $module_middleware, $handler_middleware);
132
133        $dispatcher = new Dispatcher($middleware, app());
134
135        return $dispatcher->dispatch($request);
136    }
137}
138