xref: /webtrees/index.php (revision 5fe1add5cdfc22777f7b73676b6e457449b836d8)
1<?php
2/**
3 * webtrees: online genealogy
4 * Copyright (C) 2018 webtrees development team
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16declare(strict_types=1);
17
18namespace Fisharebest\Webtrees;
19
20use Closure;
21use Exception;
22use Fisharebest\Webtrees\Exceptions\Handler;
23use Fisharebest\Webtrees\Http\Middleware\CheckCsrf;
24use Fisharebest\Webtrees\Http\Middleware\CheckForMaintenanceMode;
25use Fisharebest\Webtrees\Http\Middleware\MiddlewareInterface;
26use Fisharebest\Webtrees\Http\Middleware\PageHitCounter;
27use Fisharebest\Webtrees\Http\Middleware\UseTransaction;
28use Symfony\Component\HttpFoundation\JsonResponse;
29use Symfony\Component\HttpFoundation\RedirectResponse;
30use Symfony\Component\HttpFoundation\Request;
31use Symfony\Component\HttpFoundation\Response;
32
33// Bootstrap the application
34require 'includes/session.php';
35
36DebugBar::startMeasure('routing');
37
38// The HTTP request.
39$request = Request::createFromGlobals();
40$method  = $request->getMethod();
41$route   = $request->get('route');
42
43try {
44	// Most requests will need the current tree and user.
45	$all_trees = Tree::getAll();
46
47	$tree = $all_trees[$request->get('ged')] ?? null;
48
49	// No tree specified/available?  Choose one.
50	if ($tree === null && $method === 'GET') {
51		$tree = $all_trees[Site::getPreference('DEFAULT_GEDCOM')] ?? array_values($all_trees)[0] ?? null;
52	}
53
54	$request->attributes->set('tree', $tree);
55	$request->attributes->set('user', Auth::user());
56
57	// Most layouts will require a tree for the page header/footer
58	View::share('tree', $tree);
59
60	// Load the routing table.
61	$routes = require 'routes/web.php';
62
63	// Find the action for the selected route
64	$controller_action = $routes[$method . ':' . $route] ?? 'ErrorController@noRouteFound';
65
66	// Create the controller
67	list($controller_name, $action) = explode('@', $controller_action);
68	$controller_class = __NAMESPACE__ . '\\Http\\Controllers\\' . $controller_name;
69	$controller       = new $controller_class;
70
71	DebugBar::stopMeasure('routing');
72
73	// Note that we can't stop this timer, as running the action will
74	// generate the response - which includes (and stops) the timer
75	DebugBar::startMeasure('controller_action', $controller_action);
76
77	$middleware_stack = [
78		new CheckForMaintenanceMode,
79	];
80
81	if ($method === 'GET') {
82		$middleware_stack[] = new PageHitCounter;
83	}
84
85	if ($method === 'POST') {
86		$middleware_stack[] = new UseTransaction;
87		$middleware_stack[] = new CheckCsrf;
88	}
89
90	// Apply the middleware using the "onion" pattern.
91	$pipeline = array_reduce($middleware_stack, function (Closure $next, MiddlewareInterface $middleware): Closure {
92		// Create a closure to apply the middleware.
93		return function (Request $request) use ($middleware, $next): Response {
94			return $middleware->handle($request, $next);
95		};
96	}, function (Request $request) use ($controller, $action): Response {
97		// Create a closure to generate the response.
98		return call_user_func([$controller, $action], $request);
99	});
100
101	$response = call_user_func($pipeline, $request);
102} catch (Exception $exception) {
103	DebugBar::addThrowable($exception);
104
105	$response = (new Handler)->render($request, $exception);
106}
107
108// Send response
109if ($response instanceof RedirectResponse) {
110	// Show the debug data on the next page
111	DebugBar::stackData();
112} elseif ($response instanceof JsonResponse) {
113	// Use HTTP headers and some jQuery to add debug to the current page.
114	DebugBar::sendDataInHeaders();
115}
116
117$response->prepare($request)->send();
118