Skip to content

Commit 29ade28

Browse files
committed
RefreshDatabaseFast Trait
1 parent 37de248 commit 29ade28

File tree

5 files changed

+199
-4
lines changed

5 files changed

+199
-4
lines changed

README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ You can install the package via composer:
1616
composer require laracraft-tech/laravel-useful-traits
1717
```
1818

19+
Then publish the config file with:
20+
21+
```bash
22+
php artisan vendor:publish --tag="laravel-useful-traits-config"
23+
```
24+
1925
## Usage
2026

2127
The following traits are provided in the `LaracraftTech`-namespace:
@@ -127,6 +133,48 @@ $class::select('foo')->fromYesterday()->first()->toArray();
127133
// return ['foo' => 'foo2']
128134
```
129135

136+
### RefreshDatabaseFast
137+
138+
---
139+
140+
Credits to [Mayahi](https://mayahi.net/laravel/make-refresh-database-trait-much-faster/).
141+
142+
This is a trait which makes the migration of your database in your test suite much, much faster!
143+
It basically only migrates your database if the migration files has changed.
144+
So the first `migrate:fresh` takes awhile (depending on how many migrations you have), and then it's incredible fast.
145+
146+
Optionally you can set `USEFUL_TRAITS_SEED_AFTER_FAST_DB_REFRESH` to `true` if you like to seed your database after the migration.
147+
148+
***Pest:***
149+
```php
150+
// Pest.php
151+
152+
use LaracraftTech\LaravelUsefulTraits\RefreshDatabaseFast;
153+
use Tests\TestCase;
154+
155+
uses(
156+
Tests\TestCase::class,
157+
RefreshDatabaseCustom::class
158+
)->in('Feature');
159+
```
160+
161+
***PHPUnit:***
162+
```php
163+
use LaracraftTech\LaravelUsefulTraits\RefreshDatabaseFast;
164+
use Tests\TestCase;
165+
166+
class MyTest extends TestCase
167+
{
168+
use RefreshDatabaseFast;
169+
170+
/** @test **/
171+
public function it_does_something()
172+
{
173+
// ...
174+
}
175+
}
176+
```
177+
130178
## Testing
131179

132180
```bash

config/useful-traits.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
<?php
22

3-
// config for LaracraftTech/LaravelUsefulTraits
43
return [
5-
4+
"refresh_db_fast" => [
5+
/**
6+
* This field determines if the database should be seeded after migration.
7+
*/
8+
"seed" => env('USEFUL_TRAITS_SEED_AFTER_FAST_DB_REFRESH', false),
9+
],
610
];

src/LaravelUsefulTraitsServiceProvider.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ public function configurePackage(Package $package): void
1515
* More info: https://github.com/spatie/laravel-package-tools
1616
*/
1717
$package
18-
->name('laravel-useful-traits');
18+
->name('laravel-useful-traits')
19+
->hasConfigFile()
20+
;
1921
}
2022
}

src/RefreshDatabaseFast.php

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
<?php
2+
3+
namespace LaracraftTech\LaravelUsefulTraits;
4+
5+
use Illuminate\Contracts\Console\Kernel;
6+
use Illuminate\Foundation\Testing\RefreshDatabase;
7+
use Illuminate\Foundation\Testing\RefreshDatabaseState;
8+
use Symfony\Component\Finder\Finder;
9+
10+
/**
11+
* Only migrate fresh if necessary -> much faster after first time!
12+
* Credits to mayahi, with some small changes of mine.
13+
* @link https://mayahi.net/laravel/make-refresh-database-trait-much-faster/
14+
*/
15+
trait RefreshDatabaseFast
16+
{
17+
use RefreshDatabase;
18+
19+
/**
20+
* Only migrates fresh if necessary
21+
*
22+
* @return void
23+
*/
24+
protected function refreshTestDatabase(): void
25+
{
26+
if (! RefreshDatabaseState::$migrated) {
27+
$this->runMigrationsIfNecessary();
28+
29+
$this->app[Kernel::class]->setArtisan(null);
30+
31+
RefreshDatabaseState::$migrated = true;
32+
}
33+
34+
$this->beginDatabaseTransaction();
35+
}
36+
37+
/**
38+
* Check if migration fresh is necessary by checking
39+
* if the migrations files checksum has changed.
40+
*
41+
* @return void
42+
*/
43+
protected function runMigrationsIfNecessary(): void
44+
{
45+
if (!$this->identicalChecksum()) {
46+
if (config('useful-traits.refresh_db_fast.seed')) {
47+
$this->seed();
48+
}
49+
50+
$this->artisan('migrate:fresh', $this->migrateFreshUsing());
51+
52+
//create checksum after migration finishes
53+
$this->createChecksum();
54+
}
55+
}
56+
57+
/**
58+
* Calaculates the checksum of the migration files.
59+
*
60+
* @return string
61+
*/
62+
private function calculateChecksum(): string
63+
{
64+
$files = Finder::create()
65+
->files()
66+
->exclude([
67+
'factories',
68+
'seeders',
69+
])
70+
->in(database_path())
71+
->ignoreDotFiles(true)
72+
->ignoreVCS(true)
73+
->getIterator();
74+
75+
$files = array_keys(iterator_to_array($files));
76+
77+
$checksum = collect($files)->map(function($file) {return md5_file($file);})->implode('');
78+
79+
return md5($checksum);
80+
}
81+
82+
/**
83+
* Filepath to store the checksum.
84+
*
85+
* @return string
86+
*/
87+
private function checksumFilePath(): string
88+
{
89+
return base_path('.phpunit.database.checksum');
90+
}
91+
92+
/**
93+
* Creates the checksum file.
94+
*
95+
* @return void
96+
*/
97+
private function createChecksum(): void
98+
{
99+
file_put_contents($this->checksumFilePath(), $this->calculateChecksum());
100+
}
101+
102+
/**
103+
* Get the checksum file content.
104+
*
105+
* @return false|string
106+
*/
107+
private function checksumFileContents()
108+
{
109+
return file_get_contents($this->checksumFilePath());
110+
}
111+
112+
/**
113+
* Check if checksum exists.
114+
*
115+
* @return bool
116+
*/
117+
private function isChecksumExists(): bool
118+
{
119+
return file_exists($this->checksumFilePath());
120+
}
121+
122+
/**
123+
* Check if checksum of current database migration files
124+
* are identical to the one we stored already.
125+
*
126+
* @return bool
127+
*/
128+
private function identicalChecksum(): bool
129+
{
130+
if (!$this->isChecksumExists()) {
131+
return false;
132+
}
133+
134+
if ($this->checksumFileContents() === $this->calculateChecksum()) {
135+
return true;
136+
}
137+
138+
return false;
139+
}
140+
}

tests/Pest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
<?php
22

33
use Illuminate\Foundation\Testing\RefreshDatabase;
4+
use LaracraftTech\LaravelUsefulTraits\RefreshDatabaseFast;
45
use LaracraftTech\LaravelUsefulTraits\Tests\TestCase;
56

6-
uses(RefreshDatabase::class);
7+
uses(RefreshDatabaseFast::class);
78

89
uses(TestCase::class)->in(__DIR__);

0 commit comments

Comments
 (0)