Passed
Push — 2.0 ( 401112...fa4b31 )
by Greg
13:39
created

Webtrees::cliRequest()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 0
nc 1
nop 0
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
16
 */
17
18
declare(strict_types=1);
19
20
namespace Fisharebest\Webtrees;
21
22
use Closure;
23
use ErrorException;
24
use Fisharebest\Webtrees\Factories\CacheFactory;
25
use Fisharebest\Webtrees\Factories\ElementFactory;
26
use Fisharebest\Webtrees\Factories\FamilyFactory;
27
use Fisharebest\Webtrees\Factories\FilesystemFactory;
28
use Fisharebest\Webtrees\Factories\GedcomRecordFactory;
29
use Fisharebest\Webtrees\Factories\HeaderFactory;
30
use Fisharebest\Webtrees\Factories\ImageFactory;
31
use Fisharebest\Webtrees\Factories\IndividualFactory;
32
use Fisharebest\Webtrees\Factories\LocationFactory;
33
use Fisharebest\Webtrees\Factories\MediaFactory;
34
use Fisharebest\Webtrees\Factories\NoteFactory;
35
use Fisharebest\Webtrees\Factories\RepositoryFactory;
36
use Fisharebest\Webtrees\Factories\SlugFactory;
37
use Fisharebest\Webtrees\Factories\SourceFactory;
38
use Fisharebest\Webtrees\Factories\SubmissionFactory;
39
use Fisharebest\Webtrees\Factories\SubmitterFactory;
40
use Fisharebest\Webtrees\Factories\XrefFactory;
41
use Fisharebest\Webtrees\Http\Middleware\BadBotBlocker;
42
use Fisharebest\Webtrees\Http\Middleware\BootModules;
43
use Fisharebest\Webtrees\Http\Middleware\CheckForMaintenanceMode;
44
use Fisharebest\Webtrees\Http\Middleware\ClientIp;
45
use Fisharebest\Webtrees\Http\Middleware\CompressResponse;
46
use Fisharebest\Webtrees\Http\Middleware\ContentLength;
47
use Fisharebest\Webtrees\Http\Middleware\DoHousekeeping;
48
use Fisharebest\Webtrees\Http\Middleware\EmitResponse;
49
use Fisharebest\Webtrees\Http\Middleware\HandleExceptions;
50
use Fisharebest\Webtrees\Http\Middleware\LoadRoutes;
51
use Fisharebest\Webtrees\Http\Middleware\NoRouteFound;
52
use Fisharebest\Webtrees\Http\Middleware\ReadConfigIni;
53
use Fisharebest\Webtrees\Http\Middleware\Router;
54
use Fisharebest\Webtrees\Http\Middleware\SecurityHeaders;
55
use Fisharebest\Webtrees\Http\Middleware\UpdateDatabaseSchema;
56
use Fisharebest\Webtrees\Http\Middleware\UseDatabase;
57
use Fisharebest\Webtrees\Http\Middleware\UseDebugbar;
58
use Fisharebest\Webtrees\Http\Middleware\UseLanguage;
59
use Fisharebest\Webtrees\Http\Middleware\UseSession;
60
use Fisharebest\Webtrees\Http\Middleware\UseTheme;
61
use Fisharebest\Webtrees\Http\Middleware\UseTransaction;
62
use Fisharebest\Webtrees\Http\Middleware\BaseUrl;
63
use Illuminate\Container\Container;
64
use Middleland\Dispatcher;
65
use Nyholm\Psr7\Factory\Psr17Factory;
66
use Nyholm\Psr7Server\ServerRequestCreator;
67
use Psr\Container\ContainerInterface;
68
use Psr\Http\Message\ResponseFactoryInterface;
69
use Psr\Http\Message\ResponseInterface;
70
use Psr\Http\Message\ServerRequestFactoryInterface;
71
use Psr\Http\Message\ServerRequestInterface;
72
use Psr\Http\Message\StreamFactoryInterface;
73
use Psr\Http\Message\UploadedFileFactoryInterface;
74
use Psr\Http\Message\UriFactoryInterface;
75
use Psr\Http\Server\MiddlewareInterface;
76
77
use function date_default_timezone_set;
78
use function error_reporting;
79
use function is_string;
80
use function mb_internal_encoding;
81
use function set_error_handler;
82
83
use const E_ALL;
84
use const E_DEPRECATED;
85
use const E_USER_DEPRECATED;
86
87
/**
88
 * Definitions for the webtrees application.
89
 */
