From cba20eb871932d4301cf65b62972e9fad19015ac Mon Sep 17 00:00:00 2001 From: Greg Roach Date: Mon, 6 Jan 2025 11:17:28 +0000 Subject: [PATCH] Add PhpService so we can mock/test calles to ini_get(), etc. --- app/Factories/ImageFactory.php | 10 +- app/Factories/SlugFactory.php | 11 +- app/Http/Middleware/CompressResponse.php | 12 +- app/Http/Middleware/EmitResponse.php | 41 +------ app/Http/Middleware/HandleExceptions.php | 21 ++-- app/Http/RequestHandlers/ExportGedcomPage.php | 15 ++- app/Http/RequestHandlers/SetupWizard.php | 110 +++--------------- .../RequestHandlers/SitePreferencesPage.php | 18 +-- app/Http/RequestHandlers/UploadMediaPage.php | 26 ++--- app/Module/ClippingsCartModule.php | 15 +-- app/Services/MediaFileService.php | 40 +------ app/Services/ServerCheckService.php | 66 +++-------- app/Services/TimeoutService.php | 19 +-- app/Webtrees.php | 5 +- phpstan-baseline.neon | 60 ---------- .../views/setup/step-4-database-mysql.phtml | 3 +- tests/TestCase.php | 5 +- .../Http/Middleware/HandleExceptionsTest.php | 3 +- .../ControlPanelControllerTest.php | 24 ++-- .../RequestHandlers/ManageMediaPageTest.php | 5 +- .../RequestHandlers/UpgradeWizardPageTest.php | 3 +- .../RequestHandlers/UpgradeWizardStepTest.php | 11 +- .../RequestHandlers/UploadMediaActionTest.php | 5 +- .../RequestHandlers/UploadMediaPageTest.php | 6 +- tests/app/Services/TimeoutServiceTest.php | 65 +++-------- 25 files changed, 144 insertions(+), 455 deletions(-) diff --git a/app/Factories/ImageFactory.php b/app/Factories/ImageFactory.php index 734a5ba089c..58b2a2c70fb 100644 --- a/app/Factories/ImageFactory.php +++ b/app/Factories/ImageFactory.php @@ -26,6 +26,7 @@ use Fisharebest\Webtrees\MediaFile; use Fisharebest\Webtrees\Mime; use Fisharebest\Webtrees\Registry; +use Fisharebest\Webtrees\Services\PhpService; use Fisharebest\Webtrees\Webtrees; use Imagick; use Intervention\Gif\Exceptions\NotReadableException; @@ -44,7 +45,6 @@ use function addcslashes; use function basename; -use function extension_loaded; use function get_class; use function implode; use function pathinfo; @@ -76,6 +76,10 @@ class ImageFactory implements ImageFactoryInterface 'image/webp' => 'webp', ]; + public function __construct(private PhpService $php_service) + { + } + /** * Send the original file - either inline or as a download. */ @@ -305,11 +309,11 @@ protected function imageResponse(string $data, string $mime_type, string $filena */ protected function imageManager(): ImageManager { - if (extension_loaded(extension: 'imagick')) { + if ($this->php_service->extensionLoaded(extension: 'imagick')) { return new ImageManager(driver: new ImagickDriver()); } - if (extension_loaded(extension: 'gd')) { + if ($this->php_service->extensionLoaded(extension: 'gd')) { return new ImageManager(driver: new GdDriver()); } diff --git a/app/Factories/SlugFactory.php b/app/Factories/SlugFactory.php index bd3be820557..24bf39caa82 100644 --- a/app/Factories/SlugFactory.php +++ b/app/Factories/SlugFactory.php @@ -21,9 +21,9 @@ use Fisharebest\Webtrees\Contracts\SlugFactoryInterface; use Fisharebest\Webtrees\GedcomRecord; +use Fisharebest\Webtrees\Services\PhpService; use Transliterator; -use function extension_loaded; use function in_array; use function preg_replace; use function strip_tags; @@ -36,9 +36,9 @@ class SlugFactory implements SlugFactoryInterface { private Transliterator|null $transliterator = null; - public function __construct() + public function __construct(private PhpService $php_service) { - if (extension_loaded('intl')) { + if ($this->php_service->extensionLoaded(extension: 'intl')) { $ids = Transliterator::listIDs(); if ($ids !== false && in_array('Any-Latin', $ids, true) && in_array('Latin-ASCII', $ids, true)) { @@ -47,11 +47,6 @@ public function __construct() } } - /** - * @param GedcomRecord $record - * - * @return string - */ public function make(GedcomRecord $record): string { $slug = strip_tags($record->fullName()); diff --git a/app/Http/Middleware/CompressResponse.php b/app/Http/Middleware/CompressResponse.php index d1ad7786e01..733361dae1a 100644 --- a/app/Http/Middleware/CompressResponse.php +++ b/app/Http/Middleware/CompressResponse.php @@ -19,6 +19,7 @@ namespace Fisharebest\Webtrees\Http\Middleware; +use Fisharebest\Webtrees\Services\PhpService; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -26,7 +27,6 @@ use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; -use function extension_loaded; use function gzdeflate; use function gzencode; use function in_array; @@ -50,14 +50,8 @@ class CompressResponse implements MiddlewareInterface 'image/svg+xml', ]; - protected StreamFactoryInterface $stream_factory; - - /** - * @param StreamFactoryInterface $stream_factory - */ - public function __construct(StreamFactoryInterface $stream_factory) + public function __construct(private PhpService $php_service, private StreamFactoryInterface $stream_factory) { - $this->stream_factory = $stream_factory; } /** @@ -103,7 +97,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface protected function compressionMethod(RequestInterface $request): string|null { $accept_encoding = strtolower($request->getHeaderLine('accept-encoding')); - $zlib_available = extension_loaded('zlib'); + $zlib_available = $this->php_service->extensionLoaded(extension: 'zlib'); if ($zlib_available) { if (str_contains($accept_encoding, 'gzip')) { diff --git a/app/Http/Middleware/EmitResponse.php b/app/Http/Middleware/EmitResponse.php index ae690f95827..912273b3080 100644 --- a/app/Http/Middleware/EmitResponse.php +++ b/app/Http/Middleware/EmitResponse.php @@ -19,6 +19,7 @@ namespace Fisharebest\Webtrees\Http\Middleware; +use Fisharebest\Webtrees\Services\PhpService; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; @@ -27,7 +28,6 @@ use function connection_status; use function fastcgi_finish_request; -use function function_exists; use function header; use function header_remove; use function headers_sent; @@ -46,12 +46,10 @@ class EmitResponse implements MiddlewareInterface // Stream the output in chunks. private const int CHUNK_SIZE = 65536; - /** - * @param ServerRequestInterface $request - * @param RequestHandlerInterface $handler - * - * @return ResponseInterface - */ + public function __construct(private PhpService $php_service) + { + } + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { $response = $handler->handle($request); @@ -73,11 +71,6 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface return $response; } - /** - * Remove the default PHP header. - * - * @return void - */ private function removeDefaultPhpHeaders(): void { header_remove('X-Powered-By'); @@ -86,10 +79,6 @@ private function removeDefaultPhpHeaders(): void header_remove('Pragma'); } - /** - * @return void - * @throws RuntimeException - */ private function assertHeadersNotEmitted(): void { if (headers_sent($file, $line)) { @@ -99,10 +88,6 @@ private function assertHeadersNotEmitted(): void } } - /** - * @return void - * @throws RuntimeException - */ private function assertBodyNotEmitted(): void { if (ob_get_level() > 0 && ob_get_length() > 0) { @@ -113,9 +98,6 @@ private function assertBodyNotEmitted(): void } } - /** - * @param ResponseInterface $response - */ private function emitStatusLine(ResponseInterface $response): void { http_response_code($response->getStatusCode()); @@ -128,9 +110,6 @@ private function emitStatusLine(ResponseInterface $response): void )); } - /** - * @param ResponseInterface $response - */ private function emitHeaders(ResponseInterface $response): void { foreach ($response->getHeaders() as $name => $values) { @@ -144,11 +123,6 @@ private function emitHeaders(ResponseInterface $response): void } } - /** - * @param ResponseInterface $response - * - * @return void - */ private function emitBody(ResponseInterface $response): void { $body = $response->getBody(); @@ -162,12 +136,9 @@ private function emitBody(ResponseInterface $response): void } } - /** - * @return void - */ private function closeConnection(): void { - if (function_exists('fastcgi_finish_request')) { + if ($this->php_service->functionExists(function: 'fastcgi_finish_request')) { fastcgi_finish_request(); } } diff --git a/app/Http/Middleware/HandleExceptions.php b/app/Http/Middleware/HandleExceptions.php index fbc1d57e178..0141b45f56b 100644 --- a/app/Http/Middleware/HandleExceptions.php +++ b/app/Http/Middleware/HandleExceptions.php @@ -25,6 +25,7 @@ use Fisharebest\Webtrees\Http\ViewResponseTrait; use Fisharebest\Webtrees\Log; use Fisharebest\Webtrees\Registry; +use Fisharebest\Webtrees\Services\PhpService; use Fisharebest\Webtrees\Services\TreeService; use Fisharebest\Webtrees\Site; use Fisharebest\Webtrees\Validator; @@ -37,7 +38,6 @@ use function dirname; use function error_get_last; -use function ini_get; use function nl2br; use function ob_end_clean; use function ob_get_level; @@ -56,14 +56,8 @@ class HandleExceptions implements MiddlewareInterface, StatusCodeInterface { use ViewResponseTrait; - private TreeService $tree_service; - - /** - * @param TreeService $tree_service - */ - public function __construct(TreeService $tree_service) + public function __construct(private PhpService $php_service, private TreeService $tree_service) { - $this->tree_service = $tree_service; } /** @@ -76,11 +70,16 @@ public function __construct(TreeService $tree_service) public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { // Fatal errors. We may be out of memory, so do not create any variables. - register_shutdown_function(static function (): void { + register_shutdown_function(callback: function (): void { if (error_get_last() !== null && error_get_last()['type'] & E_ERROR) { // If PHP does not display the error, then we must display it. - if (ini_get('display_errors') !== '1') { - echo error_get_last()['message'], '

', error_get_last()['file'], ': ', error_get_last()['line']; + if (!$this->php_service->displayErrors()) { + echo + error_get_last()['message'], + '

', + error_get_last()['file'], + ': ', + error_get_last()['line']; } } }); diff --git a/app/Http/RequestHandlers/ExportGedcomPage.php b/app/Http/RequestHandlers/ExportGedcomPage.php index 9b4074ef8a6..8f69ff109f1 100644 --- a/app/Http/RequestHandlers/ExportGedcomPage.php +++ b/app/Http/RequestHandlers/ExportGedcomPage.php @@ -21,6 +21,7 @@ use Fisharebest\Webtrees\Http\ViewResponseTrait; use Fisharebest\Webtrees\I18N; +use Fisharebest\Webtrees\Services\PhpService; use Fisharebest\Webtrees\Validator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -28,7 +29,6 @@ use function date; use function e; -use function extension_loaded; use function pathinfo; use function strtolower; use function substr; @@ -36,17 +36,16 @@ use const PATHINFO_EXTENSION; /** - * Show download forms/optiosn. + * Show download forms/options. */ class ExportGedcomPage implements RequestHandlerInterface { use ViewResponseTrait; - /** - * @param ServerRequestInterface $request - * - * @return ResponseInterface - */ + public function __construct(private PhpService $php_service) + { + } + public function handle(ServerRequestInterface $request): ResponseInterface { $tree = Validator::attributes($request)->tree(); @@ -73,7 +72,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface 'filename' => $filename, 'title' => $title, 'tree' => $tree, - 'zip_available' => extension_loaded('zip'), + 'zip_available' => $this->php_service->extensionLoaded('zip'), ]); } } diff --git a/app/Http/RequestHandlers/SetupWizard.php b/app/Http/RequestHandlers/SetupWizard.php index 7d532911933..c307a2a91a3 100644 --- a/app/Http/RequestHandlers/SetupWizard.php +++ b/app/Http/RequestHandlers/SetupWizard.php @@ -33,12 +33,12 @@ use Fisharebest\Webtrees\Registry; use Fisharebest\Webtrees\Services\MigrationService; use Fisharebest\Webtrees\Services\ModuleService; +use Fisharebest\Webtrees\Services\PhpService; use Fisharebest\Webtrees\Services\ServerCheckService; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Session; use Fisharebest\Webtrees\Validator; use Fisharebest\Webtrees\Webtrees; -use Illuminate\Support\Collection; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; @@ -47,11 +47,10 @@ use function e; use function file_get_contents; use function file_put_contents; -use function ini_get; +use function intdiv; use function random_bytes; use function realpath; use function redirect; -use function substr; use function touch; use function unlink; use function view; @@ -92,38 +91,17 @@ class SetupWizard implements RequestHandlerInterface DB::SQL_SERVER => '', // Do not use default, as it is valid to have no port number. ]; - private MigrationService $migration_service; - - private ModuleService $module_service; - - private ServerCheckService $server_check_service; - - private UserService $user_service; - - /** - * @param MigrationService $migration_service - * @param ModuleService $module_service - * @param ServerCheckService $server_check_service - * @param UserService $user_service - */ public function __construct( - MigrationService $migration_service, - ModuleService $module_service, - ServerCheckService $server_check_service, - UserService $user_service + private MigrationService $migration_service, + private ModuleService $module_service, + private PhpService $php_service, + private ServerCheckService $server_check_service, + private UserService $user_service ) { - $this->user_service = $user_service; - $this->migration_service = $migration_service; - $this->module_service = $module_service; - $this->server_check_service = $server_check_service; } /** * Installation wizard - check user input and proceed to the next step. - * - * @param ServerRequestInterface $request - * - * @return ResponseInterface */ public function handle(ServerRequestInterface $request): ResponseInterface { @@ -156,9 +134,9 @@ public function handle(ServerRequestInterface $request): ResponseInterface I18N::init($data['lang'], true); - $data['cpu_limit'] = $this->maxExecutionTime(); + $data['cpu_limit'] = $this->php_service->maxExecutionTime(); $data['locales'] = $locales; - $data['memory_limit'] = $this->memoryLimit(); + $data['memory_limit'] = intdiv($this->php_service->maxExecutionTime(), 1048576); // Only show database errors after the user has chosen a driver. if ($step >= 4) { @@ -195,8 +173,6 @@ public function handle(ServerRequestInterface $request): ResponseInterface } /** - * @param ServerRequestInterface $request - * * @return array */ private function userData(ServerRequestInterface $request): array @@ -210,48 +186,8 @@ private function userData(ServerRequestInterface $request): array return $data; } - /** - * The server's memory limit - * - * @return int - */ - private function maxExecutionTime(): int - { - return (int) ini_get('max_execution_time'); - } - - /** - * The server's memory limit (in MB). - * - * @return int - */ - private function memoryLimit(): int - { - $memory_limit = ini_get('memory_limit'); - - $number = (int) $memory_limit; - - switch (substr($memory_limit, -1)) { - case 'g': - case 'G': - return $number * 1024; - case 'm': - case 'M': - return $number; - case 'k': - case 'K': - return (int) ($number / 1024); - default: - return (int) ($number / 1048576); - } - } - /** * Check we can write to the data folder. - * - * @param string $data_dir - * - * @return bool */ private function checkFolderIsWritable(string $data_dir): bool { @@ -270,8 +206,6 @@ private function checkFolderIsWritable(string $data_dir): bool /** * @param array $data - * - * @return ResponseInterface */ private function step1Language(array $data): ResponseInterface { @@ -280,8 +214,6 @@ private function step1Language(array $data): ResponseInterface /** * @param array $data - * - * @return ResponseInterface */ private function step2CheckServer(array $data): ResponseInterface { @@ -290,8 +222,6 @@ private function step2CheckServer(array $data): ResponseInterface /** * @param array $data - * - * @return ResponseInterface */ private function step3DatabaseType(array $data): ResponseInterface { @@ -304,8 +234,6 @@ private function step3DatabaseType(array $data): ResponseInterface /** * @param array $data - * - * @return ResponseInterface */ private function step4DatabaseConnection(array $data): ResponseInterface { @@ -313,13 +241,13 @@ private function step4DatabaseConnection(array $data): ResponseInterface return $this->step3DatabaseType($data); } + $data['mysql_local'] = 'localhost:' . $this->php_service->iniGet(option: 'pdo_mysql.default_socket'); + return $this->viewResponse('setup/step-4-database-' . $data['dbtype'], $data); } /** * @param array $data - * - * @return ResponseInterface */ private function step5Administrator(array $data): ResponseInterface { @@ -332,6 +260,8 @@ private function step5Administrator(array $data): ResponseInterface $data['errors']->push($ex->getMessage()); // Don't jump to step 4, as the error will make it jump to step 3. + $data['mysql_local'] = 'localhost:' . $this->php_service->iniGet(option: 'pdo_mysql.default_socket'); + return $this->viewResponse('setup/step-4-database-' . $data['dbtype'], $data); } @@ -340,8 +270,6 @@ private function step5Administrator(array $data): ResponseInterface /** * @param array $data - * - * @return ResponseInterface */ private function step6Install(array $data): ResponseInterface { @@ -363,14 +291,6 @@ private function step6Install(array $data): ResponseInterface return redirect($data['baseurl']); } - /** - * @param string $wtname - * @param string $wtuser - * @param string $wtpass - * @param string $wtemail - * - * @return string - */ private function checkAdminUser(string $wtname, string $wtuser, string $wtpass, string $wtemail): string { if ($wtname === '' || $wtuser === '' || $wtpass === '' || $wtemail === '') { @@ -386,8 +306,6 @@ private function checkAdminUser(string $wtname, string $wtuser, string $wtpass, /** * @param array $data - * - * @return void */ private function createConfigFile(array $data): void { @@ -432,8 +350,6 @@ private function createConfigFile(array $data): void /** * @param array $data - * - * @return void */ private function connectToDatabase(array $data): void { diff --git a/app/Http/RequestHandlers/SitePreferencesPage.php b/app/Http/RequestHandlers/SitePreferencesPage.php index 3729b52e887..ac33c55d233 100644 --- a/app/Http/RequestHandlers/SitePreferencesPage.php +++ b/app/Http/RequestHandlers/SitePreferencesPage.php @@ -28,8 +28,6 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; -use function ini_get; - /** * Edit the site preferences. */ @@ -37,21 +35,10 @@ class SitePreferencesPage implements RequestHandlerInterface { use ViewResponseTrait; - private ModuleService $module_service; - - /** - * @param ModuleService $module_service - */ - public function __construct(ModuleService $module_service) + public function __construct(private ModuleService $module_service) { - $this->module_service = $module_service; } - /** - * @param ServerRequestInterface $request - * - * @return ResponseInterface - */ public function handle(ServerRequestInterface $request): ResponseInterface { $this->layout = 'layouts/administration'; @@ -60,14 +47,11 @@ public function handle(ServerRequestInterface $request): ResponseInterface ->findByInterface(ModuleThemeInterface::class, true, true) ->map($this->module_service->titleMapper()); - $max_execution_time = (int) ini_get('max_execution_time'); - $title = I18N::translate('Website preferences'); return $this->viewResponse('admin/site-preferences', [ 'all_themes' => $all_themes, 'data_folder' => Registry::filesystem()->dataName(), - 'max_execution_time' => $max_execution_time, 'title' => $title, ]); } diff --git a/app/Http/RequestHandlers/UploadMediaPage.php b/app/Http/RequestHandlers/UploadMediaPage.php index db84fa59a3b..ae0b7a4ae32 100644 --- a/app/Http/RequestHandlers/UploadMediaPage.php +++ b/app/Http/RequestHandlers/UploadMediaPage.php @@ -23,11 +23,12 @@ use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Registry; use Fisharebest\Webtrees\Services\MediaFileService; +use Fisharebest\Webtrees\Services\PhpService; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; -use function ini_get; +use function intdiv; /** * Manage media from the control panel. @@ -39,32 +40,19 @@ class UploadMediaPage implements RequestHandlerInterface // How many files to upload on one form. private const int MAX_UPLOAD_FILES = 10; - private MediaFileService $media_file_service; - - /** - * @param MediaFileService $media_file_service - */ - public function __construct(MediaFileService $media_file_service) + public function __construct(private MediaFileService $media_file_service, private PhpService $php_service) { - $this->media_file_service = $media_file_service; } - /** - * @param ServerRequestInterface $request - * - * @return ResponseInterface - */ public function handle(ServerRequestInterface $request): ResponseInterface { $this->layout = 'layouts/administration'; $data_filesystem = Registry::filesystem()->data(); - - $media_folders = $this->media_file_service->allMediaFolders($data_filesystem); - - $filesize = ini_get('upload_max_filesize') ?: '2M'; - - $title = I18N::translate('Upload media files'); + $media_folders = $this->media_file_service->allMediaFolders($data_filesystem); + $kb = intdiv(num1: $this->php_service->uploadMaxFilesize() + 1023, num2: 1024); + $filesize = I18N::translate('%s KB', I18N::number($kb)); + $title = I18N::translate('Upload media files'); return $this->viewResponse('admin/media-upload', [ 'max_upload_files' => self::MAX_UPLOAD_FILES, diff --git a/app/Module/ClippingsCartModule.php b/app/Module/ClippingsCartModule.php index 13c71b165aa..92197e8dc24 100644 --- a/app/Module/ClippingsCartModule.php +++ b/app/Module/ClippingsCartModule.php @@ -46,6 +46,7 @@ use Fisharebest\Webtrees\Repository; use Fisharebest\Webtrees\Services\GedcomExportService; use Fisharebest\Webtrees\Services\LinkedRecordService; +use Fisharebest\Webtrees\Services\PhpService; use Fisharebest\Webtrees\Session; use Fisharebest\Webtrees\Source; use Fisharebest\Webtrees\Submitter; @@ -62,7 +63,6 @@ use function assert; use function count; use function date; -use function extension_loaded; use function in_array; use function is_array; use function is_string; @@ -104,16 +104,11 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface /** @var int The default access level for this module. It can be changed in the control panel. */ protected int $access_level = Auth::PRIV_USER; - private GedcomExportService $gedcom_export_service; - - private LinkedRecordService $linked_record_service; - public function __construct( - GedcomExportService $gedcom_export_service, - LinkedRecordService $linked_record_service + private GedcomExportService $gedcom_export_service, + private LinkedRecordService $linked_record_service, + private PhpService $php_service, ) { - $this->gedcom_export_service = $gedcom_export_service; - $this->linked_record_service = $linked_record_service; } public function description(): string @@ -207,7 +202,7 @@ public function getDownloadFormAction(ServerRequestInterface $request): Response 'module' => $this->name(), 'title' => $title, 'tree' => $tree, - 'zip_available' => extension_loaded('zip'), + 'zip_available' => $this->php_service->extensionLoaded(extension: 'zip'), ]); } diff --git a/app/Services/MediaFileService.php b/app/Services/MediaFileService.php index a251b829b13..6a99f371efa 100644 --- a/app/Services/MediaFileService.php +++ b/app/Services/MediaFileService.php @@ -42,7 +42,6 @@ use function array_intersect; use function dirname; use function explode; -use function ini_get; use function intdiv; use function is_float; use function min; @@ -78,50 +77,21 @@ class MediaFileService '_DAV', ]; + public function __construct(private PhpService $php_service) + { + } + /** * What is the largest file a user may upload? */ public function maxUploadFilesize(): string { - $sizePostMax = $this->parseIniFileSize((string) ini_get('post_max_size')); - $sizeUploadMax = $this->parseIniFileSize((string) ini_get('upload_max_filesize')); - - $bytes = min($sizePostMax, $sizeUploadMax); + $bytes = min($this->php_service->postMaxSize(), $this->php_service->uploadMaxFilesize()); $kb = intdiv($bytes + 1023, 1024); return I18N::translate('%s KB', I18N::number($kb)); } - /** - * Returns the given size from an ini value in bytes. - * - * @param string $size - * - * @return int - */ - private function parseIniFileSize(string $size): int - { - $number = (int) $size; - - $units = [ - 'g' => 1073741824, - 'G' => 1073741824, - 'm' => 1048576, - 'M' => 1048576, - 'k' => 1024, - 'K' => 1024, - ]; - - $number *= $units[substr($size, -1)] ?? 1; - - if (is_float($number)) { - // Probably a 32bit version of PHP, with an INI setting >= 2GB - return PHP_INT_MAX; - } - - return $number; - } - /** * A list of media files not already linked to a media object. * diff --git a/app/Services/ServerCheckService.php b/app/Services/ServerCheckService.php index db1db36d456..e7b44c929df 100644 --- a/app/Services/ServerCheckService.php +++ b/app/Services/ServerCheckService.php @@ -29,13 +29,10 @@ use function date; use function e; use function explode; -use function extension_loaded; -use function function_exists; use function in_array; use function str_ends_with; use function str_starts_with; use function strtolower; -use function sys_get_temp_dir; use function trim; use function version_compare; @@ -61,6 +58,10 @@ class ServerCheckService // As required by illuminate/database 8.x private const string MINIMUM_SQLITE_VERSION = '3.8.8'; + public function __construct(private PhpService $php_service) + { + } + /** * Things that may cause webtrees to break. * @@ -111,33 +112,18 @@ public function serverWarnings(string $driver = ''): Collection ->filter(); } - /** - * Check if a PHP extension is loaded. - * - * @param string $extension - * - * @return string - */ private function checkPhpExtension(string $extension): string { - if (!extension_loaded($extension)) { + if (!$this->php_service->extensionLoaded(extension: $extension)) { return I18N::translate('The PHP extension ā€œ%sā€ is not installed.', $extension); } return ''; } - /** - * Check if a PHP setting is correct. - * - * @param string $varname - * @param bool $expected - * - * @return string - */ private function checkPhpIni(string $varname, bool $expected): string { - $actual = (bool) ini_get($varname); + $actual = (bool) $this->php_service->iniGet(option: $varname); if ($expected && !$actual) { return I18N::translate('The PHP.INI setting ā€œ%1$sā€ is disabled.', $varname); @@ -150,29 +136,21 @@ private function checkPhpIni(string $varname, bool $expected): string return ''; } - /** - * Check if a PHP function is in the list of disabled functions. - * - * @param string $function - * - * @return bool - */ public function isFunctionDisabled(string $function): bool { $function = strtolower($function); - $disable_functions = explode(',', (string) ini_get('disable_functions')); - $disable_functions = array_map(static fn (string $func): string => strtolower(trim($func)), $disable_functions); + $disable_functions = explode(',', $this->php_service->iniGet('disable_functions')); + $disable_functions = array_map(trim(...), $disable_functions); + $disable_functions = array_map(strtolower(...), $disable_functions); - return in_array($function, $disable_functions, true) || !function_exists($function); + return + in_array($function, $disable_functions, true) || + !$this->php_service->functionExists(function: $function); } /** * Create a warning message for a disabled function. - * - * @param string $function - * - * @return string */ private function checkPhpFunction(string $function): string { @@ -183,9 +161,6 @@ private function checkPhpFunction(string $function): string return ''; } - /** - * Some servers configure their temporary folder in an inaccessible place. - */ private function checkPhpVersion(): string { $today = date('Y-m-d'); @@ -199,11 +174,6 @@ private function checkPhpVersion(): string return ''; } - /** - * Check the - * - * @return string - */ private function checkSqliteVersion(): string { if (class_exists(SQLite3::class)) { @@ -222,7 +192,7 @@ private function checkSqliteVersion(): string */ private function checkSystemTemporaryFolder(): string { - $open_basedir = ini_get('open_basedir'); + $open_basedir = $this->php_service->iniGet(option: 'open_basedir'); if ($open_basedir === '') { // open_basedir not used. @@ -231,7 +201,7 @@ private function checkSystemTemporaryFolder(): string $open_basedirs = explode(PATH_SEPARATOR, $open_basedir); - $sys_temp_dir = sys_get_temp_dir(); + $sys_temp_dir = $this->php_service->sysGetTempDir(); $sys_temp_dir = $this->normalizeFolder($sys_temp_dir); foreach ($open_basedirs as $dir) { @@ -255,10 +225,6 @@ private function checkSystemTemporaryFolder(): string * - trailing slash. * We can't use realpath() as this can trigger open_basedir restrictions, * and we are using this code to find out whether open_basedir will affect us. - * - * @param string $path - * - * @return string */ private function normalizeFolder(string $path): string { @@ -272,8 +238,6 @@ private function normalizeFolder(string $path): string } /** - * @param string $driver - * * @return Collection */ private function databaseDriverErrors(string $driver): Collection @@ -311,8 +275,6 @@ private function databaseDriverErrors(string $driver): Collection } /** - * @param string $driver - * * @return Collection */ private function databaseDriverWarnings(string $driver): Collection diff --git a/app/Services/TimeoutService.php b/app/Services/TimeoutService.php index 103c2a11c88..cca8d579ccf 100644 --- a/app/Services/TimeoutService.php +++ b/app/Services/TimeoutService.php @@ -35,24 +35,19 @@ class TimeoutService // The start time of the request private float $start_time; - /** - * @param float|null $start_time - */ - public function __construct(float|null $start_time = null) - { + public function __construct( + private PhpService $php_service, + float|null $start_time = null, + ) { $this->start_time = $start_time ?? Registry::timeFactory()->now(); } /** * Some long-running scripts need to know when to stop. - * - * @param float $threshold - * - * @return bool */ public function isTimeNearlyUp(float $threshold = self::TIME_UP_THRESHOLD): bool { - $max_execution_time = (int) ini_get('max_execution_time'); + $max_execution_time = $this->php_service->maxExecutionTime(); // If there's no time limit, then we can't run out of time. if ($max_execution_time === 0) { @@ -66,10 +61,6 @@ public function isTimeNearlyUp(float $threshold = self::TIME_UP_THRESHOLD): bool /** * Some long-running scripts are broken down into small chunks. - * - * @param float $limit - * - * @return bool */ public function isTimeLimitUp(float $limit = self::TIME_LIMIT): bool { diff --git a/app/Webtrees.php b/app/Webtrees.php index a9f45eb5a9e..74dffb04c16 100644 --- a/app/Webtrees.php +++ b/app/Webtrees.php @@ -73,6 +73,7 @@ use Fisharebest\Webtrees\Http\Middleware\UseSession; use Fisharebest\Webtrees\Http\Middleware\UseTheme; use Fisharebest\Webtrees\Http\Middleware\UseTransaction; +use Fisharebest\Webtrees\Services\PhpService; use Nyholm\Psr7\Factory\Psr17Factory; use Nyholm\Psr7Server\ServerRequestCreator; use Psr\Http\Message\ResponseFactoryInterface; @@ -205,7 +206,7 @@ public function bootstrap(): self Registry::gedcomRecordFactory(new GedcomRecordFactory()); Registry::headerFactory(new HeaderFactory()); Registry::idFactory(new IdFactory()); - Registry::imageFactory(new ImageFactory()); + Registry::imageFactory(new ImageFactory(new PhpService())); Registry::individualFactory(new IndividualFactory()); Registry::locationFactory(new LocationFactory()); Registry::markdownFactory(new MarkdownFactory()); @@ -215,7 +216,7 @@ public function bootstrap(): self Registry::responseFactory(new ResponseFactory(new Psr17Factory(), new Psr17Factory())); Registry::routeFactory(new RouteFactory()); Registry::sharedNoteFactory(new SharedNoteFactory()); - Registry::slugFactory(new SlugFactory()); + Registry::slugFactory(new SlugFactory(new PhpService())); Registry::sourceFactory(new SourceFactory()); Registry::submissionFactory(new SubmissionFactory()); Registry::submitterFactory(new SubmitterFactory()); diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 67940f1007a..afbffd7116d 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -7152,12 +7152,6 @@ parameters: count: 3 path: app/Services/MediaFileService.php - - - message: '#^Call to function is_float\(\) with int will always evaluate to false\.$#' - identifier: function.impossibleType - count: 1 - path: app/Services/MediaFileService.php - - message: '#^Cannot call method detach\(\) on mixed\.$#' identifier: method.nonObject @@ -7614,12 +7608,6 @@ parameters: count: 1 path: app/Services/SearchService.php - - - message: '#^Cannot cast mixed to string\.$#' - identifier: cast.string - count: 1 - path: app/Services/ServerCheckService.php - - message: '#^Method Fisharebest\\Webtrees\\Services\\ServerCheckService\:\:serverErrors\(\) should return Illuminate\\Support\\Collection\ but returns Illuminate\\Support\\Collection\\.$#' identifier: return.type @@ -7632,24 +7620,12 @@ parameters: count: 1 path: app/Services/ServerCheckService.php - - - message: '#^Parameter \#1 \$value of function e expects BackedEnum\|float\|Illuminate\\Contracts\\Support\\DeferringDisplayableValue\|Illuminate\\Contracts\\Support\\Htmlable\|int\|string\|null, mixed given\.$#' - identifier: argument.type - count: 1 - path: app/Services/ServerCheckService.php - - message: '#^Parameter \#1 \$version1 of function version_compare expects string, mixed given\.$#' identifier: argument.type count: 1 path: app/Services/ServerCheckService.php - - - message: '#^Parameter \#2 \$string of function explode expects string, mixed given\.$#' - identifier: argument.type - count: 1 - path: app/Services/ServerCheckService.php - - message: '#^Parameter \#2 \.\.\.\$args of static method Fisharebest\\Webtrees\\I18N\:\:translate\(\) expects string, mixed given\.$#' identifier: argument.type @@ -7668,12 +7644,6 @@ parameters: count: 1 path: app/Services/SiteLogsService.php - - - message: '#^Cannot cast mixed to int\.$#' - identifier: cast.int - count: 1 - path: app/Services/TimeoutService.php - - message: '#^Parameter \#1 \$stream of function fclose expects resource, resource\|null given\.$#' identifier: argument.type @@ -10649,33 +10619,3 @@ parameters: identifier: argument.templateType count: 1 path: tests/app/Services/ModuleServiceTest.php - - - - message: '#^Call to an undefined method object\:\:iniGet\(\)\.$#' - identifier: method.notFound - count: 1 - path: tests/app/Services/TimeoutServiceTest.php - - - - message: '#^Cannot call method method\(\) on object\|null\.$#' - identifier: method.nonObject - count: 3 - path: tests/app/Services/TimeoutServiceTest.php - - - - message: '#^Cannot call method willReturn\(\) on mixed\.$#' - identifier: method.nonObject - count: 3 - path: tests/app/Services/TimeoutServiceTest.php - - - - message: '#^Cannot call method with\(\) on mixed\.$#' - identifier: method.nonObject - count: 3 - path: tests/app/Services/TimeoutServiceTest.php - - - - message: '#^Parameter \#1 \$option of function ini_get expects string, mixed given\.$#' - identifier: argument.type - count: 1 - path: tests/app/Services/TimeoutServiceTest.php diff --git a/resources/views/setup/step-4-database-mysql.phtml b/resources/views/setup/step-4-database-mysql.phtml index f4ba3f1ede4..fca978c684a 100644 --- a/resources/views/setup/step-4-database-mysql.phtml +++ b/resources/views/setup/step-4-database-mysql.phtml @@ -14,6 +14,7 @@ use Illuminate\Support\Collection; * @var string $dbuser * @var Collection $errors * @var string $lang + * @var string $mysql_local * @var string $tblpfx * @var Collection $warnings * @var string $wtemail @@ -61,7 +62,7 @@ use Illuminate\Support\Collection;
- +
diff --git a/tests/TestCase.php b/tests/TestCase.php index 1998009147d..d81d1ac6047 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -30,6 +30,7 @@ use Fisharebest\Webtrees\Services\GedcomImportService; use Fisharebest\Webtrees\Services\MigrationService; use Fisharebest\Webtrees\Services\ModuleService; +use Fisharebest\Webtrees\Services\PhpService; use Fisharebest\Webtrees\Services\TimeoutService; use Fisharebest\Webtrees\Services\TreeService; use PHPUnit\Framework\Constraint\Callback; @@ -56,8 +57,6 @@ class TestCase extends \PHPUnit\Framework\TestCase { - public static ?object $mock_functions = null; - protected static bool $uses_database = false; /** @@ -189,7 +188,7 @@ protected function importTree(string $gedcom_file): Tree $tree_service->importGedcomFile($tree, $stream, $gedcom_file, ''); - $timeout_service = new TimeoutService(); + $timeout_service = new TimeoutService(php_service: new PhpService()); $controller = new GedcomLoad($gedcom_import_service, $timeout_service); $request = self::createRequest()->withAttribute('tree', $tree); diff --git a/tests/app/Http/Middleware/HandleExceptionsTest.php b/tests/app/Http/Middleware/HandleExceptionsTest.php index 74c2ce65f7f..1e4c775413e 100644 --- a/tests/app/Http/Middleware/HandleExceptionsTest.php +++ b/tests/app/Http/Middleware/HandleExceptionsTest.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Http\Exceptions\HttpServerErrorException; use Fisharebest\Webtrees\Registry; use Fisharebest\Webtrees\Services\ModuleService; +use Fisharebest\Webtrees\Services\PhpService; use Fisharebest\Webtrees\Services\TreeService; use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\TestCase; @@ -48,7 +49,7 @@ public function testMiddleware(): void Registry::container()->set(ModuleService::class, $module_service); $request = self::createRequest(); - $middleware = new HandleExceptions($tree_service); + $middleware = new HandleExceptions(php_service: new PhpService(), tree_service: $tree_service); $response = $middleware->process($request, $handler); self::assertSame(StatusCodeInterface::STATUS_INTERNAL_SERVER_ERROR, $response->getStatusCode()); diff --git a/tests/app/Http/RequestHandlers/ControlPanelControllerTest.php b/tests/app/Http/RequestHandlers/ControlPanelControllerTest.php index 1fa23866673..27fb5a5d429 100644 --- a/tests/app/Http/RequestHandlers/ControlPanelControllerTest.php +++ b/tests/app/Http/RequestHandlers/ControlPanelControllerTest.php @@ -26,6 +26,7 @@ use Fisharebest\Webtrees\Services\HousekeepingService; use Fisharebest\Webtrees\Services\MessageService; use Fisharebest\Webtrees\Services\ModuleService; +use Fisharebest\Webtrees\Services\PhpService; use Fisharebest\Webtrees\Services\ServerCheckService; use Fisharebest\Webtrees\Services\TimeoutService; use Fisharebest\Webtrees\Services\TreeService; @@ -42,18 +43,27 @@ class ControlPanelControllerTest extends TestCase public function testControlPanel(): void { $admin_service = new AdminService(); - $message_service = new MessageService(new EmailService(), new UserService()); + $message_service = new MessageService(email_service: new EmailService(), user_service: new UserService()); $module_service = new ModuleService(); $housekeeping_service = new HousekeepingService(); - $server_check_service = new ServerCheckService(); - $timeout_service = new TimeoutService(); + $server_check_service = new ServerCheckService(php_service: new PhpService()); + $timeout_service = new TimeoutService(php_service: new PhpService()); $gedcom_import_service = new GedcomImportService(); - $tree_service = new TreeService($gedcom_import_service); - $upgrade_service = new UpgradeService($timeout_service); + $tree_service = new TreeService(gedcom_import_service: $gedcom_import_service); + $upgrade_service = new UpgradeService(timeout_service: $timeout_service); $user_service = new UserService(); - $handler = new ControlPanel($admin_service, $housekeeping_service, $message_service, $module_service, $server_check_service, $tree_service, $upgrade_service, $user_service); + $handler = new ControlPanel( + admin_service: $admin_service, + housekeeping_service: $housekeeping_service, + message_service: $message_service, + module_service: $module_service, + server_check_service: $server_check_service, + tree_service: $tree_service, + upgrade_service: $upgrade_service, + user_service: $user_service, + ); $request = self::createRequest(); - $response = $handler->handle($request); + $response = $handler->handle(request: $request); self::assertSame(StatusCodeInterface::STATUS_OK, $response->getStatusCode()); } diff --git a/tests/app/Http/RequestHandlers/ManageMediaPageTest.php b/tests/app/Http/RequestHandlers/ManageMediaPageTest.php index 4349fa449b5..c33a7579ad4 100644 --- a/tests/app/Http/RequestHandlers/ManageMediaPageTest.php +++ b/tests/app/Http/RequestHandlers/ManageMediaPageTest.php @@ -21,6 +21,7 @@ use Fig\Http\Message\StatusCodeInterface; use Fisharebest\Webtrees\Services\MediaFileService; +use Fisharebest\Webtrees\Services\PhpService; use Fisharebest\Webtrees\TestCase; use PHPUnit\Framework\Attributes\CoversClass; @@ -31,8 +32,8 @@ class ManageMediaPageTest extends TestCase public function testIndex(): void { - $media_file_service = new MediaFileService(); - $handler = new ManageMediaPage($media_file_service); + $media_file_service = new MediaFileService(php_service: new PhpService()); + $handler = new ManageMediaPage(media_file_service: $media_file_service); $request = self::createRequest(); $response = $handler->handle($request); diff --git a/tests/app/Http/RequestHandlers/UpgradeWizardPageTest.php b/tests/app/Http/RequestHandlers/UpgradeWizardPageTest.php index e27717d9bbc..d8702a7910f 100644 --- a/tests/app/Http/RequestHandlers/UpgradeWizardPageTest.php +++ b/tests/app/Http/RequestHandlers/UpgradeWizardPageTest.php @@ -21,6 +21,7 @@ use Fig\Http\Message\StatusCodeInterface; use Fisharebest\Webtrees\Services\GedcomImportService; +use Fisharebest\Webtrees\Services\PhpService; use Fisharebest\Webtrees\Services\TimeoutService; use Fisharebest\Webtrees\Services\TreeService; use Fisharebest\Webtrees\Services\UpgradeService; @@ -34,7 +35,7 @@ class UpgradeWizardPageTest extends TestCase public function testWizard(): void { - $timeout_service = new TimeoutService(); + $timeout_service = new TimeoutService(php_service: new PhpService()); $gedcom_import_service = new GedcomImportService(); $tree_service = new TreeService($gedcom_import_service); $upgrade_service = new UpgradeService($timeout_service); diff --git a/tests/app/Http/RequestHandlers/UpgradeWizardStepTest.php b/tests/app/Http/RequestHandlers/UpgradeWizardStepTest.php index 3665c91d322..2609e343b49 100644 --- a/tests/app/Http/RequestHandlers/UpgradeWizardStepTest.php +++ b/tests/app/Http/RequestHandlers/UpgradeWizardStepTest.php @@ -26,6 +26,7 @@ use Fisharebest\Webtrees\Http\Exceptions\HttpServerErrorException; use Fisharebest\Webtrees\Services\GedcomExportService; use Fisharebest\Webtrees\Services\GedcomImportService; +use Fisharebest\Webtrees\Services\PhpService; use Fisharebest\Webtrees\Services\TimeoutService; use Fisharebest\Webtrees\Services\TreeService; use Fisharebest\Webtrees\Services\UpgradeService; @@ -45,7 +46,7 @@ public function testIgnoreStepInvalid(): void $handler = new UpgradeWizardStep( new GedcomExportService(new Psr17Factory(), new Psr17Factory()), new TreeService(new GedcomImportService()), - new UpgradeService(new TimeoutService()) + new UpgradeService(new TimeoutService(php_service: new PhpService())) ); $request = self::createRequest(RequestMethodInterface::METHOD_POST, ['step' => 'Invalid']); @@ -108,7 +109,7 @@ public function testStepPrepare(): void $handler = new UpgradeWizardStep( new GedcomExportService(new Psr17Factory(), new Psr17Factory()), new TreeService(new GedcomImportService()), - new UpgradeService(new TimeoutService()) + new UpgradeService(new TimeoutService(php_service: new PhpService())) ); $request = self::createRequest(RequestMethodInterface::METHOD_POST, ['step' => 'Prepare']); @@ -122,7 +123,7 @@ public function testStepPending(): void $handler = new UpgradeWizardStep( new GedcomExportService(new Psr17Factory(), new Psr17Factory()), new TreeService(new GedcomImportService()), - new UpgradeService(new TimeoutService()) + new UpgradeService(new TimeoutService(php_service: new PhpService())) ); $request = self::createRequest(RequestMethodInterface::METHOD_POST, ['step' => 'Pending']); @@ -143,7 +144,7 @@ public function testStepPendingExist(): void $handler = new UpgradeWizardStep( new GedcomExportService(new Psr17Factory(), new Psr17Factory()), new TreeService(new GedcomImportService()), - new UpgradeService(new TimeoutService()) + new UpgradeService(new TimeoutService(php_service: new PhpService())) ); $request = self::createRequest(RequestMethodInterface::METHOD_POST, ['step' => 'Pending']); @@ -162,7 +163,7 @@ public function testStepExport(): void $handler = new UpgradeWizardStep( new GedcomExportService(new Psr17Factory(), new Psr17Factory()), $tree_service, - new UpgradeService(new TimeoutService()) + new UpgradeService(new TimeoutService(php_service: new PhpService())) ); $request = self::createRequest()->withQueryParams(['step' => 'Export', 'tree' => $tree->name()]); diff --git a/tests/app/Http/RequestHandlers/UploadMediaActionTest.php b/tests/app/Http/RequestHandlers/UploadMediaActionTest.php index 9da8dae4407..ea4af30f734 100644 --- a/tests/app/Http/RequestHandlers/UploadMediaActionTest.php +++ b/tests/app/Http/RequestHandlers/UploadMediaActionTest.php @@ -21,6 +21,7 @@ use Fig\Http\Message\StatusCodeInterface; use Fisharebest\Webtrees\Services\MediaFileService; +use Fisharebest\Webtrees\Services\PhpService; use Fisharebest\Webtrees\TestCase; use PHPUnit\Framework\Attributes\CoversClass; @@ -31,8 +32,8 @@ class UploadMediaActionTest extends TestCase public function testResponseIsOK(): void { - $media_file_service = new MediaFileService(); - $handler = new UploadMediaAction($media_file_service); + $media_file_service = new MediaFileService(php_service: new PhpService()); + $handler = new UploadMediaAction(media_file_service: $media_file_service); $request = self::createRequest(); $response = $handler->handle($request); diff --git a/tests/app/Http/RequestHandlers/UploadMediaPageTest.php b/tests/app/Http/RequestHandlers/UploadMediaPageTest.php index 94f04008545..4f906f11f88 100644 --- a/tests/app/Http/RequestHandlers/UploadMediaPageTest.php +++ b/tests/app/Http/RequestHandlers/UploadMediaPageTest.php @@ -21,6 +21,7 @@ use Fig\Http\Message\StatusCodeInterface; use Fisharebest\Webtrees\Services\MediaFileService; +use Fisharebest\Webtrees\Services\PhpService; use Fisharebest\Webtrees\TestCase; use PHPUnit\Framework\Attributes\CoversClass; @@ -31,8 +32,9 @@ class UploadMediaPageTest extends TestCase public function testResponseIsOK(): void { - $media_file_service = new MediaFileService(); - $handler = new UploadMediaPage($media_file_service); + $php_service = new PhpService(); + $media_file_service = new MediaFileService(php_service: $php_service); + $handler = new UploadMediaPage(media_file_service: $media_file_service, php_service: $php_service); $request = self::createRequest(); $response = $handler->handle($request); diff --git a/tests/app/Services/TimeoutServiceTest.php b/tests/app/Services/TimeoutServiceTest.php index 16c5a4034f4..05bb014c9bd 100644 --- a/tests/app/Services/TimeoutServiceTest.php +++ b/tests/app/Services/TimeoutServiceTest.php @@ -20,68 +20,33 @@ namespace Fisharebest\Webtrees\Services; use Fisharebest\Webtrees\Contracts\TimeFactoryInterface; -use Fisharebest\Webtrees\MockGlobalFunctions; use Fisharebest\Webtrees\Registry; use Fisharebest\Webtrees\TestCase; use PHPUnit\Framework\Attributes\CoversClass; -/** - * Mock function. - * - * @param mixed ...$args - * - * @return mixed - */ -function ini_get(...$args) -{ - if (TestCase::$mock_functions === null) { - return \ini_get(...$args); - } - - return TestCase::$mock_functions->iniGet(...$args); -} - #[CoversClass(TimeoutService::class)] class TimeoutServiceTest extends TestCase { - protected function setUp(): void - { - parent::setUp(); - - self::$mock_functions = $this->createMock(MockGlobalFunctions::class); - } - - protected function tearDown(): void - { - parent::setUp(); - - self::$mock_functions = null; - } - public function testNoTimeOut(): void { - $now = 1500000000.0; + $php_service = $this->createMock(PhpService::class); + $php_service->method('maxExecutionTime')->willReturn(0); - $timeout_service = new TimeoutService($now); + $now = 1500000000.0; - self::$mock_functions - ->method('iniGet') - ->with('max_execution_time') - ->willReturn('0'); + $timeout_service = new TimeoutService(php_service: $php_service, start_time: $now); self::assertFalse($timeout_service->isTimeNearlyUp()); } public function testTimeOutReached(): void { - $now = 1500000000.0; + $php_service = $this->createMock(PhpService::class); + $php_service->method('maxExecutionTime')->willReturn(30); - $timeout_service = new TimeoutService($now); + $now = 1500000000.0; - self::$mock_functions - ->method('iniGet') - ->with('max_execution_time') - ->willReturn('30'); + $timeout_service = new TimeoutService(php_service: $php_service, start_time: $now); $time_factory = $this->createMock(TimeFactoryInterface::class); $time_factory->method('now')->willReturn($now + 60.0); @@ -92,14 +57,12 @@ public function testTimeOutReached(): void public function testTimeOutNotReached(): void { - $now = Registry::timeFactory()->now(); + $php_service = $this->createMock(PhpService::class); + $php_service->method('maxExecutionTime')->willReturn(30); - $timeout_service = new TimeoutService($now); + $now = Registry::timeFactory()->now(); - self::$mock_functions - ->method('iniGet') - ->with('max_execution_time') - ->willReturn('30'); + $timeout_service = new TimeoutService(php_service: $php_service, start_time: $now); $time_factory = $this->createMock(TimeFactoryInterface::class); $time_factory->method('now')->willReturn($now + 10.0); @@ -112,7 +75,7 @@ public function testTimeLimitNotReached(): void { $now = Registry::timeFactory()->now(); - $timeout_service = new TimeoutService($now); + $timeout_service = new TimeoutService(php_service: new PhpService(), start_time: $now); $time_factory = $this->createMock(TimeFactoryInterface::class); $time_factory->method('now')->willReturn($now + 1.4); @@ -125,7 +88,7 @@ public function testTimeLimitReached(): void { $now = Registry::timeFactory()->now(); - $timeout_service = new TimeoutService($now); + $timeout_service = new TimeoutService(php_service: new PhpService(), start_time: $now); $time_factory = $this->createMock(TimeFactoryInterface::class); $time_factory->method('now')->willReturn($now + 1.6);