diff options
47 files changed, 414 insertions, 382 deletions
diff --git a/app/Database.php b/app/Database.php index b5004f5623..d2d7022a80 100644 --- a/app/Database.php +++ b/app/Database.php @@ -37,7 +37,7 @@ class Database $config['dbtype'] = $config['dbtype'] ?? 'mysql'; if ($config['dbtype'] === 'sqlite') { - $config['dbname'] = WT_ROOT . 'data/' . $config['dbname'] . '.sqlite'; + $config['dbname'] = Webtrees::ROOT_DIR . 'data/' . $config['dbname'] . '.sqlite'; } $capsule = new DB(); diff --git a/app/DebugBar.php b/app/DebugBar.php index 1fa24534d8..8df049566e 100644 --- a/app/DebugBar.php +++ b/app/DebugBar.php @@ -46,14 +46,12 @@ class DebugBar * * @return void */ - public static function init(bool $enable = true): void + public static function enable(): void { - if ($enable) { - self::$debugbar = new StandardDebugBar(); - self::$debugbar->addCollector(new ViewCollector()); + self::$debugbar = new StandardDebugBar(); + self::$debugbar->addCollector(new ViewCollector()); - self::$renderer = self::$debugbar->getJavascriptRenderer('./vendor/maximebf/debugbar/src/DebugBar/Resources/'); - } + self::$renderer = self::$debugbar->getJavascriptRenderer('./vendor/maximebf/debugbar/src/DebugBar/Resources/'); } /** diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php deleted file mode 100644 index ac8dc60932..0000000000 --- a/app/Exceptions/Handler.php +++ /dev/null @@ -1,98 +0,0 @@ -<?php -/** - * webtrees: online genealogy - * Copyright (C) 2019 webtrees development team - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -declare(strict_types=1); - -namespace Fisharebest\Webtrees\Exceptions; - -use Closure; -use ErrorException; -use Fisharebest\Webtrees\Http\Controllers\ErrorController; -use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\ServerRequestInterface; -use Symfony\Component\HttpKernel\Exception\HttpException; -use Throwable; -use function error_reporting; -use function ob_end_clean; -use function ob_get_level; - -/** - * Convert an exception into an HTTP response - */ -class Handler -{ - /** - * An error handler that can be passed to set_error_handler(). - * Converts errors to exceptions - * - * @return Closure - */ - public static function phpErrorHandler(): Closure - { - return static function (int $errno, string $errstr, string $errfile, int $errline): bool { - // Ignore errors that are silenced with '@' - if (error_reporting() & $errno) { - throw new ErrorException($errstr, 0, $errno, $errfile, $errline); - } - - return true; - }; - } - - /** - * A final exception handler that can be passed to set_exception_handler(). - * Display any exception that are not caught by the middleware exception handler. - * Typically, this will be errors in index.php, errors in the exception handler - * and errors while displaying errors. - * - * @return Closure - */ - public static function phpExceptionHandler(): Closure - { - return static function (Throwable $ex): void { - $trace = $ex->getMessage() . PHP_EOL . $ex->getTraceAsString(); - $trace = str_replace(WT_ROOT, '…/', $trace); - - while (ob_get_level() > 0) { - ob_end_clean(); - } - - echo '<html lang="en"><head><title>Error</title><meta charset="UTF-8"></head><body><pre>' . $trace . '</pre></body></html>'; - }; - } - - /** - * Render an exception into an HTTP response. - * - * @param ServerRequestInterface $request - * @param Throwable $exception - * - * @return ResponseInterface - */ - public function render(ServerRequestInterface $request, Throwable $exception): ResponseInterface - { - $controller = new ErrorController(); - - if ($exception instanceof HttpException) { - if ($request->getHeaderLine('X-Requested-With') !== '') { - return $controller->ajaxErrorResponse($exception); - } - - return $controller->errorResponse($exception); - } - - return $controller->unhandledExceptionResponse($request, $exception); - } -} diff --git a/app/Helpers/functions.php b/app/Helpers/functions.php index 5d9fb57f30..d4ac3179ed 100644 --- a/app/Helpers/functions.php +++ b/app/Helpers/functions.php @@ -55,7 +55,7 @@ function asset(string $path): string if (Webtrees::STABILITY === '') { $version = Webtrees::VERSION; } else { - $version = filemtime(WT_ROOT . 'public/' . $path); + $version = filemtime(Webtrees::ROOT_DIR . 'public/' . $path); } return 'public/' . $path . '?v=' . $version; diff --git a/app/Http/Controllers/Admin/ControlPanelController.php b/app/Http/Controllers/Admin/ControlPanelController.php index 960916aa50..ae532c9ae4 100644 --- a/app/Http/Controllers/Admin/ControlPanelController.php +++ b/app/Http/Controllers/Admin/ControlPanelController.php @@ -43,6 +43,7 @@ use Fisharebest\Webtrees\Services\ServerCheckService; use Fisharebest\Webtrees\Services\UpgradeService; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; use Illuminate\Database\Capsule\Manager as DB; use Illuminate\Database\Query\JoinClause; use Illuminate\Support\Collection; @@ -73,7 +74,7 @@ class ControlPanelController extends AbstractAdminController ServerCheckService $server_check_service, UserService $user_service ): ResponseInterface { - $filesystem = new Filesystem(new Local(WT_ROOT)); + $filesystem = new Filesystem(new Local(Webtrees::ROOT_DIR)); $files_to_delete = $housekeeping_service->deleteOldWebtreesFiles($filesystem); return $this->viewResponse('admin/control-panel', [ diff --git a/app/Http/Controllers/Admin/UpgradeController.php b/app/Http/Controllers/Admin/UpgradeController.php index fea8b9332b..277d7bcfc7 100644 --- a/app/Http/Controllers/Admin/UpgradeController.php +++ b/app/Http/Controllers/Admin/UpgradeController.php @@ -90,7 +90,7 @@ class UpgradeController extends AbstractAdminController $this->filesystem = $filesystem; $this->upgrade_service = $upgrade_service; - $this->root_filesystem = new Filesystem(new CachedAdapter(new Local(WT_ROOT), new Memory())); + $this->root_filesystem = new Filesystem(new CachedAdapter(new Local(Webtrees::ROOT_DIR), new Memory())); $this->temporary_filesystem = new Filesystem(new ChrootAdapter($this->filesystem, self::UPGRADE_FOLDER)); } diff --git a/app/Http/Controllers/ErrorController.php b/app/Http/Controllers/ErrorController.php deleted file mode 100644 index b77e36736c..0000000000 --- a/app/Http/Controllers/ErrorController.php +++ /dev/null @@ -1,93 +0,0 @@ -<?php -/** - * webtrees: online genealogy - * Copyright (C) 2019 webtrees development team - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -declare(strict_types=1); - -namespace Fisharebest\Webtrees\Http\Controllers; - -use Fig\Http\Message\StatusCodeInterface; -use Fisharebest\Webtrees\Auth; -use Fisharebest\Webtrees\Log; -use Fisharebest\Webtrees\Tree; -use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\ServerRequestInterface; -use Symfony\Component\HttpKernel\Exception\HttpException; -use Throwable; -use function str_replace; - -/** - * Controller for error handling. - */ -class ErrorController extends AbstractBaseController implements StatusCodeInterface -{ - /** - * Convert an exception into an error message - * - * @param HttpException $ex - * - * @return ResponseInterface - */ - public function errorResponse(HttpException $ex): ResponseInterface - { - return $this->viewResponse('components/alert-danger', [ - 'alert' => $ex->getMessage(), - 'title' => $ex->getMessage(), - ], $ex->getStatusCode()); - } - - /** - * Convert an exception into an error message - * - * @param HttpException $ex - * - * @return ResponseInterface - */ - public function ajaxErrorResponse(HttpException $ex): ResponseInterface - { - return response(view('components/alert-danger', [ - 'alert' => $ex->getMessage(), - ]), $ex->getStatusCode()); - } - - /** - * Convert an exception into an error message - * - * @param ServerRequestInterface $request - * @param Throwable $ex - * - * @return ResponseInterface - */ - public function unhandledExceptionResponse(ServerRequestInterface $request, Throwable $ex): ResponseInterface - { - // Create a stack dump for the exception - $trace = $ex->getMessage() . PHP_EOL . $ex->getTraceAsString(); - $trace = str_replace(WT_ROOT, '…/', $trace); - - try { - Log::addErrorLog($trace); - } catch (Throwable $ex2) { - // Must have been a problem with the database. Nothing we can do here. - } - - if ($request->getHeaderLine('X-Requested-With') !== '') { - return response(view('components/alert-danger', ['alert' => $trace]), self::STATUS_INTERNAL_SERVER_ERROR); - } - - return $this->viewResponse('errors/unhandled-exception', [ - 'title' => 'Error', - 'error' => $trace, - ], self::STATUS_INTERNAL_SERVER_ERROR); - } -} diff --git a/app/Http/Controllers/PlaceHierarchyController.php b/app/Http/Controllers/PlaceHierarchyController.php index de0d582c80..b836760b75 100644 --- a/app/Http/Controllers/PlaceHierarchyController.php +++ b/app/Http/Controllers/PlaceHierarchyController.php @@ -271,7 +271,7 @@ class PlaceHierarchyController extends AbstractBaseController $placeObj = new Place($reference, $tree); $places = $placeObj->getChildPlaces(); $features = []; - $flag_path = Webtrees::MODULES_PATH . 'openstreetmap/'; + $flag_path = Webtrees::MODULES_DIR . 'openstreetmap/'; $showlink = true; if (empty($places)) { $places[] = $placeObj; diff --git a/app/Http/Controllers/SetupController.php b/app/Http/Controllers/SetupController.php index 453e0199ca..cb992c8979 100644 --- a/app/Http/Controllers/SetupController.php +++ b/app/Http/Controllers/SetupController.php @@ -17,6 +17,7 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\Controllers; +use function app; use function define; use Exception; use Fisharebest\Localization\Locale; @@ -32,6 +33,8 @@ use Fisharebest\Webtrees\Services\ServerCheckService; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Session; use Fisharebest\Webtrees\Webtrees; +use Illuminate\Cache\ArrayStore; +use Illuminate\Cache\Repository; use Illuminate\Database\Capsule\Manager; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -100,8 +103,10 @@ class SetupController extends AbstractBaseController */ public function setup(ServerRequestInterface $request): ResponseInterface { - // Required by I18N. + // Mini "bootstrap" define('WT_DATA_DIR', 'data/'); + app()->instance(ServerRequestInterface::class, $request); + app()->instance('cache.array', new Repository(new ArrayStore())); $data = $this->userData($request); @@ -327,7 +332,7 @@ class SetupController extends AbstractBaseController { // Try to create the SQLite database, if it does not already exist. if ($data['dbtype'] === 'sqlite') { - touch(WT_ROOT . 'data/' . $data['dbname'] . '.sqlite'); + touch(Webtrees::ROOT_DIR . 'data/' . $data['dbname'] . '.sqlite'); } // Try to create the MySQL database, if it does not already exist. diff --git a/app/Http/Middleware/CheckForMaintenanceMode.php b/app/Http/Middleware/CheckForMaintenanceMode.php index 25be00b806..f134ef4ed3 100644 --- a/app/Http/Middleware/CheckForMaintenanceMode.php +++ b/app/Http/Middleware/CheckForMaintenanceMode.php @@ -18,6 +18,7 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\Middleware; use Fig\Http\Message\StatusCodeInterface; +use Fisharebest\Webtrees\Webtrees; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; @@ -36,11 +37,9 @@ class CheckForMaintenanceMode implements MiddlewareInterface */ public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { - $file = WT_ROOT . 'data/offline.txt'; - - if (file_exists($file)) { + if (file_exists(Webtrees::OFFLINE_FILE)) { $html = view('layouts/offline', [ - 'message' => file_get_contents($file), + 'message' => file_get_contents(Webtrees::OFFLINE_FILE), 'url' => $request->getUri(), ]); diff --git a/app/Http/Middleware/DoHousekeeping.php b/app/Http/Middleware/DoHousekeeping.php index a1799d20e1..2c9139bc00 100644 --- a/app/Http/Middleware/DoHousekeeping.php +++ b/app/Http/Middleware/DoHousekeeping.php @@ -19,6 +19,7 @@ namespace Fisharebest\Webtrees\Http\Middleware; use Fig\Http\Message\RequestMethodInterface; use Fisharebest\Webtrees\Services\HousekeepingService; +use Fisharebest\Webtrees\Webtrees; use League\Flysystem\Adapter\Local; use League\Flysystem\Filesystem; use League\Flysystem\FilesystemInterface; @@ -90,7 +91,7 @@ class DoHousekeeping implements MiddlewareInterface private function runHousekeeping(): void { $data_filesystem = app(FilesystemInterface::class); - $root_filesystem = new Filesystem(new Local(WT_ROOT)); + $root_filesystem = new Filesystem(new Local(Webtrees::ROOT_DIR)); // Clear files in the (user-specified) data folder - which might not be local files $this->housekeeping_service->deleteOldFiles($data_filesystem, 'cache', self::MAX_CACHE_AGE); diff --git a/app/Http/Middleware/HandleExceptions.php b/app/Http/Middleware/HandleExceptions.php index a43ad53ca8..415e139a45 100644 --- a/app/Http/Middleware/HandleExceptions.php +++ b/app/Http/Middleware/HandleExceptions.php @@ -17,50 +17,102 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\Middleware; -use Fisharebest\Webtrees\Http\Controllers\ErrorController; +use Fig\Http\Message\StatusCodeInterface; +use Fisharebest\Webtrees\Http\ViewResponseTrait; +use Fisharebest\Webtrees\Log; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; use Symfony\Component\HttpKernel\Exception\HttpException; use Throwable; +use function dirname; +use function response; +use function str_replace; +use function view; +use const PHP_EOL; /** * Middleware to handle and render errors. */ -class HandleExceptions implements MiddlewareInterface +class HandleExceptions implements MiddlewareInterface, StatusCodeInterface { - /** @var ErrorController */ - private $error_controller; + use ViewResponseTrait; /** - * ExceptionHandler constructor. + * @param ServerRequestInterface $request + * @param RequestHandlerInterface $handler * - * @param ErrorController $error_controller + * @return ResponseInterface + * @throws Throwable */ - public function __construct(ErrorController $error_controller) + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { - $this->error_controller = $error_controller; + try { + try { + return $handler->handle($request); + } catch (HttpException $exception) { + $original_exception = $exception; + + return $this->httpExceptionResponse($request, $exception); + } catch (Throwable $exception) { + $original_exception = $exception; + + return $this->unhandledExceptionResponse($request, $exception); + } + } catch (Throwable $exception) { + // If we can't handle the exception, rethrow it. + throw $original_exception; + } } /** - * @param ServerRequestInterface $request - * @param RequestHandlerInterface $handler + * @param ServerRequestInterface $request + * @param HttpException $exception * * @return ResponseInterface */ - public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + private function httpExceptionResponse(ServerRequestInterface $request, HttpException $exception): ResponseInterface { - try { - return $handler->handle($request); - } catch (HttpException $exception) { - if ($request->getHeaderLine('X-Requested-With') !== '') { - return $this->error_controller->ajaxErrorResponse($exception); - } + if ($request->getHeaderLine('X-Requested-With') !== '') { + return $this->viewResponse('components/alert-danger', [ + 'alert' => $exception->getMessage(), + 'title' => $exception->getMessage(), + ], $exception->getStatusCode()); + } + + return response(view('components/alert-danger', [ + 'alert' => $exception->getMessage(), + 'title' => $exception->getMessage(), + ]), $exception->getStatusCode()); + } + + /** + * @param ServerRequestInterface $request + * @param Throwable $exception + * + * @return ResponseInterface + */ + private function unhandledExceptionResponse(ServerRequestInterface $request, Throwable $exception): ResponseInterface + { + // Create a stack dump for the exception + $base_path = dirname(__DIR__, 3); + $trace = $exception->getMessage() . PHP_EOL . $exception->getTraceAsString(); + $trace = str_replace($base_path, '…', $trace); - return $this->error_controller->errorResponse($exception); + try { + Log::addErrorLog($trace); } catch (Throwable $exception) { - return $this->error_controller->unhandledExceptionResponse($request, $exception); + // Must have been a problem with the database. Nothing we can do here. } + + if ($request->getHeaderLine('X-Requested-With') !== '') { + return response(view('components/alert-danger', ['alert' => $trace]), self::STATUS_INTERNAL_SERVER_ERROR); + } + + return $this->viewResponse('errors/unhandled-exception', [ + 'title' => 'Error', + 'error' => $trace, + ], self::STATUS_INTERNAL_SERVER_ERROR); } } diff --git a/app/Http/Middleware/ModuleMiddleware.php b/app/Http/Middleware/ModuleMiddleware.php index 0fd245c2c8..64efb7666c 100644 --- a/app/Http/Middleware/ModuleMiddleware.php +++ b/app/Http/Middleware/ModuleMiddleware.php @@ -40,8 +40,6 @@ class ModuleMiddleware implements MiddlewareInterface } /** - * Update the database schema, if necessary. - * * @param ServerRequestInterface $request * @param RequestHandlerInterface $handler * diff --git a/app/Http/Middleware/PhpEnvironment.php b/app/Http/Middleware/PhpEnvironment.php new file mode 100644 index 0000000000..4f399403e0 --- /dev/null +++ b/app/Http/Middleware/PhpEnvironment.php @@ -0,0 +1,48 @@ +<?php +/** + * webtrees: online genealogy + * Copyright (C) 2019 webtrees development team + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +declare(strict_types=1); + +namespace Fisharebest\Webtrees\Http\Middleware; + +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; +use function date_default_timezone_set; +use function mb_internal_encoding; + +/** + * Middleware to set set the PHP environment. + */ +class PhpEnvironment implements MiddlewareInterface +{ + /** + * @param ServerRequestInterface $request + * @param RequestHandlerInterface $handler + * + * @return ResponseInterface + */ + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + // All modern software uses UTF-8 encoding. + mb_internal_encoding('UTF-8'); + + // We use UTC internally and convert to local time when displaying datetimes. + date_default_timezone_set('UTC'); + + return $handler->handle($request); + } +} diff --git a/app/Http/Middleware/RequestRouter.php b/app/Http/Middleware/RequestRouter.php index f7fa7228d0..ba3e4dc16f 100644 --- a/app/Http/Middleware/RequestRouter.php +++ b/app/Http/Middleware/RequestRouter.php @@ -17,6 +17,7 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\Middleware; +use Fisharebest\Webtrees\DebugBar; use Illuminate\Support\Str; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -50,6 +51,9 @@ class RequestRouter implements MiddlewareInterface // Find the routing for the selected route. $routing = $routes[$request->getMethod() . ':' . $route] ?? ''; + // This timer gets stopped automatically when we generate the response. + DebugBar::startMeasure('controller_action'); + // No route matched? if ($routing === '') { return $handler->handle($request); diff --git a/app/Http/Middleware/UseDebugbar.php b/app/Http/Middleware/UseDebugbar.php index 8410e4a2e1..aa2e080faa 100644 --- a/app/Http/Middleware/UseDebugbar.php +++ b/app/Http/Middleware/UseDebugbar.php @@ -17,15 +17,22 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\Middleware; +use DebugBar\StandardDebugBar; use Fig\Http\Message\StatusCodeInterface; use Fisharebest\Webtrees\DebugBar; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; +use function class_exists; /** * Middleware to add debugging info to the PHP debugbar. + * Use `composer install --dev` on a development build to enable. + * Note that you may need to increase the size of the fcgi buffers on nginx. + * e.g. add these lines to your fastcgi_params file: + * fastcgi_buffers 16 16m; + * fastcgi_buffer_size 32m; */ class UseDebugbar implements MiddlewareInterface, StatusCodeInterface { @@ -37,17 +44,14 @@ class UseDebugbar implements MiddlewareInterface, StatusCodeInterface */ public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { - if (class_exists(DebugBar::class)) { - // This timer gets stopped automatically when we generate the response. - DebugBar::startMeasure('controller_action'); + if (class_exists(StandardDebugBar::class)) { + DebugBar::enable(); + $response = $handler->handle($request); - $status_code = $response->getStatusCode(); - if ($status_code === self::STATUS_FOUND || $status_code === self::STATUS_MOVED_PERMANENTLY) { - // Show the debug data on the next page + if ($this->shouldSendDataOnNextPage($response)) { DebugBar::stackData(); - } elseif ($request->getHeaderLine('X-Requested-With') !== '') { - // Use HTTP headers and some jQuery to add debug to the current page. + } elseif ($this->shouldSendDataInHeaders($request)) { DebugBar::sendDataInHeaders(); } @@ -56,4 +60,26 @@ class UseDebugbar implements MiddlewareInterface, StatusCodeInterface return $handler->handle($request); } + + /** + * @param ResponseInterface $response + * + * @return bool + */ + private function shouldSendDataOnNextPage(ResponseInterface $response): bool + { + $status_code = $response->getStatusCode(); + + return $status_code === self::STATUS_FOUND || $status_code === self::STATUS_MOVED_PERMANENTLY; + } + + /** + * @param ServerRequestInterface $request + * + * @return bool + */ + private function shouldSendDataInHeaders(ServerRequestInterface $request): bool + { + return $request->getHeaderLine('X-Requested-With') !== ''; + } } diff --git a/app/I18N.php b/app/I18N.php index 48a5129868..43d45c26a6 100644 --- a/app/I18N.php +++ b/app/I18N.php @@ -316,7 +316,7 @@ class I18N if ($code !== '') { // Create the specified locale self::$locale = Locale::create($code); - } elseif (Session::has('language') && file_exists(WT_ROOT . 'resources/lang/' . Session::get('language') . '/messages.mo')) { + } elseif (Session::has('language') && file_exists(Webtrees::ROOT_DIR . 'resources/lang/' . Session::get('language') . '/messages.mo')) { // Select a previously used locale self::$locale = Locale::create(Session::get('language')); } else { @@ -349,7 +349,7 @@ class I18N } // Load the translation file - $translation_file = WT_ROOT . 'resources/lang/' . self::$locale->languageTag() . '/messages.mo'; + $translation_file = Webtrees::ROOT_DIR . 'resources/lang/' . self::$locale->languageTag() . '/messages.mo'; if (!file_exists($translation_file)) { // Test and dev environments may not have the compiled translations diff --git a/app/Module/AbstractModule.php b/app/Module/AbstractModule.php index 23d0d575e0..9c63dc4156 100644 --- a/app/Module/AbstractModule.php +++ b/app/Module/AbstractModule.php @@ -20,6 +20,7 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Webtrees\Auth; use Fisharebest\Webtrees\Http\ViewResponseTrait; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; use Illuminate\Database\Capsule\Manager as DB; use Illuminate\Support\Collection; use stdClass; @@ -235,6 +236,6 @@ abstract class AbstractModule implements ModuleInterface */ public function resourcesFolder(): string { - return WT_ROOT . 'resources/'; + return Webtrees::ROOT_DIR . 'resources/'; } } diff --git a/app/Module/FanChartModule.php b/app/Module/FanChartModule.php index 28defada7d..0071badacf 100644 --- a/app/Module/FanChartModule.php +++ b/app/Module/FanChartModule.php @@ -24,6 +24,7 @@ use Fisharebest\Webtrees\Individual; use Fisharebest\Webtrees\Menu; use Fisharebest\Webtrees\Services\ChartService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -307,7 +308,7 @@ class FanChartModule extends AbstractModule implements ModuleChartInterface (int) $tx, (int) $ty, $foreground, - WT_ROOT . 'resources/fonts/DejaVuSans.ttf', + Webtrees::ROOT_DIR . 'resources/fonts/DejaVuSans.ttf', $text ); diff --git a/app/Module/ModuleThemeTrait.php b/app/Module/ModuleThemeTrait.php index f43f0ed197..bec64d4166 100644 --- a/app/Module/ModuleThemeTrait.php +++ b/app/Module/ModuleThemeTrait.php @@ -26,6 +26,7 @@ use Fisharebest\Webtrees\Individual; use Fisharebest\Webtrees\Menu; use Fisharebest\Webtrees\Services\ModuleService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; use Psr\Http\Message\ServerRequestInterface; use function app; @@ -46,13 +47,13 @@ trait ModuleThemeTrait public function icon(Fact $fact): string { $asset = 'public/css/' . $this->name() . '/images/facts/' . $fact->getTag() . '.png'; - if (file_exists(WT_ROOT . 'public' . $asset)) { + if (file_exists(Webtrees::ROOT_DIR . 'public' . $asset)) { return '<img src="' . e(asset($asset)) . '" title="' . GedcomTag::getLabel($fact->getTag()) . '">'; } // Spacer image - for alignment - until we move to a sprite. $asset = 'public/css/' . $this->name() . '/images/facts/NULL.png'; - if (file_exists(WT_ROOT . 'public' . $asset)) { + if (file_exists(Webtrees::ROOT_DIR . 'public' . $asset)) { return '<img src="' . e(asset($asset)) . '">'; } diff --git a/app/Module/PedigreeMapModule.php b/app/Module/PedigreeMapModule.php index 3a6037e0f6..24c35a8550 100644 --- a/app/Module/PedigreeMapModule.php +++ b/app/Module/PedigreeMapModule.php @@ -316,7 +316,7 @@ class PedigreeMapModule extends AbstractModule implements ModuleChartInterface private function getMapProviderData(ServerRequestInterface $request): ?array { if (self::$map_providers === null) { - $providersFile = WT_ROOT . Webtrees::MODULES_PATH . 'openstreetmap/providers/providers.xml'; + $providersFile = Webtrees::MODULES_DIR . 'openstreetmap/providers/providers.xml'; self::$map_selections = [ 'provider' => $this->getPreference('provider', 'openstreetmap'), 'style' => $this->getPreference('provider_style', 'mapnik'), diff --git a/app/Module/PlacesModule.php b/app/Module/PlacesModule.php index 062dde1cdb..0918480a85 100644 --- a/app/Module/PlacesModule.php +++ b/app/Module/PlacesModule.php @@ -250,7 +250,7 @@ class PlacesModule extends AbstractModule implements ModuleTabInterface private function getMapProviderData(ServerRequestInterface $request): ?array { if (self::$map_providers === null) { - $providersFile = WT_ROOT . Webtrees::MODULES_PATH . 'openstreetmap/providers/providers.xml'; + $providersFile = Webtrees::MODULES_DIR . 'openstreetmap/providers/providers.xml'; self::$map_selections = [ 'provider' => $this->getPreference('provider', 'openstreetmap'), 'style' => $this->getPreference('provider_style', 'mapnik'), diff --git a/app/Services/HousekeepingService.php b/app/Services/HousekeepingService.php index 1c361a5c4c..81869b7808 100644 --- a/app/Services/HousekeepingService.php +++ b/app/Services/HousekeepingService.php @@ -46,12 +46,12 @@ class HousekeepingService 'manageservers.php', 'media.php', 'module_admin.php', - //WT_ROOT.'modules', // Do not delete - users may have stored custom modules/data here + //'modules', // Do not delete - users may have stored custom modules/data here 'opensearch.php', 'PEAR.php', 'pgv_to_wt.php', 'places', - //WT_ROOT.'robots.txt', // Do not delete this - it may contain user data + //'robots.txt', // Do not delete this - it may contain user data 'serviceClientTest.php', 'siteconfig.php', 'SOAP', diff --git a/app/Services/ModuleService.php b/app/Services/ModuleService.php index ad61873fff..a97d20d529 100644 --- a/app/Services/ModuleService.php +++ b/app/Services/ModuleService.php @@ -552,7 +552,7 @@ class ModuleService */ private function customModules(): Collection { - $pattern = WT_ROOT . Webtrees::MODULES_PATH . '*/module.php'; + $pattern = Webtrees::MODULES_DIR . '*/module.php'; $filenames = glob($pattern, GLOB_NOSORT); return Collection::make($filenames) diff --git a/app/Services/UpgradeService.php b/app/Services/UpgradeService.php index 6bf03aeec0..9283c5264f 100644 --- a/app/Services/UpgradeService.php +++ b/app/Services/UpgradeService.php @@ -252,13 +252,13 @@ class UpgradeService { $message = I18N::translate('This website is being upgraded. Try again in a few minutes.'); - file_put_contents(WT_ROOT . self::LOCK_FILE, $message); + file_put_contents(Webtrees::OFFLINE_FILE, $message); } public function endMaintenanceMode(): void { - if (file_exists(WT_ROOT . self::LOCK_FILE)) { - unlink(WT_ROOT . self::LOCK_FILE); + if (file_exists(Webtrees::OFFLINE_FILE)) { + unlink(Webtrees::OFFLINE_FILE); } } diff --git a/app/View.php b/app/View.php index cd60b1749b..bde55e66b4 100644 --- a/app/View.php +++ b/app/View.php @@ -55,7 +55,7 @@ class View * @var string[] Where do the templates live, for each namespace. */ private static $namespaces = [ - '' => WT_ROOT . 'resources/views/', + '' => Webtrees::ROOT_DIR . 'resources/views/', ]; /** diff --git a/app/Webtrees.php b/app/Webtrees.php index 6f661e0291..9912a47922 100644 --- a/app/Webtrees.php +++ b/app/Webtrees.php @@ -17,19 +17,68 @@ declare(strict_types=1); namespace Fisharebest\Webtrees; -use function date_default_timezone_set; +use Closure; +use DebugBar\StandardDebugBar; +use ErrorException; +use Fisharebest\Webtrees\Http\Middleware\BootModules; +use Fisharebest\Webtrees\Http\Middleware\CheckCsrf; +use Fisharebest\Webtrees\Http\Middleware\CheckForMaintenanceMode; +use Fisharebest\Webtrees\Http\Middleware\DoHousekeeping; +use Fisharebest\Webtrees\Http\Middleware\EmitResponse; +use Fisharebest\Webtrees\Http\Middleware\HandleExceptions; +use Fisharebest\Webtrees\Http\Middleware\ModuleMiddleware; +use Fisharebest\Webtrees\Http\Middleware\NoRouteFound; +use Fisharebest\Webtrees\Http\Middleware\PhpEnvironment; +use Fisharebest\Webtrees\Http\Middleware\RequestRouter; +use Fisharebest\Webtrees\Http\Middleware\UpdateDatabaseSchema; +use Fisharebest\Webtrees\Http\Middleware\UseCache; +use Fisharebest\Webtrees\Http\Middleware\UseDatabase; +use Fisharebest\Webtrees\Http\Middleware\UseDebugbar; +use Fisharebest\Webtrees\Http\Middleware\UseFilesystem; +use Fisharebest\Webtrees\Http\Middleware\UseLocale; +use Fisharebest\Webtrees\Http\Middleware\UseSession; +use Fisharebest\Webtrees\Http\Middleware\UseTheme; +use Fisharebest\Webtrees\Http\Middleware\UseTransaction; +use Fisharebest\Webtrees\Http\Middleware\UseTree; +use Fisharebest\Webtrees\Http\Request; +use Nyholm\Psr7\Factory\Psr17Factory; +use Nyholm\Psr7Server\ServerRequestCreator; +use Psr\Http\Message\ResponseFactoryInterface; +use Psr\Http\Message\ServerRequestFactoryInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\StreamFactoryInterface; +use Psr\Http\Message\UploadedFileFactoryInterface; +use Psr\Http\Message\UriFactoryInterface; +use Psr\Http\Server\MiddlewareInterface; +use Throwable; +use function app; +use function class_exists; +use function dirname; use function error_reporting; -use Fisharebest\Webtrees\Exceptions\Handler; +use function ob_end_clean; +use function ob_get_level; use function set_error_handler; use function set_exception_handler; +use function str_replace; +use const PHP_EOL; /** * Definitions for the webtrees application. */ class Webtrees { + // The root folder of this installation + public const ROOT_DIR = __DIR__ . '/../'; + // Location of the file containing the database connection details. - public const CONFIG_FILE = __DIR__ . '/../data/config.ini.php'; + public const CONFIG_FILE = self::ROOT_DIR . '/data/config.ini.php'; + + // Location of the file that triggers maintenance mode. + public const OFFLINE_FILE = self::ROOT_DIR . '/data/offline.txt'; + + // Location of our modules. + public const MODULES_PATH = 'modules_v4'; + public const MODULES_DIR = self::ROOT_DIR . self::MODULES_PATH; // Enable debugging on development builds. public const DEBUG = self::STABILITY !== ''; @@ -46,31 +95,129 @@ class Webtrees // e.g. "dev", "alpha", "beta.3", etc. public const STABILITY = 'alpha.5'; - // Project website. - public const URL = 'https://www.webtrees.net/'; - // Version number public const VERSION = '2.0.0' . (self::STABILITY === '' ? '' : '-') . self::STABILITY; - // Location of our modules. - public const MODULES_PATH = 'modules_v4/'; + // Project website. + public const URL = 'https://www.webtrees.net/'; /** * Initialise the application. * * @return void */ - public static function init(): void + public function bootstrap(): void { - mb_internal_encoding('UTF-8'); - // Show all errors and warnings in development, fewer in production. error_reporting(self::ERROR_REPORTING); - // PHP requires a time zone to be set. We'll set a better one later on. - date_default_timezone_set('UTC'); + set_error_handler($this->phpErrorHandler()); + set_exception_handler($this->phpExceptionHandler()); + } + + /** + * An error handler that can be passed to set_error_handler(). + * + * @return Closure + */ + private function phpErrorHandler(): Closure + { + return static function (int $errno, string $errstr, string $errfile, int $errline): bool { + // Ignore errors that are silenced with '@' + if (error_reporting() & $errno) { + throw new ErrorException($errstr, 0, $errno, $errfile, $errline); + } + + return true; + }; + } + + /** + * An exception handler that can be passed to set_exception_handler(). + * Display any exception that are not caught by the middleware exception handler. + * + * @return Closure + */ + private function phpExceptionHandler(): Closure + { + return static function (Throwable $ex): void { + $base_path = dirname(__DIR__); + $trace = $ex->getMessage() . PHP_EOL . $ex->getTraceAsString(); + $trace = str_replace($base_path, '…', $trace); - set_error_handler(Handler::phpErrorHandler()); - set_exception_handler(Handler::phpExceptionHandler()); + while (ob_get_level() > 0) { + ob_end_clean(); + } + + echo '<html lang="en"><head><title>Error</title><meta charset="UTF-8"></head><body><pre>' . $trace . '</pre></body></html>'; + }; + } + + /** + * We can use any PSR-7 / PSR-17 compatible message factory. + * + * @return void + */ + public function selectMessageFactory(): void + { + app()->bind(ResponseFactoryInterface::class, Psr17Factory::class); + app()->bind(ServerRequestFactoryInterface::class, Psr17Factory::class); + app()->bind(StreamFactoryInterface::class, Psr17Factory::class); + app()->bind(UploadedFileFactoryInterface::class, Psr17Factory::class); + app()->bind(UriFactoryInterface::class, Psr17Factory::class); + } + + /** + * We can use any PSR-7 compatible requests. + * + * @return ServerRequestInterface + */ + public function createServerRequest(): ServerRequestInterface + { + $server_request_creator = new ServerRequestCreator( + app(ServerRequestFactoryInterface::class), + app(UriFactoryInterface::class), + app(UploadedFileFactoryInterface::class), + app(StreamFactoryInterface::class) + ); + + // Until all the code is rewritten to use PSR-7 requests, we still need our hybrid request. + if (class_exists(Request::class)) { + return Request::createFromGlobals(); + } + + return $server_request_creator->fromGlobals(); + + } + + /** + * The webtrees application is built from middleware. + * + * @return MiddlewareInterface[] + */ + public function middleware(): array + { + return [ + PhpEnvironment::class, + EmitResponse::class, + HandleExceptions::class, + CheckForMaintenanceMode::class, + UseDatabase::class, + UseDebugbar::class, + UpdateDatabaseSchema::class, + UseCache::class, + UseFilesystem::class, + UseSession::class, + UseTree::class, + UseLocale::class, + UseTheme::class, + DoHousekeeping::class, + CheckCsrf::class, + UseTransaction::class, + BootModules::class, + ModuleMiddleware::class, + RequestRouter::class, + NoRouteFound::class, + ]; } } @@ -16,99 +16,29 @@ */ declare(strict_types=1); -use Fisharebest\Webtrees\DebugBar; -use Fisharebest\Webtrees\Http\Middleware\BootModules; -use Fisharebest\Webtrees\Http\Middleware\CheckCsrf; -use Fisharebest\Webtrees\Http\Middleware\CheckForMaintenanceMode; -use Fisharebest\Webtrees\Http\Middleware\NoRouteFound; -use Fisharebest\Webtrees\Http\Middleware\UseDebugbar; -use Fisharebest\Webtrees\Http\Middleware\EmitResponse; -use Fisharebest\Webtrees\Http\Middleware\HandleExceptions; -use Fisharebest\Webtrees\Http\Middleware\DoHousekeeping; -use Fisharebest\Webtrees\Http\Middleware\ModuleMiddleware; -use Fisharebest\Webtrees\Http\Middleware\RequestRouter; -use Fisharebest\Webtrees\Http\Middleware\UpdateDatabaseSchema; -use Fisharebest\Webtrees\Http\Middleware\UseCache; -use Fisharebest\Webtrees\Http\Middleware\UseDatabase; -use Fisharebest\Webtrees\Http\Middleware\UseFilesystem; -use Fisharebest\Webtrees\Http\Middleware\UseLocale; -use Fisharebest\Webtrees\Http\Middleware\UseSession; -use Fisharebest\Webtrees\Http\Middleware\UseTheme; -use Fisharebest\Webtrees\Http\Middleware\UseTransaction; -use Fisharebest\Webtrees\Http\Middleware\UseTree; -use Fisharebest\Webtrees\Http\Request as SymfonyRequest; -use Fisharebest\Webtrees\Webtrees; +namespace Fisharebest\Webtrees; + use Middleland\Dispatcher; -use Nyholm\Psr7\Factory\Psr17Factory; -use Nyholm\Psr7Server\ServerRequestCreator; -use Psr\Http\Message\ResponseFactoryInterface; -use Psr\Http\Message\ServerRequestFactoryInterface; -use Psr\Http\Message\StreamFactoryInterface; -use Psr\Http\Message\UploadedFileFactoryInterface; -use Psr\Http\Message\UriFactoryInterface; -use DebugBar\StandardDebugBar; require __DIR__ . '/vendor/autoload.php'; -const WT_ROOT = __DIR__ . DIRECTORY_SEPARATOR; - -Webtrees::init(); - -// Use nyholm/psr7 for our PSR7 messages and PSR17 factory. -app()->bind(ResponseFactoryInterface::class, Psr17Factory::class); -app()->bind(ServerRequestFactoryInterface::class, Psr17Factory::class); -app()->bind(StreamFactoryInterface::class, Psr17Factory::class); -app()->bind(UploadedFileFactoryInterface::class, Psr17Factory::class); -app()->bind(UriFactoryInterface::class, Psr17Factory::class); +// Create the application. +$application = new Webtrees(); -// Use nyholm/psr7-server to create a request from the PHP environment. -$server_request_creator = new ServerRequestCreator( - app(ServerRequestFactoryInterface::class), - app(UriFactoryInterface::class), - app(UploadedFileFactoryInterface::class), - app(StreamFactoryInterface::class) -); +$application->bootstrap(); -// Create a PSR-7 request -$request = $server_request_creator->fromGlobals(); +// Select a PSR message factory. +$application->selectMessageFactory(); -// Initialise the DebugBar for development. -// Use `composer install --dev` on a development build to enable. -// Note that you may need to increase the size of the fcgi buffers on nginx. -// e.g. add these lines to your fastcgi_params file: -// fastcgi_buffers 16 16m; -// fastcgi_buffer_size 32m; -DebugBar::init(class_exists(StandardDebugBar::class)); - -// Until all the code is rewritten to use PSR-7 requests, we still need our hybrid request. -$request = SymfonyRequest::createFromGlobals(); +// Convert the GET, POST, COOKIE variables into a request. +$request = $application->createServerRequest(); // Calculate the base URL, so we can generate absolute URLs. // Remove any PHP script name and parameters. define('WT_BASE_URL', preg_replace('/[^\/]+\.php(\?.*)?$/', '', $request->getUri())); -$middleware = [ - EmitResponse::class, - HandleExceptions::class, - CheckForMaintenanceMode::class, - UseDatabase::class, - UseDebugbar::class, - UpdateDatabaseSchema::class, - UseCache::class, - UseFilesystem::class, - UseSession::class, - UseTree::class, - UseLocale::class, - UseTheme::class, - DoHousekeeping::class, - CheckCsrf::class, - UseTransaction::class, - BootModules::class, - ModuleMiddleware::class, - RequestRouter::class, - NoRouteFound::class, -]; - -$dispatcher = new Dispatcher($middleware, app()); - +// The application is defined by a stack of middleware and a PSR-11 container. +$middleware = $application->middleware(); +$container = app(); +$dispatcher = new Dispatcher($middleware, $container); $dispatcher->dispatch($request); diff --git a/resources/views/setup/step-4-database-sqlite.phtml b/resources/views/setup/step-4-database-sqlite.phtml index dd493c78ec..92f9154da3 100644 --- a/resources/views/setup/step-4-database-sqlite.phtml +++ b/resources/views/setup/step-4-database-sqlite.phtml @@ -1,4 +1,5 @@ -<?php use Fisharebest\Webtrees\I18N; ?> +<?php use Fisharebest\Webtrees\I18N; +use Fisharebest\Webtrees\Webtrees; ?> <form method="POST" autocomplete="off"> <input name="route" type="hidden" value="setup"> @@ -33,7 +34,7 @@ <div class="col-sm-9"> <div class="input-group" dir="ltr"> <div class="input-group-prepend"> - <span class="input-group-text"><?=e( WT_ROOT) ?>data/</span> + <span class="input-group-text"><?=e( realpath(Webtrees::ROOT_DIR)) ?>data/</span> </div> <input class="form-control" id="dbname" name="dbname" pattern="[a-zA-Z0-9_]+" type="text" value="<?= e($dbname) ?>"> diff --git a/tests/TestCase.php b/tests/TestCase.php index b110d08882..190acb685a 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -88,14 +88,11 @@ class TestCase extends \PHPUnit\Framework\TestCase implements StatusCodeInterfac app()->bind(ModuleThemeInterface::class, WebtreesTheme::class); app()->bind(LocaleInterface::class, LocaleEnUs::class); - defined('WT_ROOT') || define('WT_ROOT', dirname(__DIR__) . '/'); defined('WT_BASE_URL') || define('WT_BASE_URL', 'http://localhost/'); - defined('WT_DATA_DIR') || define('WT_DATA_DIR', WT_ROOT . 'data/'); + defined('WT_DATA_DIR') || define('WT_DATA_DIR', Webtrees::ROOT_DIR . 'data/'); defined('WT_LOCALE') || define('WT_LOCALE', I18N::init('en-US', null, true)); if (static::$uses_database) { - defined('WT_ROOT') || define('WT_ROOT', dirname(__DIR__) . '/'); - static::createTestDatabase(); } } diff --git a/tests/app/Module/AhnentafelReportModuleTest.php b/tests/app/Module/AhnentafelReportModuleTest.php index 7567a795bc..5ba73b6f38 100644 --- a/tests/app/Module/AhnentafelReportModuleTest.php +++ b/tests/app/Module/AhnentafelReportModuleTest.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Report\ReportParserGenerate; use Fisharebest\Webtrees\Report\ReportPdf; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; /** * Test harness for the class AhnentafelReportModule @@ -78,7 +79,7 @@ class AhnentafelReportModuleTest extends \Fisharebest\Webtrees\TestCase $tree = $this->importTree('demo.ged'); app()->instance(Tree::class, $tree); - $xml = WT_ROOT . 'resources/xml/reports/ahnentafel_report.xml'; + $xml = Webtrees::ROOT_DIR . 'resources/xml/reports/ahnentafel_report.xml'; $vars = [ 'pid' => ['id' => 'X1030'], 'maxgen' => ['id' => '3'], diff --git a/tests/app/Module/BirthDeathMarriageReportModuleTest.php b/tests/app/Module/BirthDeathMarriageReportModuleTest.php index 26d59bb2b3..8ef5cfd9a9 100644 --- a/tests/app/Module/BirthDeathMarriageReportModuleTest.php +++ b/tests/app/Module/BirthDeathMarriageReportModuleTest.php @@ -21,6 +21,7 @@ use Fisharebest\Webtrees\Report\ReportHtml; use Fisharebest\Webtrees\Report\ReportParserGenerate; use Fisharebest\Webtrees\Report\ReportPdf; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; /** * Test harness for the class BirthDeathMarriageReportModule @@ -72,7 +73,7 @@ class BirthDeathMarriageReportModuleTest extends \Fisharebest\Webtrees\TestCase { $tree = $this->importTree('demo.ged'); app()->instance(Tree::class, $tree); - $xml = WT_ROOT . 'resources/xml/reports/bdm_report.xml'; + $xml = Webtrees::ROOT_DIR . 'resources/xml/reports/bdm_report.xml'; $vars = [ 'name' => ['id' => ''], 'bdmplace' => ['id' => ''], diff --git a/tests/app/Module/BirthReportModuleTest.php b/tests/app/Module/BirthReportModuleTest.php index 22d8950267..d4b731228d 100644 --- a/tests/app/Module/BirthReportModuleTest.php +++ b/tests/app/Module/BirthReportModuleTest.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Report\ReportParserGenerate; use Fisharebest\Webtrees\Report\ReportPdf; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; /** * Test harness for the class BirthReportModule @@ -78,7 +79,7 @@ class BirthReportModuleTest extends \Fisharebest\Webtrees\TestCase $tree = $this->importTree('demo.ged'); app()->instance(Tree::class, $tree); - $xml = WT_ROOT . 'resources/xml/reports/birth_report.xml'; + $xml = Webtrees::ROOT_DIR . 'resources/xml/reports/birth_report.xml'; $vars = [ 'name' => ['id' => ''], 'birthplace' => ['id' => ''], diff --git a/tests/app/Module/CemeteryReportModuleTest.php b/tests/app/Module/CemeteryReportModuleTest.php index 38195bc092..9ca83fd41c 100644 --- a/tests/app/Module/CemeteryReportModuleTest.php +++ b/tests/app/Module/CemeteryReportModuleTest.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Report\ReportParserGenerate; use Fisharebest\Webtrees\Report\ReportPdf; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; /** * Test harness for the class CemeteryReportModule @@ -78,7 +79,7 @@ class CemeteryReportModuleTest extends \Fisharebest\Webtrees\TestCase $tree = $this->importTree('demo.ged'); app()->instance(Tree::class, $tree); - $xml = WT_ROOT . 'resources/xml/reports/cemetery_report.xml'; + $xml = Webtrees::ROOT_DIR . 'resources/xml/reports/cemetery_report.xml'; $vars = [ 'deathplace' => ['id' => ''], 'adlist' => ['id' => 'none'], diff --git a/tests/app/Module/ChangeReportModuleTest.php b/tests/app/Module/ChangeReportModuleTest.php index ff7ebd3a49..d0ce71a2ad 100644 --- a/tests/app/Module/ChangeReportModuleTest.php +++ b/tests/app/Module/ChangeReportModuleTest.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Report\ReportParserGenerate; use Fisharebest\Webtrees\Report\ReportPdf; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; use Illuminate\Support\Carbon; /** @@ -79,7 +80,7 @@ class ChangeReportModuleTest extends \Fisharebest\Webtrees\TestCase $tree = $this->importTree('demo.ged'); app()->instance(Tree::class, $tree); - $xml = WT_ROOT . 'resources/xml/reports/change_report.xml'; + $xml = Webtrees::ROOT_DIR . 'resources/xml/reports/change_report.xml'; $vars = [ 'changeRangeStart' => ['id' => Carbon::now()->subMonths(1)->format('d M Y')], 'changeRangeEnd' => ['id' => Carbon::now()->format('d M Y')], diff --git a/tests/app/Module/DeathReportModuleTest.php b/tests/app/Module/DeathReportModuleTest.php index cc9ddb9022..bdf01bf6ab 100644 --- a/tests/app/Module/DeathReportModuleTest.php +++ b/tests/app/Module/DeathReportModuleTest.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Report\ReportParserGenerate; use Fisharebest\Webtrees\Report\ReportPdf; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; /** * Test harness for the class FactSourcesReportModule @@ -78,7 +79,7 @@ class DeathReportModuleTest extends \Fisharebest\Webtrees\TestCase $tree = $this->importTree('demo.ged'); app()->instance(Tree::class, $tree); - $xml = WT_ROOT . 'resources/xml/reports/death_report.xml'; + $xml = Webtrees::ROOT_DIR . 'resources/xml/reports/death_report.xml'; $vars = [ 'name' => ['id' => ''], 'deathplace' => ['id' => ''], diff --git a/tests/app/Module/DescendancyReportModuleTest.php b/tests/app/Module/DescendancyReportModuleTest.php index 1b9f1a241d..9662b1560b 100644 --- a/tests/app/Module/DescendancyReportModuleTest.php +++ b/tests/app/Module/DescendancyReportModuleTest.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Report\ReportParserGenerate; use Fisharebest\Webtrees\Report\ReportPdf; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; /** * Test harness for the class DescendancyReportModule @@ -78,7 +79,7 @@ class DescendancyReportModuleTest extends \Fisharebest\Webtrees\TestCase $tree = $this->importTree('demo.ged'); app()->instance(Tree::class, $tree); - $xml = WT_ROOT . 'resources/xml/reports/descendancy_report.xml'; + $xml = Webtrees::ROOT_DIR . 'resources/xml/reports/descendancy_report.xml'; $vars = [ 'pid' => ['id' => 'X1030'], 'maxgen' => ['id' => '3'], diff --git a/tests/app/Module/FactSourcesReportModuleTest.php b/tests/app/Module/FactSourcesReportModuleTest.php index 904162c3fd..32b5bded02 100644 --- a/tests/app/Module/FactSourcesReportModuleTest.php +++ b/tests/app/Module/FactSourcesReportModuleTest.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Report\ReportParserGenerate; use Fisharebest\Webtrees\Report\ReportPdf; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; /** * Test harness for the class FactSourcesReportModule @@ -78,7 +79,7 @@ class FactSourcesReportModuleTest extends \Fisharebest\Webtrees\TestCase $tree = $this->importTree('demo.ged'); app()->instance(Tree::class, $tree); - $xml = WT_ROOT . 'resources/xml/reports/fact_sources.xml'; + $xml = Webtrees::ROOT_DIR . 'resources/xml/reports/fact_sources.xml'; $vars = [ 'id' => ['id' => 's1'], 'stype' => ['id' => 'facts'], diff --git a/tests/app/Module/FamilyGroupReportModuleTest.php b/tests/app/Module/FamilyGroupReportModuleTest.php index d2a5d26119..5b286a22b8 100644 --- a/tests/app/Module/FamilyGroupReportModuleTest.php +++ b/tests/app/Module/FamilyGroupReportModuleTest.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Report\ReportParserGenerate; use Fisharebest\Webtrees\Report\ReportPdf; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; /** * Test harness for the class FamilyGroupReportModule @@ -78,7 +79,7 @@ class FamilyGroupReportModuleTest extends \Fisharebest\Webtrees\TestCase $tree = $this->importTree('demo.ged'); app()->instance(Tree::class, $tree); - $xml = WT_ROOT . 'resources/xml/reports/family_group_report.xml'; + $xml = Webtrees::ROOT_DIR . 'resources/xml/reports/family_group_report.xml'; $vars = [ 'id' => ['id' => 'f1'], 'sources' => ['id' => 'on'], diff --git a/tests/app/Module/IndividualFamiliesReportModuleTest.php b/tests/app/Module/IndividualFamiliesReportModuleTest.php index 50a61e3778..3ea62af057 100644 --- a/tests/app/Module/IndividualFamiliesReportModuleTest.php +++ b/tests/app/Module/IndividualFamiliesReportModuleTest.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Report\ReportParserGenerate; use Fisharebest\Webtrees\Report\ReportPdf; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; /** * Test harness for the class IndividualFamiliesReportModule @@ -78,7 +79,7 @@ class IndividualFamiliesReportModuleTest extends \Fisharebest\Webtrees\TestCase $tree = $this->importTree('demo.ged'); app()->instance(Tree::class, $tree); - $xml = WT_ROOT . 'resources/xml/reports/individual_ext_report.xml'; + $xml = Webtrees::ROOT_DIR . 'resources/xml/reports/individual_ext_report.xml'; $vars = [ 'pid' => ['id' => 'X1030'], 'relatives' => ['id' => 'child-families'], diff --git a/tests/app/Module/IndividualReportModuleTest.php b/tests/app/Module/IndividualReportModuleTest.php index 713850d888..eba24b5eb7 100644 --- a/tests/app/Module/IndividualReportModuleTest.php +++ b/tests/app/Module/IndividualReportModuleTest.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Report\ReportParserGenerate; use Fisharebest\Webtrees\Report\ReportPdf; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; /** * Test harness for the class IndividualReportModule @@ -79,7 +80,7 @@ class IndividualReportModuleTest extends \Fisharebest\Webtrees\TestCase $tree = $this->importTree('demo.ged'); app()->instance(Tree::class, $tree); - $xml = WT_ROOT . 'resources/xml/reports/individual_report.xml'; + $xml = Webtrees::ROOT_DIR . 'resources/xml/reports/individual_report.xml'; $vars = [ 'id' => ['id' => 'X1030'], 'sources' => ['id' => 'on'], diff --git a/tests/app/Module/MarriageReportModuleTest.php b/tests/app/Module/MarriageReportModuleTest.php index 4aaf1688c7..ed3f3e658e 100644 --- a/tests/app/Module/MarriageReportModuleTest.php +++ b/tests/app/Module/MarriageReportModuleTest.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Report\ReportParserGenerate; use Fisharebest\Webtrees\Report\ReportPdf; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; /** * Test harness for the class MarriageReportModule @@ -78,7 +79,7 @@ class MarriageReportModuleTest extends \Fisharebest\Webtrees\TestCase $tree = $this->importTree('demo.ged'); app()->instance(Tree::class, $tree); - $xml = WT_ROOT . 'resources/xml/reports/marriage_report.xml'; + $xml = Webtrees::ROOT_DIR . 'resources/xml/reports/marriage_report.xml'; $vars = [ 'name' => ['id' => ''], 'marrplace' => ['id' => ''], diff --git a/tests/app/Module/MissingFactsReportModuleTest.php b/tests/app/Module/MissingFactsReportModuleTest.php index a7b248985c..7fa20574ff 100644 --- a/tests/app/Module/MissingFactsReportModuleTest.php +++ b/tests/app/Module/MissingFactsReportModuleTest.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Report\ReportParserGenerate; use Fisharebest\Webtrees\Report\ReportPdf; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; /** * Test harness for the class MissingFactsReportModule @@ -78,7 +79,7 @@ class MissingFactsReportModuleTest extends \Fisharebest\Webtrees\TestCase $tree = $this->importTree('demo.ged'); app()->instance(Tree::class, $tree); - $xml = WT_ROOT . 'resources/xml/reports/missing_facts_report.xml'; + $xml = Webtrees::ROOT_DIR . 'resources/xml/reports/missing_facts_report.xml'; $vars = [ 'pid' => ['id' => 'X1030'], 'relatives' => ['id' => 'direct-ancestors'], diff --git a/tests/app/Module/OccupationReportModuleTest.php b/tests/app/Module/OccupationReportModuleTest.php index c86c10ff80..bfd710a017 100644 --- a/tests/app/Module/OccupationReportModuleTest.php +++ b/tests/app/Module/OccupationReportModuleTest.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Report\ReportParserGenerate; use Fisharebest\Webtrees\Report\ReportPdf; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; /** * Test harness for the class OccupationReportModule @@ -78,7 +79,7 @@ class OccupationReportModuleTest extends \Fisharebest\Webtrees\TestCase $tree = $this->importTree('demo.ged'); app()->instance(Tree::class, $tree); - $xml = WT_ROOT . 'resources/xml/reports/occupation_report.xml'; + $xml = Webtrees::ROOT_DIR . 'resources/xml/reports/occupation_report.xml'; $vars = [ 'occupation' => ['id' => 'king'], 'pageSize' => ['id' => 'A4'], diff --git a/tests/app/Module/PedigreeReportModuleTest.php b/tests/app/Module/PedigreeReportModuleTest.php index 5ea92b82b5..d074cb732f 100644 --- a/tests/app/Module/PedigreeReportModuleTest.php +++ b/tests/app/Module/PedigreeReportModuleTest.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Report\ReportParserGenerate; use Fisharebest\Webtrees\Report\ReportPdf; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; /** * Test harness for the class PedigreeReportModule @@ -78,7 +79,7 @@ class PedigreeReportModuleTest extends \Fisharebest\Webtrees\TestCase $tree = $this->importTree('demo.ged'); app()->instance(Tree::class, $tree); - $xml = WT_ROOT . 'resources/xml/reports/pedigree_report.xml'; + $xml = Webtrees::ROOT_DIR . 'resources/xml/reports/pedigree_report.xml'; $vars = [ 'pid' => ['id' => 'X1030'], 'spouses' => ['id' => 'on'], diff --git a/tests/app/Module/RelatedIndividualsReportModuleTest.php b/tests/app/Module/RelatedIndividualsReportModuleTest.php index 1bfff18829..8b467f0b57 100644 --- a/tests/app/Module/RelatedIndividualsReportModuleTest.php +++ b/tests/app/Module/RelatedIndividualsReportModuleTest.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Report\ReportParserGenerate; use Fisharebest\Webtrees\Report\ReportPdf; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Tree; +use Fisharebest\Webtrees\Webtrees; /** * Test harness for the class RelatedIndividualsReportModule @@ -78,7 +79,7 @@ class RelatedIndividualsReportModuleTest extends \Fisharebest\Webtrees\TestCase $tree = $this->importTree('demo.ged'); app()->instance(Tree::class, $tree); - $xml = WT_ROOT . 'resources/xml/reports/relative_ext_report.xml'; + $xml = Webtrees::ROOT_DIR . 'resources/xml/reports/relative_ext_report.xml'; $vars = [ 'pid' => ['id' => 'X1030'], 'relatives' => ['id' => 'child-family'], diff --git a/tests/app/WebtreesTest.php b/tests/app/WebtreesTest.php index 68d51afcd7..a075ac742a 100644 --- a/tests/app/WebtreesTest.php +++ b/tests/app/WebtreesTest.php @@ -17,10 +17,10 @@ declare(strict_types=1); namespace Fisharebest\Webtrees; +use ErrorException; use function date_default_timezone_get; use function date_default_timezone_set; use function error_reporting; -use ErrorException; use function set_error_handler; /** @@ -29,19 +29,16 @@ use function set_error_handler; class WebtreesTest extends TestCase { /** - * @covers \Fisharebest\Webtrees\Webtrees::init + * @covers \Fisharebest\Webtrees\Webtrees::bootstrap * @return void */ public function testInit(): void { - date_default_timezone_set('Europe/London'); error_reporting(0); set_error_handler(null); - Webtrees::init(); - - // webtrees always runs in UTC (and converts to local time on demand). - $this->assertSame('UTC', date_default_timezone_get()); + $webtrees = new Webtrees(); + $webtrees->bootstrap(); // webtrees sets the error reporting level. $this->assertNotSame(0, error_reporting()); @@ -49,13 +46,13 @@ class WebtreesTest extends TestCase try { // Trigger an error - fopen(__DIR__ . '/no-such-file', 'r'); + fopen(__DIR__ . '/no-such-file', 'rb'); } catch (ErrorException $ex) { $this->assertSame(__FILE__, $ex->getFile()); } // Disable error reporting (we could use "@"), and don't raise an exception. error_reporting(0); - fopen(__DIR__ . '/no-such-file', 'r'); + fopen(__DIR__ . '/no-such-file', 'rb'); } } |