90
class Webtrees
91
{
92
    // The root folder of this installation
93
    public const ROOT_DIR = __DIR__ . '/../';
94
95
    // This is the location of system data, such as temporary and cache files.
96
    // The system files are always in this location.
97
    // It is also the default location of user data, such as media and GEDCOM files.
98
    // The user files could be anywhere supported by Flysystem.
99
    public const DATA_DIR = self::ROOT_DIR . 'data/';
100
101
    // Location of the file containing the database connection details.
102
    public const CONFIG_FILE = self::DATA_DIR . 'config.ini.php';
103
104
    // Location of the file that triggers maintenance mode.
105
    public const OFFLINE_FILE = self::DATA_DIR . 'offline.txt';
106
107
    // Location of our modules.
108
    public const MODULES_PATH = 'modules_v4/';
109
    public const MODULES_DIR  = self::ROOT_DIR . self::MODULES_PATH;
110
111
    // Enable debugging on development builds.
112
    public const DEBUG = self::STABILITY !== '';
113
114
    // We want to know about all PHP errors during development, and fewer in production.
115
    public const ERROR_REPORTING = self::DEBUG ? E_ALL : E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED;
116
117
    // The name of the application.
118
    public const NAME = 'webtrees';
119
120
    // Required version of database tables/columns/indexes/etc.
121
    public const SCHEMA_VERSION = 45;
122
123
    // e.g. "-dev", "-alpha", "-beta", etc.
124
    public const STABILITY = '-dev';
125
126
    // Version number
127
    public const VERSION = '2.0.18' . self::STABILITY;
128
129
    // Project website.
130
    public const URL = 'https://webtrees.net/';
131
132
    // FAQ links
133
    public const URL_FAQ_EMAIL = 'https://webtrees.net/faq/email';
134
135
    // Project website.
136
    public const GEDCOM_PDF = 'https://webtrees.net/downloads/gedcom-5-5-1.pdf';
137
138
    private const MIDDLEWARE = [
139
        EmitResponse::class,
140
        SecurityHeaders::class,
141
        ReadConfigIni::class,
142
        BaseUrl::class,
143
        HandleExceptions::class,
144
        ClientIp::class,
145
        ContentLength::class,
146
        CompressResponse::class,
147
        BadBotBlocker::class,
148
        UseDatabase::class,
149
        UseDebugbar::class,
150
        UpdateDatabaseSchema::class,
151
        UseSession::class,
152
        UseLanguage::class,
153
        CheckForMaintenanceMode::class,
154
        UseTheme::class,
155
        DoHousekeeping::class,
156
        UseTransaction::class,
157
        LoadRoutes::class,
158
        BootModules::class,
159
        Router::class,
160
        NoRouteFound::class,
161
    ];
162
163
    /**
164
     * Initialise the application.
165
     *
166
     * @return void
167
     */
168
    public function bootstrap(): void
169
    {
170
        // Show all errors and warnings in development, fewer in production.
171
        error_reporting(self::ERROR_REPORTING);
172
        set_error_handler($this->phpErrorHandler());
173
174
        // All modern software uses UTF-8 encoding.
175
        mb_internal_encoding('UTF-8');
176
177
        // Use UTC internally and convert to local time when displaying datetimes.
178
        date_default_timezone_set('UTC');
179
180
        // Factory objects
181
        Registry::cache(new CacheFactory());
182
        Registry::familyFactory(new FamilyFactory());
183
        Registry::filesystem(new FilesystemFactory());
184
        Registry::elementFactory(new ElementFactory());
185
        Registry::gedcomRecordFactory(new GedcomRecordFactory());
186
        Registry::headerFactory(new HeaderFactory());
187
        Registry::imageFactory(new ImageFactory());
188
        Registry::individualFactory(new IndividualFactory());
189
        Registry::locationFactory(new LocationFactory());
190
        Registry::mediaFactory(new MediaFactory());
191
        Registry::noteFactory(new NoteFactory());
192
        Registry::repositoryFactory(new RepositoryFactory());
193
        Registry::slugFactory(new SlugFactory());
194
        Registry::sourceFactory(new SourceFactory());
195
        Registry::submissionFactory(new SubmissionFactory());
196
        Registry::submitterFactory(new SubmitterFactory());
197
        Registry::xrefFactory(new XrefFactory());
198
    }
199
200
    /**
201
     * Respond to a CLI request.
202
     *
203
     * @return void
204
     */
205
    public function cliRequest(): void
206
    {
207
        // CLI handler will go here.
208
    }
209
210
    /**
211
     * Response to an HTTP request.
212
     *
213
     * @return ResponseInterface
214
     */
215
    public function httpRequest(): ResponseInterface
216
    {
217
        // PSR7 messages and PSR17 message-factories
218
        self::set(ResponseFactoryInterface::class, Psr17Factory::class);
219
        self::set(ServerRequestFactoryInterface::class, Psr17Factory::class);
220
        self::set(StreamFactoryInterface::class, Psr17Factory::class);
221
        self::set(UploadedFileFactoryInterface::class, Psr17Factory::class);
222
        self::set(UriFactoryInterface::class, Psr17Factory::class);
223
224
        $request = $this->captureRequest();
225
226
        return self::dispatch($request, self::MIDDLEWARE);
227
    }
228
229
    /**
230
     * @param ServerRequestInterface            $request
231
     * @param array<string|MiddlewareInterface> $middleware
232
     *
233
     * @return ResponseInterface
234
     */
235
    public static function dispatch(ServerRequestInterface $request, array $middleware): ResponseInterface
236
    {
237
        $dispatcher = new Dispatcher($middleware, self::container());
238
239
        return $dispatcher->dispatch($request);
240
    }
241
242
    /**
243
     * An error handler that can be passed to set_error_handler().
244
     *
245
     * @return Closure
246
     */
247
    private function phpErrorHandler(): Closure
248
    {
249
        return static function (int $errno, string $errstr, string $errfile, int $errline): bool {
250
            // Ignore errors that are silenced with '@'
251
            if (error_reporting() & $errno) {
252
                throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
253
            }
254
255
            return true;
256
        };
257
    }
258
259
    /**
260
     * Build the request from the PHP super-globals.
261
     *
262
     * @return ServerRequestInterface
263
     */
264
    private function captureRequest(): ServerRequestInterface
265
    {
266
        return self::make(ServerRequestCreator::class)->fromGlobals();
267
    }
268
269
    /**
270
     * @return ContainerInterface
271
     */
272
    public static function container(): ContainerInterface
273
    {
274
        return Container::getInstance();
275
    }
276
277
    /**
278
     * Make an object, using dependency injection.
279
     *
280
     * @param string $class
281
     *
282
     * @return mixed
283
     */
284
    public static function make(string $class)
285
    {
286
        return Container::getInstance()->make($class);
287
    }
288
289
    /**
290
     * Write a value into the container.
291
     *
292
     * @param string        $abstract
293
     * @param string|object $concrete
294
     */
295
    public static function set(string $abstract, $concrete): void
296
    {
297
        if (is_string($concrete)) {
298
            Container::getInstance()->bind($abstract, $concrete);
299
        } else {
300
            Container::getInstance()->instance($abstract, $concrete);
301
        }
302
    }
303
}
304