From a93a5b8d4fcfd65d961600faf3e67dca93851f5b Mon Sep 17 00:00:00 2001 From: Niels Vanpachtenbeke <10651054+Nielsvanpach@users.noreply.github.com> Date: Fri, 7 Jun 2024 10:59:48 +0200 Subject: [PATCH] add more types --- composer.json | 4 +- phpstan-baseline.neon | 56 +++++++++++++++++++ phpstan.neon.dist | 2 +- src/BackupDestination/Backup.php | 1 + src/BackupDestination/BackupCollection.php | 2 + src/BackupDestination/BackupDestination.php | 1 + .../BackupDestinationFactory.php | 4 ++ src/BackupServiceProvider.php | 2 +- src/Commands/BackupCommand.php | 2 +- src/Commands/BaseCommand.php | 2 + src/Commands/ListCommand.php | 11 +++- src/Exceptions/CannotCreateDbDumper.php | 8 ++- src/Exceptions/NotificationCouldNotBeSent.php | 2 +- src/Helpers/ConsoleOutput.php | 3 +- src/Helpers/File.php | 1 + src/Notifications/BaseNotification.php | 2 + .../Channels/Discord/DiscordChannel.php | 3 +- .../Channels/Discord/DiscordMessage.php | 4 +- src/Notifications/EventHandler.php | 10 +++- src/Notifications/Notifiable.php | 1 + src/Tasks/Backup/BackupJob.php | 17 ++++-- src/Tasks/Backup/BackupJobFactory.php | 7 +++ src/Tasks/Backup/DbDumperFactory.php | 8 ++- src/Tasks/Backup/FileSelection.php | 24 ++++++-- src/Tasks/Backup/Manifest.php | 3 + src/Tasks/Backup/Zip.php | 2 +- src/Tasks/Cleanup/CleanupJob.php | 3 +- src/Tasks/Cleanup/CleanupStrategy.php | 2 +- .../Cleanup/Strategies/DefaultStrategy.php | 14 +++-- src/Tasks/Monitor/BackupDestinationStatus.php | 2 + .../BackupDestinationStatusFactory.php | 27 ++++++++- src/Tasks/Monitor/HealthCheck.php | 2 +- src/Traits/Retryable.php | 10 ++-- tests/TestSupport/FakeFailingHealthCheck.php | 2 +- 34 files changed, 195 insertions(+), 49 deletions(-) diff --git a/composer.json b/composer.json index ffaea00b..d41ff2e0 100644 --- a/composer.json +++ b/composer.json @@ -32,10 +32,10 @@ "spatie/laravel-signal-aware-command": "^1.2|^2.0", "spatie/temporary-directory": "^2.0", "symfony/console": "^6.0|^7.0", - "symfony/finder": "^6.0|^7.0" + "symfony/finder": "^6.0|^7.0", + "ext-pcntl": "*" }, "require-dev": { - "ext-pcntl": "*", "composer-runtime-api": "^2.0", "larastan/larastan": "^2.7.0", "laravel/slack-notification-channel": "^2.5|^3.0", diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index e69de29b..c56c638a 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -0,0 +1,56 @@ +parameters: + ignoreErrors: + - + message: "#^Parameter \\#1 \\$callback of method Illuminate\\\\Support\\\\Collection\\\\:\\:filter\\(\\) expects \\(callable\\(Spatie\\\\Backup\\\\BackupDestination\\\\Backup, int\\)\\: bool\\)\\|null, Closure\\(string\\)\\: bool given\\.$#" + count: 1 + path: src/BackupDestination/BackupCollection.php + + - + message: "#^Parameter \\#1 \\$callback of method Illuminate\\\\Support\\\\Collection\\\\:\\:map\\(\\) expects callable\\(Spatie\\\\Backup\\\\BackupDestination\\\\Backup, int\\)\\: Spatie\\\\Backup\\\\BackupDestination\\\\Backup, Closure\\(string\\)\\: Spatie\\\\Backup\\\\BackupDestination\\\\Backup given\\.$#" + count: 1 + path: src/BackupDestination/BackupCollection.php + + - + message: "#^Unable to resolve the template type TKey in call to function collect$#" + count: 1 + path: src/BackupDestination/BackupDestinationFactory.php + + - + message: "#^Unable to resolve the template type TValue in call to function collect$#" + count: 1 + path: src/BackupDestination/BackupDestinationFactory.php + + - + message: "#^Parameter \\#1 \\$callback of method Illuminate\\\\Support\\\\Collection\\\\:\\:map\\(\\) expects callable\\(int, int\\)\\: string, Closure\\(string\\)\\: non\\-falsy\\-string given\\.$#" + count: 1 + path: src/Exceptions/CannotCreateDbDumper.php + + - + message: "#^Method Spatie\\\\Backup\\\\Notifications\\\\Channels\\\\Discord\\\\DiscordMessage\\:\\:toArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/Notifications/Channels/Discord/DiscordMessage.php + + - + message: "#^Method Spatie\\\\Backup\\\\Tasks\\\\Backup\\\\FileSelection\\:\\:sanitize\\(\\) return type with generic class Illuminate\\\\Support\\\\Collection does not specify its types\\: TKey, TValue$#" + count: 1 + path: src/Tasks/Backup/FileSelection.php + + - + message: "#^Method Spatie\\\\Backup\\\\Tasks\\\\Backup\\\\Manifest\\:\\:files\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/Tasks/Backup/Manifest.php + + - + message: "#^Method Spatie\\\\Backup\\\\Tasks\\\\Backup\\\\Manifest\\:\\:files\\(\\) return type has no value type specified in iterable type array\\|Generator\\.$#" + count: 1 + path: src/Tasks/Backup/Manifest.php + + - + message: "#^Method Spatie\\\\Backup\\\\Tasks\\\\Backup\\\\Zip\\:\\:add\\(\\) has parameter \\$files with no value type specified in iterable type iterable\\.$#" + count: 1 + path: src/Tasks/Backup/Zip.php + + - + message: "#^Parameter \\#1 \\$callback of method Illuminate\\\\Support\\\\Collection\\\\:\\:each\\(\\) expects callable\\(Spatie\\\\Backup\\\\BackupDestination\\\\Backup, int\\)\\: mixed, Closure\\(Spatie\\\\Backup\\\\BackupDestination\\\\BackupCollection\\)\\: void given\\.$#" + count: 1 + path: src/Tasks/Cleanup/Strategies/DefaultStrategy.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 81a4e5b0..685a823f 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,7 +2,7 @@ includes: - phpstan-baseline.neon parameters: - level: 5 + level: 6 paths: - src - config diff --git a/src/BackupDestination/Backup.php b/src/BackupDestination/Backup.php index b4b4c0f7..6a0d6d31 100644 --- a/src/BackupDestination/Backup.php +++ b/src/BackupDestination/Backup.php @@ -66,6 +66,7 @@ public function sizeInBytes(): float return $this->size; } + /** @return resource */ public function stream() { return throw_unless( diff --git a/src/BackupDestination/BackupCollection.php b/src/BackupDestination/BackupCollection.php index 514c1bfa..dc998fdf 100644 --- a/src/BackupDestination/BackupCollection.php +++ b/src/BackupDestination/BackupCollection.php @@ -6,10 +6,12 @@ use Illuminate\Support\Collection; use Spatie\Backup\Helpers\File; +/** @extends Collection */ class BackupCollection extends Collection { protected ?float $sizeCache = null; + /** @param array $files */ public static function createFromFiles(?FileSystem $disk, array $files): self { return (new static($files)) diff --git a/src/BackupDestination/BackupDestination.php b/src/BackupDestination/BackupDestination.php index 73d6f684..3ef69882 100644 --- a/src/BackupDestination/BackupDestination.php +++ b/src/BackupDestination/BackupDestination.php @@ -114,6 +114,7 @@ public function connectionError(): Exception return $this->connectionError; } + /** @return array */ public function getDiskOptions(): array { return config("filesystems.disks.{$this->diskName()}.backup_options") ?? []; diff --git a/src/BackupDestination/BackupDestinationFactory.php b/src/BackupDestination/BackupDestinationFactory.php index 3212470a..99c085b4 100644 --- a/src/BackupDestination/BackupDestinationFactory.php +++ b/src/BackupDestination/BackupDestinationFactory.php @@ -6,6 +6,10 @@ class BackupDestinationFactory { + /** + * @param array $config + * @return Collection + */ public static function createFromArray(array $config): Collection { return collect($config['destination']['disks']) diff --git a/src/BackupServiceProvider.php b/src/BackupServiceProvider.php index 8e460d53..ecd087bb 100644 --- a/src/BackupServiceProvider.php +++ b/src/BackupServiceProvider.php @@ -52,7 +52,7 @@ public function packageRegistered(): void $this->registerDiscordChannel(); } - protected function registerDiscordChannel() + protected function registerDiscordChannel(): void { Notification::resolved(function (ChannelManager $service) { $service->extend('discord', function ($app) { diff --git a/src/Commands/BackupCommand.php b/src/Commands/BackupCommand.php index b69d5cfd..07dfdaa7 100644 --- a/src/Commands/BackupCommand.php +++ b/src/Commands/BackupCommand.php @@ -95,7 +95,7 @@ public function handle(): int } } - protected function guardAgainstInvalidOptions() + protected function guardAgainstInvalidOptions(): void { if (! $this->option('only-db')) { return; diff --git a/src/Commands/BaseCommand.php b/src/Commands/BaseCommand.php index 0762f723..b05aaf56 100644 --- a/src/Commands/BaseCommand.php +++ b/src/Commands/BaseCommand.php @@ -10,6 +10,7 @@ abstract class BaseCommand extends SignalAwareCommand { + /** @var array */ protected array $handlesSignals = []; public function __construct() @@ -33,6 +34,7 @@ protected function runningInConsole(): bool return in_array(PHP_SAPI, ['cli', 'phpdbg']); } + /** @return array */ public function getSubscribedSignals(): array { return $this->handlesSignals; diff --git a/src/Commands/ListCommand.php b/src/Commands/ListCommand.php index cf63ca23..94d961e3 100644 --- a/src/Commands/ListCommand.php +++ b/src/Commands/ListCommand.php @@ -30,7 +30,10 @@ public function handle(): int return static::SUCCESS; } - protected function displayOverview(Collection $backupDestinationStatuses) + /** + * @param Collection $backupDestinationStatuses + */ + protected function displayOverview(Collection $backupDestinationStatuses): static { $headers = ['Name', 'Disk', 'Reachable', 'Healthy', '# of backups', 'Newest backup', 'Used storage']; @@ -46,6 +49,7 @@ protected function displayOverview(Collection $backupDestinationStatuses) return $this; } + /** @return array{0: string, 1: string, 2: string, disk: string, amount: integer, newest: string, usedStorage: string} */ public function convertToRow(BackupDestinationStatus $backupDestinationStatus): array { $destination = $backupDestinationStatus->backupDestination(); @@ -73,7 +77,8 @@ public function convertToRow(BackupDestinationStatus $backupDestinationStatus): return $row; } - protected function displayFailures(Collection $backupDestinationStatuses) + /** @param Collection $backupDestinationStatuses */ + protected function displayFailures(Collection $backupDestinationStatuses): static { $failed = $backupDestinationStatuses ->filter(function (BackupDestinationStatus $backupDestinationStatus) { @@ -98,7 +103,7 @@ protected function displayFailures(Collection $backupDestinationStatuses) return $this; } - protected function getFormattedBackupDate(?Backup $backup = null) + protected function getFormattedBackupDate(?Backup $backup = null): string { return is_null($backup) ? 'No backups present' diff --git a/src/Exceptions/CannotCreateDbDumper.php b/src/Exceptions/CannotCreateDbDumper.php index 3c756a23..5fabe436 100644 --- a/src/Exceptions/CannotCreateDbDumper.php +++ b/src/Exceptions/CannotCreateDbDumper.php @@ -6,11 +6,13 @@ class CannotCreateDbDumper extends Exception { - public static function unsupportedDriver(string $driver): self + public static function unsupportedDriver(string $driver): static { - $supportedDrivers = collect(config('database.connections'))->keys(); + /** @var array $supportedDrivers */ + $supportedDrivers = config('database.connections'); - $formattedSupportedDrivers = $supportedDrivers + $formattedSupportedDrivers = collect($supportedDrivers) + ->keys() ->map(fn (string $supportedDriver) => "`{$supportedDriver}`") ->join(glue: ', ', finalGlue: ' or '); diff --git a/src/Exceptions/NotificationCouldNotBeSent.php b/src/Exceptions/NotificationCouldNotBeSent.php index b01d0c17..c09dfad1 100644 --- a/src/Exceptions/NotificationCouldNotBeSent.php +++ b/src/Exceptions/NotificationCouldNotBeSent.php @@ -6,7 +6,7 @@ class NotificationCouldNotBeSent extends Exception { - public static function noNotificationClassForEvent($event): self + public static function noNotificationClassForEvent(object $event): static { $eventClass = $event::class; diff --git a/src/Helpers/ConsoleOutput.php b/src/Helpers/ConsoleOutput.php index 72107288..8294d3ab 100644 --- a/src/Helpers/ConsoleOutput.php +++ b/src/Helpers/ConsoleOutput.php @@ -18,7 +18,8 @@ public function setCommand(Command $command): void $this->command = $command; } - public function __call(string $method, array $arguments) + /** @param array $arguments */ + public function __call(string $method, array $arguments): void { $consoleOutput = app(static::class); diff --git a/src/Helpers/File.php b/src/Helpers/File.php index bcf7a2fe..0c33b3d1 100644 --- a/src/Helpers/File.php +++ b/src/Helpers/File.php @@ -7,6 +7,7 @@ class File { + /** @var array */ protected static array $allowedMimeTypes = [ 'application/zip', 'application/x-zip', diff --git a/src/Notifications/BaseNotification.php b/src/Notifications/BaseNotification.php index 9a509e9f..d91d75e4 100644 --- a/src/Notifications/BaseNotification.php +++ b/src/Notifications/BaseNotification.php @@ -9,6 +9,7 @@ abstract class BaseNotification extends Notification { + /** @return array */ public function via(): array { $notificationChannels = config('backup.notifications.notifications.'.static::class); @@ -34,6 +35,7 @@ public function diskName(): string return $this->backupDestination()->diskName(); } + /** @return Collection */ protected function backupDestinationProperties(): Collection { $backupDestination = $this->backupDestination(); diff --git a/src/Notifications/Channels/Discord/DiscordChannel.php b/src/Notifications/Channels/Discord/DiscordChannel.php index 6571e12d..93c32230 100644 --- a/src/Notifications/Channels/Discord/DiscordChannel.php +++ b/src/Notifications/Channels/Discord/DiscordChannel.php @@ -4,10 +4,11 @@ use Illuminate\Notifications\Notification; use Illuminate\Support\Facades\Http; +use Spatie\Backup\Notifications\Notifiable; class DiscordChannel { - public function send($notifiable, Notification $notification): void + public function send(Notifiable $notifiable, Notification $notification): void { $discordMessage = $notification->toDiscord(); // @phpstan-ignore-line diff --git a/src/Notifications/Channels/Discord/DiscordMessage.php b/src/Notifications/Channels/Discord/DiscordMessage.php index b7bf6555..1d865eeb 100644 --- a/src/Notifications/Channels/Discord/DiscordMessage.php +++ b/src/Notifications/Channels/Discord/DiscordMessage.php @@ -20,6 +20,7 @@ class DiscordMessage protected string $description = ''; + /** @var array */ protected array $fields = []; protected ?string $timestamp = null; @@ -48,7 +49,7 @@ public function url(string $url): self return $this; } - public function title($title): self + public function title(string $title): self { $this->title = $title; @@ -97,6 +98,7 @@ public function error(): self return $this; } + /** @param array $fields */ public function fields(array $fields, bool $inline = true): self { foreach ($fields as $label => $value) { diff --git a/src/Notifications/EventHandler.php b/src/Notifications/EventHandler.php index 25c20f3a..6f1fdeec 100644 --- a/src/Notifications/EventHandler.php +++ b/src/Notifications/EventHandler.php @@ -31,18 +31,21 @@ public function subscribe(Dispatcher $events): void }); } - protected function determineNotifiable() + protected function determineNotifiable(): Notifiable { $notifiableClass = $this->config->get('backup.notifications.notifiable'); return app($notifiableClass); } - protected function determineNotification($event): Notification + protected function determineNotification(object $event): Notification { $lookingForNotificationClass = class_basename($event).'Notification'; - $notificationClass = collect($this->config->get('backup.notifications.notifications')) + /** @var array> $notificationClasses */ + $notificationClasses = $this->config->get('backup.notifications.notifications'); + + $notificationClass = collect($notificationClasses) ->keys() ->first(fn (string $notificationClass) => class_basename($notificationClass) === $lookingForNotificationClass); @@ -53,6 +56,7 @@ protected function determineNotification($event): Notification return new $notificationClass($event); } + /** @return array */ protected function allBackupEventClasses(): array { return [ diff --git a/src/Notifications/Notifiable.php b/src/Notifications/Notifiable.php index 13e30475..419ce283 100644 --- a/src/Notifications/Notifiable.php +++ b/src/Notifications/Notifiable.php @@ -8,6 +8,7 @@ class Notifiable { use NotifiableTrait; + /** @return string|array{int, string} */ public function routeNotificationForMail(): string|array { return config('backup.notifications.mail.to'); diff --git a/src/Tasks/Backup/BackupJob.php b/src/Tasks/Backup/BackupJob.php index 662acfda..16bf96d2 100644 --- a/src/Tasks/Backup/BackupJob.php +++ b/src/Tasks/Backup/BackupJob.php @@ -27,8 +27,10 @@ class BackupJob protected FileSelection $fileSelection; + /** @var Collection */ protected Collection $dbDumpers; + /** @var Collection */ protected Collection $backupDestinations; protected string $filename; @@ -56,6 +58,7 @@ public function dontBackupFilesystem(): self return $this; } + /** @param array $allowedDbNames */ public function onlyDbName(array $allowedDbNames): self { $this->dbDumpers = $this->dbDumpers->filter( @@ -100,6 +103,10 @@ public function setFileSelection(FileSelection $fileSelection): self return $this; } + /** + * @param Collection $dbDumpers + * @return $this + */ public function setDbDumpers(Collection $dbDumpers): self { $this->dbDumpers = $dbDumpers; @@ -127,6 +134,7 @@ public function onlyBackupTo(string $diskName): self return $this; } + /** @param Collection $backupDestinations */ public function setBackupDestinations(Collection $backupDestinations): self { $this->backupDestinations = $backupDestinations; @@ -134,9 +142,7 @@ public function setBackupDestinations(Collection $backupDestinations): self return $this; } - /** - * @throws Exception - */ + /** @throws Exception */ public function run(): void { $temporaryDirectoryPath = config('backup.backup.temporary_directory') ?? storage_path('app/backup-temp'); @@ -206,6 +212,7 @@ public function filesToBeBackedUp(): Generator return $this->fileSelection->selectedFiles(); } + /** @return array */ protected function directoriesUsedByBackupJob(): array { return $this->backupDestinations @@ -240,6 +247,8 @@ protected function createZipContainingEveryFileInManifest(Manifest $manifest): s /** * Dumps the databases to the given directory. * Returns an array with paths to the dump files. + * + * @return array */ protected function dumpDatabases(): array { @@ -312,7 +321,7 @@ protected function copyToBackupDestinations(string $path): void }); } - protected function sendNotification($notification): void + protected function sendNotification(object|string $notification): void { if ($this->sendNotifications) { rescue( diff --git a/src/Tasks/Backup/BackupJobFactory.php b/src/Tasks/Backup/BackupJobFactory.php index f9cfddfe..3ce874a8 100644 --- a/src/Tasks/Backup/BackupJobFactory.php +++ b/src/Tasks/Backup/BackupJobFactory.php @@ -5,9 +5,11 @@ use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Spatie\Backup\BackupDestination\BackupDestinationFactory; +use Spatie\DbDumper\DbDumper; class BackupJobFactory { + /** @param array> $config */ public static function createFromArray(array $config): BackupJob { return (new BackupJob()) @@ -16,6 +18,7 @@ public static function createFromArray(array $config): BackupJob ->setBackupDestinations(BackupDestinationFactory::createFromArray($config['backup'])); } + /** @param array $sourceFiles */ protected static function createFileSelection(array $sourceFiles): FileSelection { return FileSelection::create($sourceFiles['include']) @@ -24,6 +27,10 @@ protected static function createFileSelection(array $sourceFiles): FileSelection ->shouldIgnoreUnreadableDirs(Arr::get($sourceFiles, 'ignore_unreadable_directories', false)); } + /** + * @param array $dbConnectionNames + * @return Collection + */ protected static function createDbDumpers(array $dbConnectionNames): Collection { return collect($dbConnectionNames)->mapWithKeys( diff --git a/src/Tasks/Backup/DbDumperFactory.php b/src/Tasks/Backup/DbDumperFactory.php index c416abd1..f879a790 100644 --- a/src/Tasks/Backup/DbDumperFactory.php +++ b/src/Tasks/Backup/DbDumperFactory.php @@ -15,6 +15,7 @@ class DbDumperFactory { + /** @var array */ protected static array $custom = []; public static function createFromConnection(string $dbConnectionName): DbDumper @@ -74,9 +75,9 @@ public static function extend(string $driver, callable $callback): void static::$custom[$driver] = $callback; } - protected static function forDriver($dbDriver): DbDumper + protected static function forDriver(string $dbDriver): DbDumper { - $driver = strtolower((string) $dbDriver); + $driver = strtolower($dbDriver); if (isset(static::$custom[$driver])) { return (static::$custom[$driver])(); @@ -91,6 +92,7 @@ protected static function forDriver($dbDriver): DbDumper }; } + /** @param array> $dumpConfiguration */ protected static function processExtraDumpParameters(array $dumpConfiguration, DbDumper $dbDumper): DbDumper { collect($dumpConfiguration)->each(function ($configValue, $configName) use ($dbDumper) { @@ -107,7 +109,7 @@ protected static function processExtraDumpParameters(array $dumpConfiguration, D return $dbDumper; } - protected static function callMethodOnDumper(DbDumper $dbDumper, string $methodName, $methodValue): DbDumper + protected static function callMethodOnDumper(DbDumper $dbDumper, string $methodName, mixed $methodValue): DbDumper { if (! $methodValue) { $dbDumper->$methodName(); diff --git a/src/Tasks/Backup/FileSelection.php b/src/Tasks/Backup/FileSelection.php index a11f6b08..45364662 100644 --- a/src/Tasks/Backup/FileSelection.php +++ b/src/Tasks/Backup/FileSelection.php @@ -9,19 +9,23 @@ class FileSelection { + /** @var Collection */ protected Collection $includeFilesAndDirectories; + /** @var Collection */ protected Collection $excludeFilesAndDirectories; protected bool $shouldFollowLinks = false; protected bool $shouldIgnoreUnreadableDirs = false; - public static function create(array|string $includeFilesAndDirectories = []): self + /** @param array|string $includeFilesAndDirectories */ + public static function create(array|string $includeFilesAndDirectories = []): static { return new static($includeFilesAndDirectories); } + /** @param array|string $includeFilesAndDirectories */ public function __construct(array|string $includeFilesAndDirectories = []) { $this->includeFilesAndDirectories = collect($includeFilesAndDirectories); @@ -29,6 +33,7 @@ public function __construct(array|string $includeFilesAndDirectories = []) $this->excludeFilesAndDirectories = collect(); } + /** @param array|string $excludeFilesAndDirectories */ public function excludeFilesFrom(array|string $excludeFilesAndDirectories): self { $this->excludeFilesAndDirectories = $this->excludeFilesAndDirectories->merge($this->sanitize($excludeFilesAndDirectories)); @@ -50,6 +55,7 @@ public function shouldIgnoreUnreadableDirs(bool $ignoreUnreadableDirs): self return $this; } + /** @return Generator|array */ public function selectedFiles(): Generator|array { if ($this->includeFilesAndDirectories->isEmpty()) { @@ -87,18 +93,20 @@ public function selectedFiles(): Generator|array } } + /** @return array */ protected function includedFiles(): array { return $this ->includeFilesAndDirectories - ->filter(fn ($path) => is_file($path))->toArray(); + ->filter(fn (string $path) => is_file($path))->toArray(); } + /** @return array */ protected function includedDirectories(): array { return $this ->includeFilesAndDirectories - ->reject(fn ($path) => is_file($path))->toArray(); + ->reject(fn (string $path) => is_file($path))->toArray(); } protected function shouldExclude(string $path): bool @@ -121,15 +129,19 @@ protected function shouldExclude(string $path): bool return false; } + /** + * @param string|array $paths + */ protected function sanitize(string|array $paths): Collection { return collect($paths) - ->reject(fn ($path) => $path === '') - ->flatMap(fn ($path) => $this->getMatchingPaths($path)) - ->map(fn ($path) => realpath($path)) + ->reject(fn (string $path) => $path === '') + ->flatMap(fn (string $path) => $this->getMatchingPaths($path)) + ->map(fn (string $path) => realpath($path)) ->reject(fn ($path) => $path === false); } + /** @return array */ protected function getMatchingPaths(string $path): array { if ($this->canUseGlobBrace($path)) { diff --git a/src/Tasks/Backup/Manifest.php b/src/Tasks/Backup/Manifest.php index 330b23b9..ab0efa2d 100644 --- a/src/Tasks/Backup/Manifest.php +++ b/src/Tasks/Backup/Manifest.php @@ -23,6 +23,9 @@ public function path(): string return $this->manifestPath; } + /** + * @param Generator|string|array $filePaths + */ public function addFiles(array|string|Generator $filePaths): self { if (is_string($filePaths)) { diff --git a/src/Tasks/Backup/Zip.php b/src/Tasks/Backup/Zip.php index 1234649a..83b0010f 100644 --- a/src/Tasks/Backup/Zip.php +++ b/src/Tasks/Backup/Zip.php @@ -30,7 +30,7 @@ public static function createForManifest(Manifest $manifest, string $pathToZip): return $zip; } - protected static function determineNameOfFileInZip(string $pathToFile, string $pathToZip, string $relativePath) + protected static function determineNameOfFileInZip(string $pathToFile, string $pathToZip, string $relativePath): string { $fileDirectory = pathinfo($pathToFile, PATHINFO_DIRNAME).DIRECTORY_SEPARATOR; diff --git a/src/Tasks/Cleanup/CleanupJob.php b/src/Tasks/Cleanup/CleanupJob.php index c782e426..a8734eda 100644 --- a/src/Tasks/Cleanup/CleanupJob.php +++ b/src/Tasks/Cleanup/CleanupJob.php @@ -13,6 +13,7 @@ class CleanupJob { protected bool $sendNotifications = true; + /** @param Collection $backupDestinations */ public function __construct( protected Collection $backupDestinations, protected CleanupStrategy $strategy, @@ -49,7 +50,7 @@ public function run(): void }); } - protected function sendNotification($notification): void + protected function sendNotification(string|object $notification): void { if ($this->sendNotifications) { rescue( diff --git a/src/Tasks/Cleanup/CleanupStrategy.php b/src/Tasks/Cleanup/CleanupStrategy.php index 49bf3438..59d698f9 100644 --- a/src/Tasks/Cleanup/CleanupStrategy.php +++ b/src/Tasks/Cleanup/CleanupStrategy.php @@ -15,7 +15,7 @@ public function __construct( ) { } - abstract public function deleteOldBackups(BackupCollection $backups); + abstract public function deleteOldBackups(BackupCollection $backups): void; public function setBackupDestination(BackupDestination $backupDestination): self { diff --git a/src/Tasks/Cleanup/Strategies/DefaultStrategy.php b/src/Tasks/Cleanup/Strategies/DefaultStrategy.php index f73dca91..d4ba5c17 100644 --- a/src/Tasks/Cleanup/Strategies/DefaultStrategy.php +++ b/src/Tasks/Cleanup/Strategies/DefaultStrategy.php @@ -20,7 +20,7 @@ public function deleteOldBackups(BackupCollection $backups): void $dateRanges = $this->calculateDateRanges(); - /** @var Collection<(string|BackupCollection)> */ + /** @var Collection $backupsPerPeriod */ $backupsPerPeriod = $dateRanges->map(function (Period $period) use ($backups) { return $backups ->filter(fn (Backup $backup) => $backup->date()->between($period->startDate(), $period->endDate())); @@ -38,6 +38,7 @@ public function deleteOldBackups(BackupCollection $backups): void $this->removeOldBackupsUntilUsingLessThanMaximumStorage($backups); } + /** @return Collection */ protected function calculateDateRanges(): Collection { $config = $this->config->get('backup.cleanup.default_strategy'); @@ -70,15 +71,16 @@ protected function calculateDateRanges(): Collection return collect(compact('daily', 'weekly', 'monthly', 'yearly')); } - protected function groupByDateFormat(Collection $backups, string $dateFormat): Collection + protected function groupByDateFormat(BackupCollection $backups, string $dateFormat): BackupCollection { return $backups->groupBy(fn (Backup $backup) => $backup->date()->format($dateFormat)); } - protected function removeBackupsForAllPeriodsExceptOne(Collection $backupsPerPeriod) + /** @param Collection $backupsPerPeriod */ + protected function removeBackupsForAllPeriodsExceptOne(Collection $backupsPerPeriod): void { $backupsPerPeriod->each(function (Collection $groupedBackupsByDateProperty, string $periodName) { - $groupedBackupsByDateProperty->each(function (Collection $group) { + $groupedBackupsByDateProperty->each(function (BackupCollection $group) { $group->shift(); $group->each(fn (Backup $backup) => $backup->delete()); @@ -86,14 +88,14 @@ protected function removeBackupsForAllPeriodsExceptOne(Collection $backupsPerPer }); } - protected function removeBackupsOlderThan(Carbon $endDate, BackupCollection $backups) + protected function removeBackupsOlderThan(Carbon $endDate, BackupCollection $backups): void { $backups ->filter(fn (Backup $backup) => $backup->exists() && $backup->date()->lt($endDate)) ->each(fn (Backup $backup) => $backup->delete()); } - protected function removeOldBackupsUntilUsingLessThanMaximumStorage(BackupCollection $backups) + protected function removeOldBackupsUntilUsingLessThanMaximumStorage(BackupCollection $backups): void { if (! $this->shouldRemoveOldestBackup($backups)) { return; diff --git a/src/Tasks/Monitor/BackupDestinationStatus.php b/src/Tasks/Monitor/BackupDestinationStatus.php index 5908ef7d..35387e6f 100644 --- a/src/Tasks/Monitor/BackupDestinationStatus.php +++ b/src/Tasks/Monitor/BackupDestinationStatus.php @@ -11,6 +11,7 @@ class BackupDestinationStatus { protected ?HealthCheckFailure $healthCheckFailure = null; + /** @param array $healthChecks */ public function __construct( protected BackupDestination $backupDestination, protected array $healthChecks = [] @@ -33,6 +34,7 @@ public function check(HealthCheck $check): bool|HealthCheckFailure return true; } + /** @return Collection */ public function getHealthChecks(): Collection { return collect($this->healthChecks)->prepend(new IsReachable()); diff --git a/src/Tasks/Monitor/BackupDestinationStatusFactory.php b/src/Tasks/Monitor/BackupDestinationStatusFactory.php index 81036302..eb2ad233 100644 --- a/src/Tasks/Monitor/BackupDestinationStatusFactory.php +++ b/src/Tasks/Monitor/BackupDestinationStatusFactory.php @@ -8,6 +8,11 @@ class BackupDestinationStatusFactory { + + /** + * @param array{name: string, disks: array, health_checks: array>} $monitorConfiguration + * @return Collection + */ public static function createForMonitorConfig(array $monitorConfiguration): Collection { return collect($monitorConfiguration) @@ -16,6 +21,10 @@ public static function createForMonitorConfig(array $monitorConfiguration): Coll $backupDestinationStatus->backupDestination()->diskName()); } + /** + * @param array{name: string, disks: array, health_checks: array>} $monitorConfig + * @return Collection + */ public static function createForSingleMonitor(array $monitorConfig): Collection { return collect($monitorConfig['disks']) @@ -26,9 +35,22 @@ public static function createForSingleMonitor(array $monitorConfig): Collection }); } - protected static function buildHealthChecks($monitorConfig): array + /** + * @param array{name: string, disks: array, health_checks: array>} $monitorConfig + * @return array + */ + protected static function buildHealthChecks(array $monitorConfig): array { - return collect(Arr::get($monitorConfig, 'health_checks')) + ray(collect($monitorConfig['health_checks']) + ->map(function ($options, $class) { + if (is_int($class)) { + $class = $options; + $options = []; + } + + return static::buildHealthCheck($class, $options); + })->toArray()); + return collect($monitorConfig['health_checks']) ->map(function ($options, $class) { if (is_int($class)) { $class = $options; @@ -39,6 +61,7 @@ protected static function buildHealthChecks($monitorConfig): array })->toArray(); } + /** @param string|array $options */ protected static function buildHealthCheck(string $class, string|array $options): HealthCheck { if (! is_array($options)) { diff --git a/src/Tasks/Monitor/HealthCheck.php b/src/Tasks/Monitor/HealthCheck.php index 6d04f141..499c12e5 100644 --- a/src/Tasks/Monitor/HealthCheck.php +++ b/src/Tasks/Monitor/HealthCheck.php @@ -8,7 +8,7 @@ abstract class HealthCheck { - abstract public function checkHealth(BackupDestination $backupDestination); + abstract public function checkHealth(BackupDestination $backupDestination): void; public function name(): string { diff --git a/src/Traits/Retryable.php b/src/Traits/Retryable.php index 69a973c2..bae1cf1a 100644 --- a/src/Traits/Retryable.php +++ b/src/Traits/Retryable.php @@ -10,7 +10,7 @@ trait Retryable protected int $currentTry = 1; - protected function shouldRetry() + protected function shouldRetry(): bool { if ($this->tries <= 1) { return false; @@ -19,17 +19,17 @@ protected function shouldRetry() return $this->currentTry < $this->tries; } - protected function hasRetryDelay(string $type) + protected function hasRetryDelay(string $type): bool { return ! empty($this->getRetryDelay($type)); } - protected function sleepFor(int $seconds = 0) + protected function sleepFor(int $seconds = 0): void { Sleep::for($seconds)->seconds(); } - protected function setTries(string $type) + protected function setTries(string $type): void { if ($this->option('tries')) { $this->tries = (int) $this->option('tries'); @@ -40,7 +40,7 @@ protected function setTries(string $type) $this->tries = (int) config('backup.'.$type.'.tries', 1); } - protected function getRetryDelay(string $type) + protected function getRetryDelay(string $type): int { return (int) config('backup.'.$type.'.retry_delay', 0); } diff --git a/tests/TestSupport/FakeFailingHealthCheck.php b/tests/TestSupport/FakeFailingHealthCheck.php index 7f96a5f6..d0be35a4 100644 --- a/tests/TestSupport/FakeFailingHealthCheck.php +++ b/tests/TestSupport/FakeFailingHealthCheck.php @@ -10,7 +10,7 @@ class FakeFailingHealthCheck extends HealthCheck { public static $reason; - public function checkHealth(BackupDestination $backupDestination) + public function checkHealth(BackupDestination $backupDestination): void { throw (static::$reason ?: new Exception('dummy exception message')); }