Skip to content

Commit 366a193

Browse files
authored
feat: Add versionAt method (#43)
Queries a version at a specific time in the models history.
1 parent 12694da commit 366a193

File tree

3 files changed

+109
-6
lines changed

3 files changed

+109
-6
lines changed

README.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class Post extends Model
7272
* @var array
7373
*/
7474
protected $versionable = ['title', 'content'];
75-
75+
7676
// Or use blacklist
7777
//protected $dontVersionable = ['created_at', 'updated_at'];
7878

@@ -93,11 +93,15 @@ $post->update(['title' => 'version2']);
9393
$post->versions; // all versions
9494
$post->latestVersion; // latest version
9595
// or
96-
$post->lastVersion;
96+
$post->lastVersion;
9797

9898
$post->versions->first(); // first version
99-
// or
99+
// or
100100
$post->firstVersion;
101+
102+
$post->versionAt('2022-10-06 12:00:00'); // get version from a specific time
103+
// or
104+
$post->versionAt(\Carbon\Carbon::create(2022, 10, 6, 12));
101105
```
102106

103107
### Reversion
@@ -164,8 +168,8 @@ You can set the following different version policies through property `protected
164168
### Show diff between two versions
165169

166170
```php
167-
$diff = $post->getVersion(1)->diff($post->getVersion(2));
168-
```
171+
$diff = $post->getVersion(1)->diff($post->getVersion(2));
172+
```
169173

170174
`$diff` is a object `Overtrue\LaravelVersionable\Diff`, it based on [jfcherng/php-diff](https://github.com/jfcherng/php-diff).
171175

@@ -211,7 +215,7 @@ toSideBySideHtml(array $differOptions = [], array $renderOptions = []): array
211215
```
212216

213217
> **Note**
214-
>
218+
>
215219
> `$differOptions` and `$renderOptions` are optional, you can set them following the README of [jfcherng/php-diff](https://github.com/jfcherng/php-diff#example).
216220
217221
## :heart: Sponsor me

src/Versionable.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Illuminate\Database\Eloquent\Model;
66
use Illuminate\Database\Eloquent\Relations\MorphMany;
77
use Illuminate\Database\Eloquent\Relations\MorphOne;
8+
use Illuminate\Support\Carbon;
89

910
trait Versionable
1011
{
@@ -64,6 +65,25 @@ public function firstVersion(): MorphOne
6465
return $this->morphOne($this->getVersionModel(), 'versionable')->oldest('id');
6566
}
6667

68+
/**
69+
* Get the version for a specific time.
70+
*
71+
* @param string|DateTimeInterface|null $time
72+
* @param DateTimeZone|string|null $tz
73+
*
74+
* @throws \Carbon\Exceptions\InvalidFormatException
75+
*
76+
* @return static
77+
*/
78+
public function versionAt($time = null, $tz = null): ?Version
79+
{
80+
return $this->versions()
81+
->where('created_at', '<=', Carbon::parse($time, $tz))
82+
->orderByDesc('created_at')
83+
->orderByDesc($this->getKey())
84+
->first();
85+
}
86+
6787
public function getVersion(int $id): ?Version
6888
{
6989
return $this->versions()->find($id);

tests/VersionAtTest.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
3+
namespace Tests;
4+
5+
use Illuminate\Support\Carbon;
6+
use Overtrue\LaravelVersionable\Diff;
7+
8+
class VersionAtTest extends TestCase
9+
{
10+
protected $user;
11+
12+
protected function setUp(): void
13+
{
14+
parent::setUp();
15+
16+
Post::enableVersioning();
17+
18+
config([
19+
'auth.providers.users.model' => User::class,
20+
'versionable.user_model' => User::class,
21+
]);
22+
23+
$this->user = User::create(['name' => 'marijoo']);
24+
$this->actingAs($this->user);
25+
}
26+
27+
/**
28+
* @test
29+
*/
30+
public function it_can_find_version_at_specific_time()
31+
{
32+
$this->travelTo(Carbon::create(2022, 10, 1, 12, 0));
33+
34+
$post = Post::create(['title' => 'version1', 'content' => 'version1 content']);
35+
36+
$this->travelTo(Carbon::create(2022, 10, 2, 14, 0));
37+
38+
$post->update(['title' => 'version2']);
39+
40+
$this->travelTo(Carbon::create(2022, 10, 3, 10, 0));
41+
42+
$post->update(['title' => 'version3']);
43+
44+
$this->assertEquals('version1', $post->versionAt('2022-10-02 10:00:00')->contents['title']);
45+
$this->assertEquals('version1', $post->versionAt('2022-10-02 13:59:59')->contents['title']);
46+
$this->assertEquals('version2', $post->versionAt(Carbon::create(2022, 10, 02, 14))->contents['title']);
47+
$this->assertEquals('version2', $post->versionAt('2022-10-02 15:00:00')->contents['title']);
48+
$this->assertEquals('version3', $post->versionAt('2022-10-03 10:00:00')->contents['title']);
49+
}
50+
51+
/**
52+
* @test
53+
*/
54+
public function it_returns_null_if_given_time_is_before_first_version()
55+
{
56+
$this->travelTo(Carbon::create(2022, 10, 1, 12, 0));
57+
58+
$post = Post::create(['title' => 'version1', 'content' => 'version1 content']);
59+
60+
$this->assertNull($post->versionAt('2022-10-01 11:59:59'));
61+
$this->assertEquals('version1', $post->versionAt('2022-10-01 12:00:00')->contents['title']);
62+
}
63+
64+
/**
65+
* @test
66+
*/
67+
public function it_returns_latest_version_if_given_time_is_in_future()
68+
{
69+
$this->travelTo(Carbon::create(2022, 10, 1, 12, 0));
70+
71+
$post = Post::create(['title' => 'version1', 'content' => 'version1 content']);
72+
73+
$this->travelTo(Carbon::create(2022, 10, 2, 14, 0));
74+
75+
$post->update(['title' => 'version2']);
76+
77+
$this->assertEquals('version2', $post->versionAt('2024-11-01 12:00:00')->contents['title']);
78+
}
79+
}

0 commit comments

Comments
 (0)