Skip to content

Commit

Permalink
it can rollback versions
Browse files Browse the repository at this point in the history
  • Loading branch information
sheadawson committed Sep 17, 2024
1 parent c6d2edc commit 2e69e58
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 62 deletions.
29 changes: 13 additions & 16 deletions src/Concerns/HasPublishing.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Indra\Revisor\Contracts\RevisorContract;
use Indra\Revisor\Contracts\HasPublishing as HasPublishingContract;
use Indra\Revisor\Facades\Revisor;

trait HasPublishing
Expand All @@ -19,13 +19,13 @@ trait HasPublishing

public static function bootHasPublishing(): void
{
static::created(function (RevisorContract $model) {
static::created(function (HasPublishingContract $model) {
if ($model->shouldPublishOnCreated()) {
$model->publish();
}
});

static::updated(function (RevisorContract $model) {
static::updated(function (HasPublishingContract $model) {
if ($model->shouldPublishOnUpdated()) {
$model->publish();
}
Expand All @@ -47,7 +47,7 @@ public function initializeHasPublishing(): void
* Copies the base record to the published table.
* Saves the updated base record.
*/
public function publish(): static|bool
public function publish(): HasPublishingContract|bool
{
if ($this->fireModelEvent('publishing') === false) {
return false;
Expand Down Expand Up @@ -78,7 +78,7 @@ public function publish(): static|bool
* Saves the updated base record.
* Fires the unpublished event.
*/
public function unpublish(): static
public function unpublish(): HasPublishingContract
{
if ($this->fireModelEvent('unpublishing') === false) {
return $this;
Expand Down Expand Up @@ -109,7 +109,7 @@ public function unpublish(): static
* Updates the published_at timestamp, sets is_published to true,
* and associates the current authenticated user as the publisher.
*/
public function setPublishedAttributes(): static
public function setPublishedAttributes(): HasPublishingContract
{
$this->published_at = now();
$this->is_published = true;
Expand All @@ -118,7 +118,7 @@ public function setPublishedAttributes(): static
return $this;
}

public function applyStateToPublishedRecord(): static
public function applyStateToPublishedRecord(): HasPublishingContract
{
// find or make the published record
$published = $this->publishedRecord ?? static::withPublishedTable();
Expand All @@ -133,7 +133,7 @@ public function applyStateToPublishedRecord(): static
return $this;
}

public function setUnpublishedAttributes(): static
public function setUnpublishedAttributes(): HasPublishingContract
{
$this->published_at = null;
$this->is_published = false;
Expand All @@ -157,29 +157,26 @@ public function publisher(): MorphTo
return $this->morphTo('publisher');
}

public static function withPublishedTable(): static
public static function withPublishedTable(): HasPublishingContract
{
$instance = new static;
$instance->setWithPublishedTable();

return $instance;
return app(static::class)->setWithPublishedTable();
}

public function setWithPublishedTable(bool $bool = true): static
public function setWithPublishedTable(bool $bool = true): HasPublishingContract
{
$this->withPublishedTable = $bool;

return $this;
}

public function publishOnCreated(bool $bool = true): static
public function publishOnCreated(bool $bool = true): HasPublishingContract
{
$this->publishOnCreated = $bool;

return $this;
}

public function publishOnUpdated(bool $bool = true): static
public function publishOnUpdated(bool $bool = true): HasPublishingContract
{
$this->publishOnUpdated = $bool;

Expand Down
2 changes: 1 addition & 1 deletion src/Concerns/HasRevisor.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ protected function fireModelEvent($event, $halt = true): mixed
return true;
}

if (! isset(static::$dispatcher)) {
if (!isset(static::$dispatcher)) {
return true;
}

Expand Down
101 changes: 63 additions & 38 deletions src/Concerns/HasVersioning.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Indra\Revisor\Contracts\RevisorContract;
use Indra\Revisor\Facades\Revisor;
use Indra\Revisor\Contracts\HasVersioning as HasVersioningContract;

trait HasVersioning
{
Expand All @@ -19,21 +19,21 @@ trait HasVersioning

public static function bootHasVersioning(): void
{
static::created(function (RevisorContract $model) {
static::created(function (HasVersioningContract $model) {
if ($model->shouldRecordNewVersionOnCreated()) {
$model->recordNewVersion();
}
});

static::updated(function (RevisorContract $model) {
static::updated(function (HasVersioningContract $model) {
if ($model->shouldRecordNewVersionOnUpdated()) {
$model->recordNewVersion();
} else {
$model->syncCurrentVersion();
}
});

static::saving(function (RevisorContract $model) {
static::saving(function (HasVersioningContract $model) {
$model->is_current = true;
});

Expand Down Expand Up @@ -66,35 +66,70 @@ public function initializeHasVersioning(): void
* Ensures it is_current and other versions are not
* Updates the current base record to have the new version_number
*/
public function recordNewVersion(): static|bool
public function recordNewVersion(): HasVersioningContract|bool
{
if ($this->fireModelEvent('savingNewVersion') === false) {
return false;
}

$version = static::withVersionTable();
$attributes = array_merge(
$this->attributes,
[
'is_current' => 1,
$attributes = collect($this->attributes)
->except(['id'])
->merge([
'record_id' => $this->id,
'version_number' => ($this->versions()->max('version_number') ?? 0) + 1,
]
);
unset($attributes['id']);
'version_number' => ($this->versions()->max('version_number') ?? 0) + 1
])
->toArray();

$this->setVersionAsCurrent(static::withVersionTable(), $attributes);

$this->fireModelEvent('savedNewVersion');

$version->forceFill($attributes)->saveQuietly();
return $this;
}

public function rollbackToVersion(HasVersioningContract|int $version): HasVersioningContract
{
$version = is_int($version) ? $this->versions()->find($version) : $version;

$this->fireModelEvent('rollingBackToVersion', $version);

// set the version as current and save it
$this->setVersionAsCurrent($version);

// update the current base record to have the data from the version
$this->forceFill(collect($version->getAttributes())->except(['id', 'record_id'])->toArray())
->saveQuietly();

$this->fireModelEvent('rolledBackToVersion', $version);

return $this->refresh();
}

public function rollbackToVersionNumber(int $versionNumber): HasVersioningContract
{
$version = $this->versions()->firstWhere('version_number', $versionNumber);

return $this->rollbackToVersion($version);
}

public function setVersionAsCurrent(HasVersioningContract|int $version, array $attributes = []): HasVersioningContract
{
$version = is_int($version) ? $this->versions()->find($version) : $version;

// update the version record with the given attributes
$version->forceFill($attributes);

// update all other versions to not be current
$this->versions()
->where('is_current', 1)
->where($version->getKeyName(), '!=', $version->getKey())
->update(['is_current' => 0]);
// and set this version as current and save it
$this->versions()->where('is_current', 1)->update(['is_current' => 0]);
$version->forceFill(['is_current' => 1])->saveQuietly();

// update the current base record to have the new version_number
$this->forceFill(['version_number' => $version->version_number])->saveQuietly();
if ($this->version_number !== $version->version_number) {
$this->forceFill(['version_number' => $version->version_number])->saveQuietly();
}

$this->fireModelEvent('savedNewVersion');
$this->refresh();

return $this;
}
Expand All @@ -119,9 +154,9 @@ public function currentVersion(): HasOne
)->where('is_current', 1);
}

public function syncCurrentVersion(): static|bool
public function syncCurrentVersion(): HasVersioningContract|bool
{
if (! $this->currentVersion) {
if (!$this->currentVersion) {
return $this->recordNewVersion();
}

Expand All @@ -130,29 +165,19 @@ public function syncCurrentVersion(): static|bool
return $this;
}

public static function withVersionTable(): static
public static function withVersionTable(): HasVersioningContract
{
$instance = new static;
$instance->setWithVersionTable();

return $instance;
}

public function setWithPublishedTable(bool $bool = true): static
{
$this->withPublishedTable = $bool;

return $this;
return app(static::class)->setWithVersionTable();
}

public function setWithVersionTable(bool $bool = true): static
public function setWithVersionTable(bool $bool = true): HasVersioningContract
{
$this->withVersionTable = $bool;

return $this;
}

public function recordNewVersionOnCreated(bool $bool = true): static
public function recordNewVersionOnCreated(bool $bool = true): HasVersioningContract
{
$this->recordNewVersionOnCreated = $bool;

Expand All @@ -166,7 +191,7 @@ public function shouldRecordNewVersionOnCreated(): bool
$this->recordNewVersionOnCreated;
}

public function recordNewVersionOnUpdated(bool $bool = true): static
public function recordNewVersionOnUpdated(bool $bool = true): HasVersioningContract
{
$this->recordNewVersionOnUpdated = $bool;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

namespace Indra\Revisor\Contracts;

interface RevisorContract {}
interface HasPublishing {}
7 changes: 7 additions & 0 deletions src/Contracts/HasVersioning.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

declare(strict_types=1);

namespace Indra\Revisor\Contracts;

interface HasVersioning {}
23 changes: 19 additions & 4 deletions tests/HasVersioningTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,29 @@

expect($page->currentVersion->version_number)->toBe(2)
->and($page->version_number)->toBe(2)
->and($page->publishedRecord->version_number)->toBe(2);
->and($page->publishedRecord->version_number)->toBe(2)
->and($page->versions()->count())->toBe(2);
});

it('can rollback versions', function () {
$page = Page::create(['title' => 'Home']);
$page->update(['title' => 'Home 2']);
$page->update(['title' => 'Home 2']);
$page->update(['title' => 'Home 2']);

// dd($page->versions()->count());
expect($page->versions()->count())->toBe(2)
->and($page->currentVersion->version_number)->toBe(2);

// rollback to version object
$page->rollbackToVersion($page->versions->first());
expect($page->currentVersion->version_number)->toBe(1)
->and($page->currentVersion->title)->toBe('Home');

// rollback to version id
$page->rollbackToVersion($page->versions->last()->id);
expect($page->currentVersion->version_number)->toBe(2)
->and($page->currentVersion->title)->toBe('Home 2');

// rollback to version number
$page->RollbackToVersionNumber(1);
expect($page->currentVersion->version_number)->toBe(1)
->and($page->currentVersion->title)->toBe('Home');
});
1 change: 1 addition & 0 deletions tests/MigrationsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
'content',
'created_at',
'updated_at',
'version_number'
];

sort($expectedColumns);
Expand Down
5 changes: 3 additions & 2 deletions tests/Models/Page.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@

use Illuminate\Database\Eloquent\Model;
use Indra\Revisor\Concerns\HasRevisor;
use Indra\Revisor\Contracts\RevisorContract;
use Indra\Revisor\Contracts\HasPublishing as HasPublishingContract;
use Indra\Revisor\Contracts\HasVersioning as HasVersioningContract;

class Page extends Model implements RevisorContract
class Page extends Model implements HasVersioningContract, HasPublishingContract
{
use HasRevisor;

Expand Down

0 comments on commit 2e69e58

Please sign in to comment.