Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Contracts/Revision.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public function revisionable(): MorphTo;

public function previous(): ?static;

public function next(): ?static;

Comment thread
thijskok marked this conversation as resolved.
Comment on lines 16 to +19
public function diff(?self $target = null): Diff;

public function toModel(): Model;
Comment on lines 16 to 22
Expand Down
31 changes: 31 additions & 0 deletions src/Models/Revision.php
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,37 @@ public function previous(): ?static
->first();
}

/**
* Return the revision that directly follows this one for the same model.
*/
public function next(): ?static
{
Comment on lines +189 to +193
return static::query()
->where([
['revisionable_type', $this->revisionable_type],
['revisionable_id', $this->revisionable_id],
[$this->getKeyName(), '>', $this->getKey()],
])
->oldest($this->getKeyName())
->first();
}

/**
* Determine whether this is the oldest revision for its model.
*/
public function isFirstRevision(): bool
{
return $this->exists && $this->previous() === null;
}

/**
* Determine whether this is the most recent revision for its model.
*/
public function isLastRevision(): bool
{
return $this->exists && $this->next() === null;
}
Comment on lines +207 to +218

/**
* Compare this revision against another revision or its predecessor.
*/
Expand Down
104 changes: 104 additions & 0 deletions tests/RevisionNavigationTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

namespace TestMonitor\Revisable\Tests;

use PHPUnit\Framework\Attributes\Test;
use TestMonitor\Revisable\Models\Revision;
use TestMonitor\Revisable\Tests\Models\Post;

class RevisionNavigationTest extends TestCase
{
#[Test]
public function it_returns_the_previous_revision()
{
// Given
$post = $this->createPost();

$this->modifyPost($post);
$this->modifyPost($post, ['name' => 'Yet another post name']);

$revisions = $post->revisions()->orderBy('id')->get();

// When / Then
$this->assertNull($revisions->first()->previous());
$this->assertTrue($revisions->last()->previous()->is($revisions->first()));
}

#[Test]
public function it_returns_the_next_revision()
{
// Given
$post = $this->createPost();

$this->modifyPost($post);
$this->modifyPost($post, ['name' => 'Yet another post name']);

$revisions = $post->revisions()->orderBy('id')->get();

// When / Then
$this->assertTrue($revisions->first()->next()->is($revisions->last()));
$this->assertNull($revisions->last()->next());
}

#[Test]
public function it_determines_whether_a_revision_is_the_first_revision()
{
// Given
$post = $this->createPost();

$this->modifyPost($post);
$this->modifyPost($post, ['name' => 'Yet another post name']);

$revisions = $post->revisions()->orderBy('id')->get();

// When / Then
$this->assertTrue($revisions->first()->isFirstRevision());
$this->assertFalse($revisions->last()->isFirstRevision());
}

#[Test]
public function it_determines_whether_a_revision_is_the_last_revision()
{
// Given
$post = $this->createPost();

$this->modifyPost($post);
$this->modifyPost($post, ['name' => 'Yet another post name']);

$revisions = $post->revisions()->orderBy('id')->get();

// When / Then
$this->assertFalse($revisions->first()->isLastRevision());
$this->assertTrue($revisions->last()->isLastRevision());
}

#[Test]
public function it_treats_a_single_revision_as_both_the_first_and_the_last()
{
// Given
$post = $this->createPost();

$this->modifyPost($post);

// When
$revision = $post->revisions()->firstOrFail();

// Then
$this->assertTrue($revision->isFirstRevision());
$this->assertTrue($revision->isLastRevision());
}

#[Test]
public function it_treats_an_unsaved_revision_as_neither_the_first_nor_the_last()
{
// Given
$revision = new Revision([
'revisionable_type' => Post::class,
'revisionable_id' => 1,
]);

// When / Then
$this->assertFalse($revision->isFirstRevision());
$this->assertFalse($revision->isLastRevision());
}
}