My team at Spatie is currently building Mailcoach, a solution to self host your e-mail newsletter. Mailcoach can be used as stand alone software or as a Laravel package. Subscribe now at Mailcoach to get a notification as soon as we release it.

laravel-backup v6 has been released

Original – by Freek Van der Herten – 4 minute read

laravel-backup is a Laravel package that can backup your application.

It can create a zip containing a dump of your database together with other files that you can select. Using the power of Laravel's filesystem abstraction this zip can than be uploaded to one or more remote filesystems. The package can also monitor the health of your backups and notify if anything goes wrong.

We recently released v6 of the laravel-backup. Though it's a new major version it's mostly a cleanup of the internals. The only new feature added is the support for creating custom health checks.

Support for custom health checks

In previous versions of the package health was determined by the size and the age of last backup. If the backup was too large or the last backups was already a day old, we'd send a notification.

In the new version of the package you can write your own health check. You could for instance check if the size of your backup grows. If it doesn't get larger over time, something might be wrong, and a notification can be sent.

Writing your own health check is pretty easy. You need to create a class that implements Spatie\Backup\Tasks\Monitor\HealthCheck and register your class in the config file. Want to know more, head over to the docs.

Rewritten tests

The first versions of the package supported Laravel 5.1. The core testsuite of the package was written with the testing facilities Laravel had at that time. Meanwhile a lot of niceties have been added to Laravel: faking the filesystem, faking notifications, testing console commands, ...

For v6 of laravel-backup, I took to the time to rewrite the testsuite to make use of these new features.

Let's take a look at the package can clean up old backups. In this test we create 1000 backups with different ages. Then we run the backup:clean command and verify that some backups are still there and some have been deleted.

Here's the old code first. I edited it slightly for brevity. In this old code I still had to setup a temp directory and to fake a filesystem myself.

/** @test */
public function it_can_remove_old_backups_from_the_backup_directory()
{
    $allBackups = collect();

    collect(range(0, 1000))->each(function (int $numberOfDays) use ($allBackups) {
        $date = Carbon::now()->subDays($numberOfDays);

        $allBackups->push($this->testHelper->createTempFileWithAge("mysite/test_{$date->format('Ymd')}_first.zip", $date));
        $allBackups->push($this->testHelper->createTempFileWithAge("mysite/test_{$date->format('Ymd')}_second.zip", $date->addHour(2)));
    });

    $remainingBackups = collect([
        'mysite/test_20131231_first.zip',
        'mysite/test_20141231_first.zip',
        'mysite/test_20150630_first.zip',
        // ...
    ]);

    Artisan::call('backup:clean');

    $this->assertTempFilesExist($remainingBackups->toArray());

    $deletedBackups = $allBackups
        ->map(function ($fullPath) {
            $tempPath = str_replace($this->testHelper->getTempDirectory().'/', '', $fullPath);

            return $tempPath;
        })
        ->reject(function (string $deletedPath) use ($remainingBackups) {
            return $remainingBackups->contains($deletedPath);
        });

    $this->assertTempFilesNotExist($deletedBackups->toArray());
}

And here's the new version. Here we can just make use a faked filesystem and use some cool collection methods that were added to recent Laravel versions. It's not less lines of code, but the intent of the code is more clear.

/** @test */
public function it_can_remove_old_backups_from_the_backup_directory()
{
    $this->setNow(2016, 1, 1);

    [$expectedRemainingBackups, $expectedDeletedBackups] = Collection::times(1000)
        ->flatMap(function (int $numberOfDays) {
            $date = now()->subDays($numberOfDays);

            return [
                $this->createFileOnDisk('local', "mysite/test_{$date->format('Ymd')}_first.zip", $date),
                $this->createFileOnDisk('local', "mysite/test_{$date->format('Ymd')}_second.zip", $date->addHour(2)),
            ];
        })->partition(function (string $backupPath) {
            return in_array($backupPath, [
                'mysite/test_20131231_first.zip',
                'mysite/test_20141231_first.zip',
                'mysite/test_20150630_first.zip',
                // ... 
            ]);
        });

    $this->artisan('backup:clean')->assertExitCode(0);

    Storage::disk('local')
	   ->assertExists($expectedRemainingBackups->toArray())
	   ->assertMissing($expectedDeletedBackups->toArray());
}

It's great to see just how the features added to Laravel enabled me to write clearer code. Though regular users will never see them, these rewritten tests will improve the experience that contributors will have when working on the package.

In closing

Don't think that using backups of your hosting provider is enough. They can fuck up too. If you want to know more about the features of laravel-backup itself, go read the docs.

Stay up to date with all things Laravel, PHP, and JavaScript.

Follow me on Twitter. I regularly tweet out programming tips, and what I myself have learned in ongoing projects.

Every two weeks I send out a newsletter containing lots of interesting stuff for the modern PHP developer.

Expect quick tips & tricks, interesting tutorials, opinions and packages. Because I work with Laravel every day there is an emphasis on that framework.

Rest assured that I will only use your email address to send you the newsletter and will not use it for any other purposes.

Marc Guinea liked on 9th July 2019
ダビッド トレス liked on 8th July 2019
Duy Ha Nguyen replied on 8th July 2019
totally agree with you