diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 63a8f070..2e52031d 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -17,7 +17,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - php: [8.3, 8.2, 8.1] + php: [8.3, 8.2] laravel: [11.*, 10.*] stability: [prefer-lowest, prefer-stable] carbon: [^2.63] @@ -26,9 +26,6 @@ jobs: testbench: 8.* - laravel: 11.* testbench: 9.* - exclude: - - laravel: 11.* - php: 8.1 name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} diff --git a/.gitignore b/.gitignore index f3ae3118..bf66b2e0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ composer.lock vendor .phpunit.result.cache .php-cs-fixer.cache +.phpunit.cache diff --git a/composer.json b/composer.json index d41ff2e0..11d9c522 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ } ], "require": { - "php": "^8.1", + "php": "^8.2", "ext-zip": "^1.14.0", "illuminate/console": "^10.10.0|^11.0", "illuminate/contracts": "^10.10.0|^11.0", diff --git a/docs/sending-notifications/customizing-the-notifiable.md b/docs/sending-notifications/customizing-the-notifiable.md index c3b21a82..c3dc1859 100644 --- a/docs/sending-notifications/customizing-the-notifiable.md +++ b/docs/sending-notifications/customizing-the-notifiable.md @@ -20,7 +20,7 @@ class BackupNotifiable extends Notifiable { public function routeNotificationForAnotherNotificationChannel() { - return config('backup.notifications.another_notification_channel.property'); + return $this->config()->notifications->another_notification_channel->property; } } diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index c56c638a..80e7aa86 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -10,16 +10,6 @@ parameters: 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 @@ -54,3 +44,8 @@ parameters: 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 + + - + message: "#^Parameter \\#1 \\$callback of method Illuminate\\\\Support\\\\Collection\\<\\(int\\|string\\),Spatie\\\\Backup\\\\Config\\\\MonitoredBackupConfig\\>\\:\\:flatMap\\(\\) expects callable\\(Spatie\\\\Backup\\\\Config\\\\MonitoredBackupConfig, int\\|string\\)\\: \\(array\\\\|Illuminate\\\\Support\\\\Collection\\\\), Closure\\(array\\)\\: Illuminate\\\\Support\\\\Collection\\ given\\.$#" + count: 1 + path: src/Tasks/Monitor/BackupDestinationStatusFactory.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 685a823f..c5770235 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -9,6 +9,7 @@ parameters: tmpDir: build/phpstan checkOctaneCompatibility: true checkModelProperties: true + treatPhpDocTypesAsCertain: false ignoreErrors: - '#Unsafe usage of new static#' diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 92ed9fe9..6f21f52f 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,10 +1,15 @@ - - - - src/ - - + tests @@ -13,4 +18,9 @@ + + + src/ + + diff --git a/rector.php b/rector.php index a81f8384..836677e8 100644 --- a/rector.php +++ b/rector.php @@ -15,6 +15,7 @@ use Rector\Php74\Rector\Closure\ClosureToArrowFunctionRector; use Rector\TypeDeclaration\Rector\ArrowFunction\AddArrowFunctionReturnTypeRector; use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector; +use Rector\TypeDeclaration\Rector\Closure\AddClosureVoidReturnTypeWhereNoReturnRector; return RectorConfig::configure() ->withPaths(['config', 'resources', 'src']) @@ -33,4 +34,5 @@ PostIncDecToPreIncDecRector::class, NullableCompareToNullRector::class, AddArrowFunctionReturnTypeRector::class, + AddClosureVoidReturnTypeWhereNoReturnRector::class, ]); diff --git a/src/BackupDestination/BackupCollection.php b/src/BackupDestination/BackupCollection.php index dc998fdf..b3564010 100644 --- a/src/BackupDestination/BackupCollection.php +++ b/src/BackupDestination/BackupCollection.php @@ -16,7 +16,7 @@ public static function createFromFiles(?FileSystem $disk, array $files): self { return (new static($files)) ->filter(fn (string $path) => (new File())->isZipFile($disk, $path)) - ->map(fn (string $path) => new Backup($disk, $path)) + ->map(fn (string $path): \Spatie\Backup\BackupDestination\Backup => new Backup($disk, $path)) ->sortByDesc(fn (Backup $backup) => $backup->date()->timestamp) ->values(); } diff --git a/src/BackupDestination/BackupDestinationFactory.php b/src/BackupDestination/BackupDestinationFactory.php index 8ba0e95b..af48085b 100644 --- a/src/BackupDestination/BackupDestinationFactory.php +++ b/src/BackupDestination/BackupDestinationFactory.php @@ -3,16 +3,16 @@ namespace Spatie\Backup\BackupDestination; use Illuminate\Support\Collection; +use Spatie\Backup\Config\Config; class BackupDestinationFactory { /** - * @param array $config * @return Collection */ - public static function createFromArray(array $config): Collection + public static function createFromArray(Config $config): Collection { - return collect($config['destination']['disks']) - ->map(fn ($filesystemName) => BackupDestination::create($filesystemName, $config['name'])); + return collect($config->backup->destination->disks) + ->map(fn (string $filesystemName) => BackupDestination::create($filesystemName, $config->backup->name)); } } diff --git a/src/BackupServiceProvider.php b/src/BackupServiceProvider.php index ecd087bb..92e10d75 100644 --- a/src/BackupServiceProvider.php +++ b/src/BackupServiceProvider.php @@ -9,6 +9,7 @@ use Spatie\Backup\Commands\CleanupCommand; use Spatie\Backup\Commands\ListCommand; use Spatie\Backup\Commands\MonitorCommand; +use Spatie\Backup\Config\Config; use Spatie\Backup\Events\BackupZipWasCreated; use Spatie\Backup\Helpers\ConsoleOutput; use Spatie\Backup\Listeners\EncryptBackupArchive; @@ -50,12 +51,16 @@ public function packageRegistered(): void $this->app->bind(CleanupStrategy::class, config('backup.cleanup.strategy')); $this->registerDiscordChannel(); + + $this->app->scoped(Config::class, function (): \Spatie\Backup\Config\Config { + return Config::fromArray(config('backup')); + }); } protected function registerDiscordChannel(): void { Notification::resolved(function (ChannelManager $service) { - $service->extend('discord', function ($app) { + $service->extend('discord', function ($app): \Spatie\Backup\Notifications\Channels\Discord\DiscordChannel { return new DiscordChannel(); }); }); diff --git a/src/Commands/BackupCommand.php b/src/Commands/BackupCommand.php index 07dfdaa7..3ddeb225 100644 --- a/src/Commands/BackupCommand.php +++ b/src/Commands/BackupCommand.php @@ -4,6 +4,7 @@ use Exception; use Illuminate\Contracts\Console\Isolatable; +use Spatie\Backup\Config\Config; use Spatie\Backup\Events\BackupHasFailed; use Spatie\Backup\Exceptions\BackupFailed; use Spatie\Backup\Exceptions\InvalidCommand; @@ -18,6 +19,11 @@ class BackupCommand extends BaseCommand implements Isolatable protected $description = 'Run the backup.'; + public function __construct(protected Config $config) + { + parent::__construct(); + } + public function handle(): int { consoleOutput()->comment($this->currentTry > 1 ? sprintf('Attempt n°%d...', $this->currentTry) : 'Starting backup...'); @@ -31,7 +37,7 @@ public function handle(): int try { $this->guardAgainstInvalidOptions(); - $backupJob = BackupJobFactory::createFromArray(config('backup')); + $backupJob = BackupJobFactory::createFromConfig($this->config); if ($this->option('only-db')) { $backupJob->dontBackupFilesystem(); diff --git a/src/Commands/CleanupCommand.php b/src/Commands/CleanupCommand.php index 28551e3f..be4b5332 100644 --- a/src/Commands/CleanupCommand.php +++ b/src/Commands/CleanupCommand.php @@ -5,6 +5,7 @@ use Exception; use Illuminate\Contracts\Console\Isolatable; use Spatie\Backup\BackupDestination\BackupDestinationFactory; +use Spatie\Backup\Config\Config; use Spatie\Backup\Events\CleanupHasFailed; use Spatie\Backup\Tasks\Cleanup\CleanupJob; use Spatie\Backup\Tasks\Cleanup\CleanupStrategy; @@ -20,8 +21,10 @@ class CleanupCommand extends BaseCommand implements Isolatable /** @var string */ protected $description = 'Remove all backups older than specified number of days in config.'; - public function __construct(protected CleanupStrategy $strategy) - { + public function __construct( + protected CleanupStrategy $strategy, + protected Config $config, + ) { parent::__construct(); } @@ -34,9 +37,7 @@ public function handle(): int $this->setTries('cleanup'); try { - $config = config('backup'); - - $backupDestinations = BackupDestinationFactory::createFromArray($config['backup']); + $backupDestinations = BackupDestinationFactory::createFromArray($this->config); $cleanupJob = new CleanupJob($backupDestinations, $this->strategy, $disableNotifications); diff --git a/src/Commands/ListCommand.php b/src/Commands/ListCommand.php index 2c76faa1..7e226eeb 100644 --- a/src/Commands/ListCommand.php +++ b/src/Commands/ListCommand.php @@ -4,6 +4,7 @@ use Illuminate\Support\Collection; use Spatie\Backup\BackupDestination\Backup; +use Spatie\Backup\Config\Config; use Spatie\Backup\Helpers\Format; use Spatie\Backup\Helpers\RightAlignedTableStyle; use Spatie\Backup\Tasks\Monitor\BackupDestinationStatus; @@ -17,13 +18,14 @@ class ListCommand extends BaseCommand /** @var string */ protected $description = 'Display a list of all backups.'; - public function handle(): int + public function __construct(protected Config $config) { - if (config()->has('backup.monitorBackups')) { - $this->warn('Warning! Your config file still uses the old monitorBackups key. Update it to monitor_backups.'); - } + parent::__construct(); + } - $statuses = BackupDestinationStatusFactory::createForMonitorConfig(config('backup.monitor_backups')); + public function handle(): int + { + $statuses = BackupDestinationStatusFactory::createForMonitorConfig($this->config->monitoredBackups); $this->displayOverview($statuses)->displayFailures($statuses); @@ -37,7 +39,7 @@ protected function displayOverview(Collection $backupDestinationStatuses): stati { $headers = ['Name', 'Disk', 'Reachable', 'Healthy', '# of backups', 'Newest backup', 'Used storage']; - $rows = $backupDestinationStatuses->map(function (BackupDestinationStatus $backupDestinationStatus) { + $rows = $backupDestinationStatuses->map(function (BackupDestinationStatus $backupDestinationStatus): array { return $this->convertToRow($backupDestinationStatus); }); @@ -81,10 +83,10 @@ public function convertToRow(BackupDestinationStatus $backupDestinationStatus): protected function displayFailures(Collection $backupDestinationStatuses): static { $failed = $backupDestinationStatuses - ->filter(function (BackupDestinationStatus $backupDestinationStatus) { + ->filter(function (BackupDestinationStatus $backupDestinationStatus): bool { return $backupDestinationStatus->getHealthCheckFailure() !== null; }) - ->map(function (BackupDestinationStatus $backupDestinationStatus) { + ->map(function (BackupDestinationStatus $backupDestinationStatus): array { return [ $backupDestinationStatus->backupDestination()->backupName(), $backupDestinationStatus->backupDestination()->diskName(), diff --git a/src/Commands/MonitorCommand.php b/src/Commands/MonitorCommand.php index 652cda42..d0adb34a 100644 --- a/src/Commands/MonitorCommand.php +++ b/src/Commands/MonitorCommand.php @@ -3,6 +3,7 @@ namespace Spatie\Backup\Commands; use Illuminate\Contracts\Console\Isolatable; +use Spatie\Backup\Config\Config; use Spatie\Backup\Events\HealthyBackupWasFound; use Spatie\Backup\Events\UnhealthyBackupWasFound; use Spatie\Backup\Tasks\Monitor\BackupDestinationStatusFactory; @@ -15,15 +16,16 @@ class MonitorCommand extends BaseCommand implements Isolatable /** @var string */ protected $description = 'Monitor the health of all backups.'; - public function handle(): int + public function __construct(protected Config $config) { - if (config()->has('backup.monitorBackups')) { - $this->warn('Warning! Your config file still uses the old monitorBackups key. Update it to monitor_backups.'); - } + parent::__construct(); + } + public function handle(): int + { $hasError = false; - $statuses = BackupDestinationStatusFactory::createForMonitorConfig(config('backup.monitor_backups')); + $statuses = BackupDestinationStatusFactory::createForMonitorConfig($this->config->monitoredBackups); foreach ($statuses as $backupDestinationStatus) { $backupName = $backupDestinationStatus->backupDestination()->backupName(); diff --git a/src/Config/BackupConfig.php b/src/Config/BackupConfig.php new file mode 100644 index 00000000..1de5347a --- /dev/null +++ b/src/Config/BackupConfig.php @@ -0,0 +1,51 @@ +tries < 1) { + throw InvalidConfig::integerMustBePositive('tries'); + } + } + + /** @param array $data */ + public static function fromArray(array $data): self + { + $monitoredBackups = $data['monitored_backups'] ?? $data['monitorBackups'] ?? null; + + return new self( + name: $data['name'], + source: SourceConfig::fromArray($data['source']), + databaseDumpCompressor: $data['database_dump_compressor'], + databaseDumpFileTimestampFormat: $data['database_dump_file_timestamp_format'], + databaseDumpFilenameBase: $data['database_dump_filename_base'], + databaseDumpFileExtension: $data['database_dump_file_extension'], + destination: DestinationConfig::fromArray($data['destination']), + temporaryDirectory: $data['temporary_directory'] ?? null, + password: $data['password'], + encryption: $data['encryption'], + tries: $data['tries'], + retryDelay: $data['retry_delay'], + monitoredBackups: $monitoredBackups ? MonitoredBackupsConfig::fromArray($monitoredBackups) : null, + ); + } +} diff --git a/src/Config/CleanupConfig.php b/src/Config/CleanupConfig.php new file mode 100644 index 00000000..31a072e2 --- /dev/null +++ b/src/Config/CleanupConfig.php @@ -0,0 +1,39 @@ + $strategy + */ + protected function __construct( + public string $strategy, + public StrategyConfig $defaultStrategy, + public int $tries, + public int $retryDelay, + ) { + if ($this->tries < 1) { + throw InvalidConfig::integerMustBePositive('cleanup tries'); + } + + if (! class_exists($this->strategy)) { + throw InvalidConfig::invalidStrategy($this->strategy); + } + } + + /** @param array $data */ + public static function fromArray(array $data): self + { + return new self( + strategy: $data['strategy'], + defaultStrategy: StrategyConfig::fromArray($data['default_strategy']), + tries: $data['tries'], + retryDelay: $data['retry_delay'], + ); + } +} diff --git a/src/Config/Config.php b/src/Config/Config.php new file mode 100644 index 00000000..e99baa30 --- /dev/null +++ b/src/Config/Config.php @@ -0,0 +1,35 @@ +scoped(Config::class, function (): \Spatie\Backup\Config\Config { + return self::fromArray(config('backup')); + }); + } + + /** @param array $data */ + public static function fromArray(array $data): self + { + return new self( + backup: BackupConfig::fromArray($data['backup']), + notifications: NotificationsConfig::fromArray($data['notifications']), + monitoredBackups: MonitoredBackupsConfig::fromArray($data['monitor_backups']), + cleanup: CleanupConfig::fromArray($data['cleanup']), + ); + } +} diff --git a/src/Config/DestinationConfig.php b/src/Config/DestinationConfig.php new file mode 100644 index 00000000..9894f727 --- /dev/null +++ b/src/Config/DestinationConfig.php @@ -0,0 +1,39 @@ + $compressionLevel + * @param array $disks + */ + protected function __construct( + public int $compressionMethod, + public int $compressionLevel, + public string $filenamePrefix, + public array $disks, + ) { + if ($compressionLevel > 9) { + throw InvalidConfig::integerMustBeBetween('compression_level', 0, 9); + } + + if ($compressionLevel < 0) { + throw InvalidConfig::integerMustBeBetween('compression_level', 0, 9); + } + } + + /** @param array $data */ + public static function fromArray(array $data): self + { + return new self( + compressionMethod: $data['compression_method'], + compressionLevel: $data['compression_level'], + filenamePrefix: $data['filename_prefix'], + disks: $data['disks'], + ); + } +} diff --git a/src/Config/MonitoredBackupConfig.php b/src/Config/MonitoredBackupConfig.php new file mode 100644 index 00000000..c3668a74 --- /dev/null +++ b/src/Config/MonitoredBackupConfig.php @@ -0,0 +1,30 @@ + $disks + * @param array, int> $healthChecks + */ + protected function __construct( + public string $name, + public array $disks, + public array $healthChecks, + ) { + } + + /** @param array $data */ + public static function fromArray(array $data): self + { + return new self( + name: $data['name'], + disks: $data['disks'], + healthChecks: $data['health_checks'], + ); + } +} diff --git a/src/Config/MonitoredBackupsConfig.php b/src/Config/MonitoredBackupsConfig.php new file mode 100644 index 00000000..7d2ae1fd --- /dev/null +++ b/src/Config/MonitoredBackupsConfig.php @@ -0,0 +1,26 @@ + $monitorBackups + */ + protected function __construct( + public array $monitorBackups, + ) { + } + + /** @param array $data */ + public static function fromArray(array $data): self + { + return new self( + monitorBackups: collect($data) + ->map(fn (array $monitoredBackup) => MonitoredBackupConfig::fromArray($monitoredBackup)) + ->toArray(), + ); + } +} diff --git a/src/Config/NotificationDiscordConfig.php b/src/Config/NotificationDiscordConfig.php new file mode 100644 index 00000000..46ce63f9 --- /dev/null +++ b/src/Config/NotificationDiscordConfig.php @@ -0,0 +1,25 @@ + $data */ + public static function fromArray(array $data): self + { + return new self( + webhookUrl: $data['webhook_url'], + username: $data['username'], + avatar_url: $data['avatar_url'], + ); + } +} diff --git a/src/Config/NotificationMailConfig.php b/src/Config/NotificationMailConfig.php new file mode 100644 index 00000000..414c575a --- /dev/null +++ b/src/Config/NotificationMailConfig.php @@ -0,0 +1,32 @@ + $data + * + * @throws InvalidConfig + */ + public static function fromArray(array $data): self + { + if (! filter_var($data['to'], FILTER_VALIDATE_EMAIL)) { + throw InvalidConfig::invalidEmail($data['to']); + } + + return new self( + to: $data['to'], + from: NotificationMailSenderConfig::fromArray($data['from'] ?? []), + ); + } +} diff --git a/src/Config/NotificationMailSenderConfig.php b/src/Config/NotificationMailSenderConfig.php new file mode 100644 index 00000000..3013d9b7 --- /dev/null +++ b/src/Config/NotificationMailSenderConfig.php @@ -0,0 +1,34 @@ + $data */ + public static function fromArray(array $data): self + { + $address = $data['from']['address'] ?? config('mail.from.address'); + + if ($address === null) { + throw InvalidConfig::missingSender(); + } + + if ($address && ! filter_var($address, FILTER_VALIDATE_EMAIL)) { + throw InvalidConfig::invalidEmail($address); + } + + return new self( + address: $address, + name: $data['from']['name'] ?? config('mail.from.name'), + ); + } +} diff --git a/src/Config/NotificationSlackConfig.php b/src/Config/NotificationSlackConfig.php new file mode 100644 index 00000000..ae02f391 --- /dev/null +++ b/src/Config/NotificationSlackConfig.php @@ -0,0 +1,27 @@ + $data */ + public static function fromArray(array $data): self + { + return new self( + webhookUrl: $data['webhook_url'], + channel: $data['channel'], + username: $data['username'], + icon: $data['icon'], + ); + } +} diff --git a/src/Config/NotificationsConfig.php b/src/Config/NotificationsConfig.php new file mode 100644 index 00000000..b2045e99 --- /dev/null +++ b/src/Config/NotificationsConfig.php @@ -0,0 +1,39 @@ +, array> $notifications + * @param class-string $notifiable + */ + protected function __construct( + public array $notifications, + public string $notifiable, + public NotificationMailConfig $mail, + public NotificationSlackConfig $slack, + public NotificationDiscordConfig $discord, + ) { + if (! class_exists($this->notifiable)) { + throw InvalidConfig::invalidStrategy($this->notifiable); + } + } + + /** @param array $data */ + public static function fromArray(array $data): self + { + return new self( + notifications: $data['notifications'], + notifiable: $data['notifiable'], + mail: NotificationMailConfig::fromArray($data['mail']), + slack: NotificationSlackConfig::fromArray($data['slack']), + discord: NotificationDiscordConfig::fromArray($data['discord']), + ); + } +} diff --git a/src/Config/SourceConfig.php b/src/Config/SourceConfig.php new file mode 100644 index 00000000..2bc9ba6d --- /dev/null +++ b/src/Config/SourceConfig.php @@ -0,0 +1,26 @@ + $databases + */ + protected function __construct( + public SourceFilesConfig $files, + public array $databases, + ) { + } + + /** @param array $data */ + public static function fromArray(array $data): self + { + return new self( + files: SourceFilesConfig::fromArray($data['files']), + databases: $data['databases'], + ); + } +} diff --git a/src/Config/SourceFilesConfig.php b/src/Config/SourceFilesConfig.php new file mode 100644 index 00000000..1fa2b5cc --- /dev/null +++ b/src/Config/SourceFilesConfig.php @@ -0,0 +1,33 @@ + $include + * @param array $exclude + */ + protected function __construct( + public array $include, + public array $exclude, + public bool $followLinks, + public bool $ignoreUnreadableDirectories, + public ?string $relativePath, + ) { + } + + /** @param array $data */ + public static function fromArray(array $data): self + { + return new self( + include: $data['include'], + exclude: $data['exclude'], + followLinks: $data['follow_links'] ?? false, + ignoreUnreadableDirectories: $data['ignore_unreadable_directories'] ?? false, + relativePath: $data['relative_path'], + ); + } +} diff --git a/src/Config/StrategyConfig.php b/src/Config/StrategyConfig.php new file mode 100644 index 00000000..2c25e6d0 --- /dev/null +++ b/src/Config/StrategyConfig.php @@ -0,0 +1,31 @@ + $data */ + public static function fromArray(array $data): self + { + return new self( + keepAllBackupsForDays: $data['keep_all_backups_for_days'], + keepDailyBackupsForDays: $data['keep_daily_backups_for_days'], + keepWeeklyBackupsForWeeks: $data['keep_weekly_backups_for_weeks'], + keepMonthlyBackupsForMonths: $data['keep_monthly_backups_for_months'], + keepYearlyBackupsForYears: $data['keep_yearly_backups_for_years'], + deleteOldestBackupsWhenUsingMoreMegabytesThan: $data['delete_oldest_backups_when_using_more_megabytes_than'], + ); + } +} diff --git a/src/Exceptions/InvalidConfig.php b/src/Exceptions/InvalidConfig.php new file mode 100644 index 00000000..53f8c2f8 --- /dev/null +++ b/src/Exceptions/InvalidConfig.php @@ -0,0 +1,33 @@ + */ public function via(): array { - $notificationChannels = config('backup.notifications.notifications.'.static::class); + $notificationChannels = $this->config()->notifications->notifications[static::class]; return array_filter($notificationChannels); } + public function config(): Config + { + return app(Config::class); + } + public function applicationName(): string { $name = config('app.name') ?? config('app.url') ?? 'Laravel'; diff --git a/src/Notifications/Notifiable.php b/src/Notifications/Notifiable.php index 419ce283..1321c168 100644 --- a/src/Notifications/Notifiable.php +++ b/src/Notifications/Notifiable.php @@ -3,6 +3,7 @@ namespace Spatie\Backup\Notifications; use Illuminate\Notifications\Notifiable as NotifiableTrait; +use Spatie\Backup\Config\Config; class Notifiable { @@ -11,21 +12,26 @@ class Notifiable /** @return string|array{int, string} */ public function routeNotificationForMail(): string|array { - return config('backup.notifications.mail.to'); + return $this->config()->notifications->mail->to; } public function routeNotificationForSlack(): string { - return config('backup.notifications.slack.webhook_url'); + return $this->config()->notifications->slack->webhookUrl; } public function routeNotificationForDiscord(): string { - return config('backup.notifications.discord.webhook_url'); + return $this->config()->notifications->discord->webhookUrl; } public function getKey(): int { return 1; } + + protected function config(): Config + { + return app(Config::class); + } } diff --git a/src/Notifications/Notifications/BackupHasFailedNotification.php b/src/Notifications/Notifications/BackupHasFailedNotification.php index bf4cea52..5e59c50d 100644 --- a/src/Notifications/Notifications/BackupHasFailedNotification.php +++ b/src/Notifications/Notifications/BackupHasFailedNotification.php @@ -20,7 +20,7 @@ public function toMail(): MailMessage { $mailMessage = (new MailMessage()) ->error() - ->from(config('backup.notifications.mail.from.address', config('mail.from.address')), config('backup.notifications.mail.from.name', config('mail.from.name'))) + ->from($this->config()->notifications->mail->from->address, $this->config()->notifications->mail->from->name) ->subject(trans('backup::notifications.backup_failed_subject', ['application_name' => $this->applicationName()])) ->line(trans('backup::notifications.backup_failed_body', ['application_name' => $this->applicationName()])) ->line(trans('backup::notifications.exception_message', ['message' => $this->event->exception->getMessage()])) @@ -35,8 +35,8 @@ public function toSlack(): SlackMessage { return (new SlackMessage()) ->error() - ->from(config('backup.notifications.slack.username'), config('backup.notifications.slack.icon')) - ->to(config('backup.notifications.slack.channel')) + ->from($this->config()->notifications->slack->username, $this->config()->notifications->slack->icon) + ->to($this->config()->notifications->slack->channel) ->content(trans('backup::notifications.backup_failed_subject', ['application_name' => $this->applicationName()])) ->attachment(function (SlackAttachment $attachment) { $attachment @@ -57,7 +57,7 @@ public function toDiscord(): DiscordMessage { return (new DiscordMessage()) ->error() - ->from(config('backup.notifications.discord.username'), config('backup.notifications.discord.avatar_url')) + ->from($this->config()->notifications->discord->username, $this->config()->notifications->discord->avatar_url) ->title(trans('backup::notifications.backup_failed_subject', ['application_name' => $this->applicationName()])) ->fields([ trans('backup::notifications.exception_message_title') => $this->event->exception->getMessage(), diff --git a/src/Notifications/Notifications/BackupWasSuccessfulNotification.php b/src/Notifications/Notifications/BackupWasSuccessfulNotification.php index 2b21b335..3ff78c58 100644 --- a/src/Notifications/Notifications/BackupWasSuccessfulNotification.php +++ b/src/Notifications/Notifications/BackupWasSuccessfulNotification.php @@ -19,7 +19,7 @@ public function __construct( public function toMail(): MailMessage { $mailMessage = (new MailMessage()) - ->from(config('backup.notifications.mail.from.address', config('mail.from.address')), config('backup.notifications.mail.from.name', config('mail.from.name'))) + ->from($this->config()->notifications->mail->from->address, $this->config()->notifications->mail->from->name) ->subject(trans('backup::notifications.backup_successful_subject', ['application_name' => $this->applicationName()])) ->line(trans('backup::notifications.backup_successful_body', ['application_name' => $this->applicationName(), 'disk_name' => $this->diskName()])); @@ -34,8 +34,8 @@ public function toSlack(): SlackMessage { return (new SlackMessage()) ->success() - ->from(config('backup.notifications.slack.username'), config('backup.notifications.slack.icon')) - ->to(config('backup.notifications.slack.channel')) + ->from($this->config()->notifications->slack->username, $this->config()->notifications->slack->icon) + ->to($this->config()->notifications->slack->channel) ->content(trans('backup::notifications.backup_successful_subject_title')) ->attachment(function (SlackAttachment $attachment) { $attachment->fields($this->backupDestinationProperties()->toArray()); @@ -46,7 +46,7 @@ public function toDiscord(): DiscordMessage { return (new DiscordMessage()) ->success() - ->from(config('backup.notifications.discord.username'), config('backup.notifications.discord.avatar_url')) + ->from($this->config()->notifications->discord->username, $this->config()->notifications->discord->avatar_url) ->title(trans('backup::notifications.backup_successful_subject_title')) ->fields($this->backupDestinationProperties()->toArray()); } diff --git a/src/Notifications/Notifications/CleanupHasFailedNotification.php b/src/Notifications/Notifications/CleanupHasFailedNotification.php index 0a76876b..699c0915 100644 --- a/src/Notifications/Notifications/CleanupHasFailedNotification.php +++ b/src/Notifications/Notifications/CleanupHasFailedNotification.php @@ -20,7 +20,7 @@ public function toMail(): MailMessage { $mailMessage = (new MailMessage()) ->error() - ->from(config('backup.notifications.mail.from.address', config('mail.from.address')), config('backup.notifications.mail.from.name', config('mail.from.name'))) + ->from($this->config()->notifications->mail->from->address, $this->config()->notifications->mail->from->name) ->subject(trans('backup::notifications.cleanup_failed_subject', ['application_name' => $this->applicationName()])) ->line(trans('backup::notifications.cleanup_failed_body', ['application_name' => $this->applicationName()])) ->line(trans('backup::notifications.exception_message', ['message' => $this->event->exception->getMessage()])) @@ -37,8 +37,8 @@ public function toSlack(): SlackMessage { return (new SlackMessage()) ->error() - ->from(config('backup.notifications.slack.username'), config('backup.notifications.slack.icon')) - ->to(config('backup.notifications.slack.channel')) + ->from($this->config()->notifications->slack->username, $this->config()->notifications->slack->icon) + ->to($this->config()->notifications->slack->channel) ->content(trans('backup::notifications.cleanup_failed_subject', ['application_name' => $this->applicationName()])) ->attachment(function (SlackAttachment $attachment) { $attachment @@ -59,7 +59,7 @@ public function toDiscord(): DiscordMessage { return (new DiscordMessage()) ->error() - ->from(config('backup.notifications.discord.username'), config('backup.notifications.discord.avatar_url')) + ->from($this->config()->notifications->discord->username, $this->config()->notifications->discord->avatar_url) ->title( trans('backup::notifications.cleanup_failed_subject', ['application_name' => $this->applicationName()]) )->fields([ diff --git a/src/Notifications/Notifications/CleanupWasSuccessfulNotification.php b/src/Notifications/Notifications/CleanupWasSuccessfulNotification.php index 8ab7da53..5e6925f1 100644 --- a/src/Notifications/Notifications/CleanupWasSuccessfulNotification.php +++ b/src/Notifications/Notifications/CleanupWasSuccessfulNotification.php @@ -19,7 +19,7 @@ public function __construct( public function toMail(): MailMessage { $mailMessage = (new MailMessage()) - ->from(config('backup.notifications.mail.from.address', config('mail.from.address')), config('backup.notifications.mail.from.name', config('mail.from.name'))) + ->from($this->config()->notifications->mail->from->address, $this->config()->notifications->mail->from->name) ->subject(trans('backup::notifications.cleanup_successful_subject', ['application_name' => $this->applicationName()])) ->line(trans('backup::notifications.cleanup_successful_body', ['application_name' => $this->applicationName(), 'disk_name' => $this->diskName()])); @@ -34,8 +34,8 @@ public function toSlack(): SlackMessage { return (new SlackMessage()) ->success() - ->from(config('backup.notifications.slack.username'), config('backup.notifications.slack.icon')) - ->to(config('backup.notifications.slack.channel')) + ->from($this->config()->notifications->slack->username, $this->config()->notifications->slack->icon) + ->to($this->config()->notifications->slack->channel) ->content(trans('backup::notifications.cleanup_successful_subject_title')) ->attachment(function (SlackAttachment $attachment) { $attachment->fields($this->backupDestinationProperties()->toArray()); @@ -46,7 +46,7 @@ public function toDiscord(): DiscordMessage { return (new DiscordMessage()) ->success() - ->from(config('backup.notifications.discord.username'), config('backup.notifications.discord.avatar_url')) + ->from($this->config()->notifications->discord->username, $this->config()->notifications->discord->avatar_url) ->title(trans('backup::notifications.cleanup_successful_subject_title')) ->fields($this->backupDestinationProperties()->toArray()); } diff --git a/src/Notifications/Notifications/HealthyBackupWasFoundNotification.php b/src/Notifications/Notifications/HealthyBackupWasFoundNotification.php index 44ed0d1b..424adfce 100644 --- a/src/Notifications/Notifications/HealthyBackupWasFoundNotification.php +++ b/src/Notifications/Notifications/HealthyBackupWasFoundNotification.php @@ -19,7 +19,7 @@ public function __construct( public function toMail(): MailMessage { $mailMessage = (new MailMessage()) - ->from(config('backup.notifications.mail.from.address', config('mail.from.address')), config('backup.notifications.mail.from.name', config('mail.from.name'))) + ->from($this->config()->notifications->mail->from->address, $this->config()->notifications->mail->from->name) ->subject(trans('backup::notifications.healthy_backup_found_subject', ['application_name' => $this->applicationName(), 'disk_name' => $this->diskName()])) ->line(trans('backup::notifications.healthy_backup_found_body', ['application_name' => $this->applicationName()])); @@ -34,8 +34,8 @@ public function toSlack(): SlackMessage { return (new SlackMessage()) ->success() - ->from(config('backup.notifications.slack.username'), config('backup.notifications.slack.icon')) - ->to(config('backup.notifications.slack.channel')) + ->from($this->config()->notifications->slack->username, $this->config()->notifications->slack->icon) + ->to($this->config()->notifications->slack->channel) ->content(trans('backup::notifications.healthy_backup_found_subject_title', ['application_name' => $this->applicationName()])) ->attachment(function (SlackAttachment $attachment) { $attachment->fields($this->backupDestinationProperties()->toArray()); @@ -46,7 +46,7 @@ public function toDiscord(): DiscordMessage { return (new DiscordMessage()) ->success() - ->from(config('backup.notifications.discord.username'), config('backup.notifications.discord.avatar_url')) + ->from($this->config()->notifications->discord->username, $this->config()->notifications->discord->avatar_url) ->title( trans('backup::notifications.healthy_backup_found_subject_title', [ 'application_name' => $this->applicationName(), diff --git a/src/Notifications/Notifications/UnhealthyBackupWasFoundNotification.php b/src/Notifications/Notifications/UnhealthyBackupWasFoundNotification.php index 8c7fab75..eacb3ff0 100644 --- a/src/Notifications/Notifications/UnhealthyBackupWasFoundNotification.php +++ b/src/Notifications/Notifications/UnhealthyBackupWasFoundNotification.php @@ -21,7 +21,7 @@ public function toMail(): MailMessage { $mailMessage = (new MailMessage()) ->error() - ->from(config('backup.notifications.mail.from.address', config('mail.from.address')), config('backup.notifications.mail.from.name', config('mail.from.name'))) + ->from($this->config()->notifications->mail->from->address, $this->config()->notifications->mail->from->name) ->subject(trans('backup::notifications.unhealthy_backup_found_subject', ['application_name' => $this->applicationName()])) ->line(trans('backup::notifications.unhealthy_backup_found_body', ['application_name' => $this->applicationName(), 'disk_name' => $this->diskName()])) ->line($this->problemDescription()); @@ -44,8 +44,8 @@ public function toSlack(): SlackMessage { $slackMessage = (new SlackMessage()) ->error() - ->from(config('backup.notifications.slack.username'), config('backup.notifications.slack.icon')) - ->to(config('backup.notifications.slack.channel')) + ->from($this->config()->notifications->slack->username, $this->config()->notifications->slack->icon) + ->to($this->config()->notifications->slack->channel) ->content(trans('backup::notifications.unhealthy_backup_found_subject_title', ['application_name' => $this->applicationName(), 'problem' => $this->problemDescription()])) ->attachment(function (SlackAttachment $attachment) { $attachment->fields($this->backupDestinationProperties()->toArray()); @@ -77,7 +77,7 @@ public function toDiscord(): DiscordMessage { $discordMessage = (new DiscordMessage()) ->error() - ->from(config('backup.notifications.discord.username'), config('backup.notifications.discord.avatar_url')) + ->from($this->config()->notifications->discord->username, $this->config()->notifications->discord->avatar_url) ->title( trans('backup::notifications.unhealthy_backup_found_subject_title', [ 'application_name' => $this->applicationName(), diff --git a/src/Support/Data.php b/src/Support/Data.php new file mode 100644 index 00000000..c8f474a1 --- /dev/null +++ b/src/Support/Data.php @@ -0,0 +1,30 @@ + */ +class Data implements Arrayable +{ + public function toArray(): array + { + $array = []; + $reflectionClass = new ReflectionClass($this); + + foreach ($reflectionClass->getProperties(ReflectionProperty::IS_PUBLIC) as $property) { + $name = $property->getName(); + $value = $this->$name; + + if ($value instanceof Arrayable) { + $array[$name] = $value->toArray(); + } else { + $array[$name] = $value; + } + } + + return $array; + } +} diff --git a/src/Tasks/Backup/BackupJob.php b/src/Tasks/Backup/BackupJob.php index 5453426c..ad3c0453 100644 --- a/src/Tasks/Backup/BackupJob.php +++ b/src/Tasks/Backup/BackupJob.php @@ -8,6 +8,7 @@ use Illuminate\Console\Command; use Illuminate\Support\Collection; use Spatie\Backup\BackupDestination\BackupDestination; +use Spatie\Backup\Config\Config; use Spatie\Backup\Events\BackupManifestWasCreated; use Spatie\Backup\Events\BackupWasSuccessful; use Spatie\Backup\Events\BackupZipWasCreated; @@ -41,7 +42,7 @@ class BackupJob protected bool $signals = true; - public function __construct() + public function __construct(protected Config $config) { $this ->dontBackupFilesystem() @@ -145,7 +146,7 @@ public function setBackupDestinations(Collection $backupDestinations): self /** @throws Exception */ public function run(): void { - $temporaryDirectoryPath = config('backup.backup.temporary_directory') ?? storage_path('app/backup-temp'); + $temporaryDirectoryPath = $this->config->backup->temporaryDirectory ?? storage_path('app/backup-temp'); $this->temporaryDirectory = (new TemporaryDirectory($temporaryDirectoryPath)) ->name('temp') @@ -229,7 +230,7 @@ protected function createZipContainingEveryFileInManifest(Manifest $manifest): s { consoleOutput()->info("Zipping {$manifest->count()} files and directories..."); - $pathToZip = $this->temporaryDirectory->path(config('backup.backup.destination.filename_prefix').$this->filename); + $pathToZip = $this->temporaryDirectory->path($this->config->backup->destination->filenamePrefix.$this->filename); $zip = Zip::createForManifest($manifest, $pathToZip); @@ -253,12 +254,12 @@ protected function createZipContainingEveryFileInManifest(Manifest $manifest): s protected function dumpDatabases(): array { return $this->dbDumpers - ->map(function (DbDumper $dbDumper, $key) { + ->map(function (DbDumper $dbDumper, string $key): string { consoleOutput()->info("Dumping database {$dbDumper->getDbName()}..."); $dbType = mb_strtolower(basename(str_replace('\\', '/', $dbDumper::class))); - if (config('backup.backup.database_dump_filename_base') === 'connection') { + if ($this->config->backup->databaseDumpFilenameBase === 'connection') { $dbName = $key; } elseif ($dbDumper instanceof Sqlite) { $dbName = $key.'-database'; @@ -267,18 +268,20 @@ protected function dumpDatabases(): array } $timeStamp = ''; - if ($timeStampFormat = config('backup.backup.database_dump_file_timestamp_format')) { + + if ($timeStampFormat = $this->config->backup->databaseDumpFileTimestampFormat) { $timeStamp = '-'.Carbon::now()->format($timeStampFormat); } $fileName = "{$dbType}-{$dbName}{$timeStamp}.{$this->getExtension($dbDumper)}"; + // @todo is this still relevant or undocumented? if (config('backup.backup.gzip_database_dump')) { $dbDumper->useCompressor(new GzipCompressor()); $fileName .= '.'.$dbDumper->getCompressorExtension(); } - if ($compressor = config('backup.backup.database_dump_compressor')) { + if ($compressor = $this->config->backup->databaseDumpCompressor) { $dbDumper->useCompressor(new $compressor()); $fileName .= '.'.$dbDumper->getCompressorExtension(); } @@ -333,7 +336,7 @@ protected function sendNotification(object|string $notification): void protected function getExtension(DbDumper $dbDumper): string { - if ($extension = config('backup.backup.database_dump_file_extension')) { + if ($extension = $this->config->backup->databaseDumpFileExtension) { return $extension; } diff --git a/src/Tasks/Backup/BackupJobFactory.php b/src/Tasks/Backup/BackupJobFactory.php index 64bfb7fc..a047f6e0 100644 --- a/src/Tasks/Backup/BackupJobFactory.php +++ b/src/Tasks/Backup/BackupJobFactory.php @@ -2,29 +2,28 @@ namespace Spatie\Backup\Tasks\Backup; -use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Spatie\Backup\BackupDestination\BackupDestinationFactory; +use Spatie\Backup\Config\Config; +use Spatie\Backup\Config\SourceFilesConfig; use Spatie\DbDumper\DbDumper; class BackupJobFactory { - /** @param array> $config */ - public static function createFromArray(array $config): BackupJob + public static function createFromConfig(Config $config): BackupJob { - return (new BackupJob()) - ->setFileSelection(static::createFileSelection($config['backup']['source']['files'])) - ->setDbDumpers(static::createDbDumpers($config['backup']['source']['databases'])) - ->setBackupDestinations(BackupDestinationFactory::createFromArray($config['backup'])); + return (new BackupJob($config)) + ->setFileSelection(static::createFileSelection($config->backup->source->files)) + ->setDbDumpers(static::createDbDumpers($config->backup->source->databases)) + ->setBackupDestinations(BackupDestinationFactory::createFromArray($config)); } - /** @param array $sourceFiles */ - protected static function createFileSelection(array $sourceFiles): FileSelection + protected static function createFileSelection(SourceFilesConfig $sourceFiles): FileSelection { - return FileSelection::create($sourceFiles['include']) - ->excludeFilesFrom($sourceFiles['exclude']) - ->shouldFollowLinks(isset($sourceFiles['follow_links']) && $sourceFiles['follow_links']) - ->shouldIgnoreUnreadableDirs(Arr::get($sourceFiles, 'ignore_unreadable_directories', false)); + return FileSelection::create($sourceFiles->include) + ->excludeFilesFrom($sourceFiles->exclude) + ->shouldFollowLinks($sourceFiles->followLinks) + ->shouldIgnoreUnreadableDirs($sourceFiles->ignoreUnreadableDirectories); } /** @@ -34,7 +33,7 @@ protected static function createFileSelection(array $sourceFiles): FileSelection protected static function createDbDumpers(array $dbConnectionNames): Collection { return collect($dbConnectionNames)->mapWithKeys( - fn (string $dbConnectionName) => [$dbConnectionName => DbDumperFactory::createFromConnection($dbConnectionName)] + fn (string $dbConnectionName): array => [$dbConnectionName => DbDumperFactory::createFromConnection($dbConnectionName)] ); } } diff --git a/src/Tasks/Backup/Zip.php b/src/Tasks/Backup/Zip.php index 83b0010f..41181481 100644 --- a/src/Tasks/Backup/Zip.php +++ b/src/Tasks/Backup/Zip.php @@ -3,6 +3,7 @@ namespace Spatie\Backup\Tasks\Backup; use Illuminate\Support\Str; +use Spatie\Backup\Config\Config; use Spatie\Backup\Helpers\Format; use ZipArchive; @@ -12,10 +13,23 @@ class Zip protected int $fileCount = 0; + protected Config $config; + + public function __construct(protected string $pathToZip) + { + $this->zipFile = new ZipArchive(); + $this->config = app(Config::class); + + $this->open(); + } + public static function createForManifest(Manifest $manifest, string $pathToZip): self { - $relativePath = config('backup.backup.source.files.relative_path') ? - rtrim((string) config('backup.backup.source.files.relative_path'), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR : false; + $config = app(Config::class); + + $relativePath = $config->backup->source->files->relativePath + ? rtrim($config->backup->source->files->relativePath, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR + : false; $zip = new static($pathToZip); @@ -47,13 +61,6 @@ protected static function determineNameOfFileInZip(string $pathToFile, string $p return $pathToFile; } - public function __construct(protected string $pathToZip) - { - $this->zipFile = new ZipArchive(); - - $this->open(); - } - public function path(): string { return $this->pathToZip; @@ -93,8 +100,8 @@ public function add(string|iterable $files, ?string $nameInZip = null): self $files = [$files]; } - $compressionMethod = config('backup.backup.destination.compression_method', null); - $compressionLevel = config('backup.backup.destination.compression_level', 9); + $compressionMethod = $this->config->backup->destination->compressionMethod; + $compressionLevel = $this->config->backup->destination->compressionLevel; foreach ($files as $file) { if (is_dir($file)) { @@ -104,13 +111,11 @@ public function add(string|iterable $files, ?string $nameInZip = null): self if (is_file($file)) { $this->zipFile->addFile($file, ltrim((string) $nameInZip, DIRECTORY_SEPARATOR)); - if (is_int($compressionMethod)) { - $this->zipFile->setCompressionName( - ltrim($nameInZip ?: $file, DIRECTORY_SEPARATOR), - $compressionMethod, - $compressionLevel - ); - } + $this->zipFile->setCompressionName( + ltrim($nameInZip ?: $file, DIRECTORY_SEPARATOR), + $compressionMethod, + $compressionLevel + ); } $this->fileCount++; diff --git a/src/Tasks/Monitor/BackupDestinationStatusFactory.php b/src/Tasks/Monitor/BackupDestinationStatusFactory.php index 233fdec8..42c0c6ec 100644 --- a/src/Tasks/Monitor/BackupDestinationStatusFactory.php +++ b/src/Tasks/Monitor/BackupDestinationStatusFactory.php @@ -4,29 +4,29 @@ use Illuminate\Support\Collection; use Spatie\Backup\BackupDestination\BackupDestination; +use Spatie\Backup\Config\MonitoredBackupsConfig; class BackupDestinationStatusFactory { /** - * @param array{name: string, disks: array, health_checks: array>} $monitorConfiguration * @return Collection */ - public static function createForMonitorConfig(array $monitorConfiguration): Collection + public static function createForMonitorConfig(MonitoredBackupsConfig $monitorConfiguration): Collection { - return collect($monitorConfiguration) + return collect($monitorConfiguration->monitorBackups) ->flatMap(fn (array $monitorProperties) => self::createForSingleMonitor($monitorProperties)) ->sortBy(fn (BackupDestinationStatus $backupDestinationStatus) => $backupDestinationStatus->backupDestination()->backupName().'-'. $backupDestinationStatus->backupDestination()->diskName()); } /** - * @param array{name: string, disks: array, health_checks: array>} $monitorConfig + * @param array{name: string, disks: array, healthChecks: array>} $monitorConfig * @return Collection */ public static function createForSingleMonitor(array $monitorConfig): Collection { return collect($monitorConfig['disks']) - ->map(function ($diskName) use ($monitorConfig) { + ->map(function ($diskName) use ($monitorConfig): \Spatie\Backup\Tasks\Monitor\BackupDestinationStatus { $backupDestination = BackupDestination::create($diskName, $monitorConfig['name']); return new BackupDestinationStatus($backupDestination, static::buildHealthChecks($monitorConfig)); @@ -34,23 +34,13 @@ public static function createForSingleMonitor(array $monitorConfig): Collection } /** - * @param array{name: string, disks: array, health_checks: array>} $monitorConfig + * @param array{name: string, disks: array, healthChecks: array>} $monitorConfig * @return array */ protected static function buildHealthChecks(array $monitorConfig): array { - 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) { + return collect($monitorConfig['healthChecks']) + ->map(function ($options, $class): \Spatie\Backup\Tasks\Monitor\HealthCheck { if (is_int($class)) { $class = $options; $options = []; diff --git a/src/Traits/Retryable.php b/src/Traits/Retryable.php index bae1cf1a..f255a983 100644 --- a/src/Traits/Retryable.php +++ b/src/Traits/Retryable.php @@ -37,11 +37,19 @@ protected function setTries(string $type): void return; } - $this->tries = (int) config('backup.'.$type.'.tries', 1); + $this->tries = match ($type) { + 'backup' => $this->config->backup->tries, + 'cleanup' => $this->config->cleanup->tries, + default => 1, + }; } protected function getRetryDelay(string $type): int { - return (int) config('backup.'.$type.'.retry_delay', 0); + return match ($type) { + 'backup' => $this->config->backup->retryDelay, + 'cleanup' => $this->config->cleanup->retryDelay, + default => 0, + }; } } diff --git a/tests/BackupDestination/BackupTest.php b/tests/BackupDestination/BackupTest.php index 9767eabd..2b48c1c5 100644 --- a/tests/BackupDestination/BackupTest.php +++ b/tests/BackupDestination/BackupTest.php @@ -6,6 +6,7 @@ use Mockery as m; use Spatie\Backup\BackupDestination\Backup; use Spatie\Backup\BackupDestination\BackupDestinationFactory; +use Spatie\Backup\Config\Config; use Spatie\Backup\Exceptions\InvalidBackupFile; it('can determine the disk of the backup', function () { @@ -92,7 +93,9 @@ 's3-test-backup', ]); - $backupDestination = BackupDestinationFactory::createFromArray(config('backup.backup'))->first(); + $config = Config::fromArray(config('backup')); + + $backupDestination = BackupDestinationFactory::createFromArray($config)->first(); expect($backupDestination->getDiskOptions())->toEqual(['StorageClass' => 'COLD']); }); @@ -107,7 +110,9 @@ 'local', ]); - $backupDestination = BackupDestinationFactory::createFromArray(config('backup.backup'))->first(); + $config = Config::fromArray(config('backup')); + + $backupDestination = BackupDestinationFactory::createFromArray($config)->first(); expect($backupDestination->getDiskOptions())->toBe([]); }); diff --git a/tests/Commands/BackupCommandTest.php b/tests/Commands/BackupCommandTest.php index 3b883325..0c59d72b 100644 --- a/tests/Commands/BackupCommandTest.php +++ b/tests/Commands/BackupCommandTest.php @@ -397,6 +397,8 @@ config()->set('backup.backup.destination.compression_method', ZipArchive::CM_STORE); config()->set('backup.backup.destination.compression_level', 0); + \Spatie\Backup\Config\Config::rebind(); + $this->artisan('backup:run --only-db')->assertExitCode(0); $zip = new ZipArchive(); @@ -411,6 +413,8 @@ config()->set('backup.backup.destination.compression_method', ZipArchive::CM_DEFLATE); config()->set('backup.backup.destination.compression_level', 2); + \Spatie\Backup\Config\Config::rebind(); + $this->artisan('backup:run --only-db')->assertExitCode(0); $zip = new ZipArchive(); diff --git a/tests/Commands/ListCommandTest.php b/tests/Commands/ListCommandTest.php index e3c12903..a5b67f6e 100644 --- a/tests/Commands/ListCommandTest.php +++ b/tests/Commands/ListCommandTest.php @@ -7,13 +7,3 @@ $this->artisan('backup:list')->assertExitCode(0); }); - -it('warns_the_user_about_the_old_style_config_keys', function () { - $this->artisan('backup:list') - ->assertSuccessful(); - - config(['backup.monitorBackups' => config('backup.monitor_backups')]); - - $this->artisan('backup:list') - ->expectsOutput('Warning! Your config file still uses the old monitorBackups key. Update it to monitor_backups.'); -}); diff --git a/tests/Commands/MonitorCommandTest.php b/tests/Commands/MonitorCommandTest.php index 79277a05..f768f0dc 100644 --- a/tests/Commands/MonitorCommandTest.php +++ b/tests/Commands/MonitorCommandTest.php @@ -2,19 +2,6 @@ namespace Spatie\Backup\Tests\Commands; -use Spatie\Backup\Tests\TestCase; - -class MonitorCommandTest extends TestCase -{ - /** @test */ - public function it_warns_the_user_about_the_old_style_config_keys(): void - { - $this->artisan('backup:monitor') - ->assertSuccessful(); - - config(['backup.monitorBackups' => config('backup.monitor_backups')]); - - $this->artisan('backup:monitor') - ->expectsOutput('Warning! Your config file still uses the old monitorBackups key. Update it to monitor_backups.'); - } -} +it('can run the monitor command', function () { + $this->artisan('backup:monitor')->assertExitCode(0); +}); diff --git a/tests/Notifications/EventHandlerTest.php b/tests/Notifications/EventHandlerTest.php index 5da94435..bcfb1aee 100644 --- a/tests/Notifications/EventHandlerTest.php +++ b/tests/Notifications/EventHandlerTest.php @@ -2,6 +2,7 @@ use Illuminate\Support\Facades\Notification; use Spatie\Backup\BackupDestination\BackupDestinationFactory; +use Spatie\Backup\Config\Config; use Spatie\Backup\Events\BackupHasFailed; use Spatie\Backup\Notifications\Notifiable; use Spatie\Backup\Notifications\Notifications\BackupHasFailedNotification; @@ -49,11 +50,13 @@ Notification::assertSentTimes(BackupHasFailedNotification::class, 1); }); -function fireBackupHasFailedEvent() +function fireBackupHasFailedEvent(): void { $exception = new Exception('Dummy exception'); - $backupDestination = BackupDestinationFactory::createFromArray(config('backup.backup'))->first(); + $config = Config::fromArray(config('backup')); + + $backupDestination = BackupDestinationFactory::createFromArray($config)->first(); event(new BackupHasFailed($exception, $backupDestination)); } diff --git a/tests/TestCase.php b/tests/TestCase.php index 28b699ef..d7e5f45b 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -55,7 +55,7 @@ protected function getEnvironmentSetUp($app) Storage::fake('secondLocal'); } - protected function setUpDatabase(Application $app) + protected function setUpDatabase(Application $app): void { touch($this->getTempDirectory().'/database.sqlite'); @@ -114,7 +114,7 @@ protected function fileExistsInZip(string $diskName, string $zipPath, string $fi return false; } - protected function assertExactPathExistsInZip(string $diskName, string $zipPath, string $fullPath) + protected function assertExactPathExistsInZip(string $diskName, string $zipPath, string $fullPath): void { $this->assertTrue( $this->exactPathExistsInZip($diskName, $zipPath, $fullPath),