Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b2641d9
Add upgrade note to readme
ryanmitchell Jun 23, 2023
d5f933f
Merge remote-tracking branch 'upstream/master'
ryanmitchell Jun 24, 2023
b3070a1
Merge remote-tracking branch 'upstream/master'
ryanmitchell Jun 26, 2023
f20faef
Merge remote-tracking branch 'upstream/master'
ryanmitchell Jun 26, 2023
3c43ef5
Missing update script
ryanmitchell Jun 27, 2023
946b2dd
Correct file path to migration
ryanmitchell Jun 27, 2023
2ec8658
Lets not exclude parent
ryanmitchell Jun 28, 2023
7e32a0f
Merge remote-tracking branch 'upstream/master'
ryanmitchell Jun 29, 2023
91788de
Merge remote-tracking branch 'upstream/master'
ryanmitchell Jul 20, 2023
0d63f24
Merge remote-tracking branch 'upstream/master'
ryanmitchell Aug 10, 2023
a43f1cd
Merge remote-tracking branch 'upstream/master'
ryanmitchell Oct 23, 2023
0aece49
Merge remote-tracking branch 'upstream/master'
ryanmitchell Dec 7, 2023
b6fc439
Merge remote-tracking branch 'upstream/master'
ryanmitchell Feb 20, 2024
ada0328
Merge remote-tracking branch 'upstream/master'
ryanmitchell Mar 11, 2024
3610761
Merge remote-tracking branch 'upstream/master'
ryanmitchell Mar 14, 2024
c0557fc
Merge remote-tracking branch 'upstream/master'
ryanmitchell Apr 12, 2024
cc772b5
Merge remote-tracking branch 'upstream/master'
ryanmitchell May 8, 2024
23577cb
Merge remote-tracking branch 'upstream/master'
ryanmitchell Jun 5, 2024
f629b6c
Merge remote-tracking branch 'upstream/master'
ryanmitchell Jun 5, 2024
9d66e17
Merge remote-tracking branch 'upstream/master'
ryanmitchell Jun 17, 2024
4660d8e
Merge remote-tracking branch 'upstream/master'
ryanmitchell Jun 27, 2024
ebe086b
Merge remote-tracking branch 'upstream/master'
ryanmitchell Jul 16, 2024
ddf7f91
Merge remote-tracking branch 'upstream/master'
ryanmitchell Jul 24, 2024
04961c2
Merge remote-tracking branch 'upstream/master'
ryanmitchell Aug 21, 2024
856806d
Merge remote-tracking branch 'upstream/master'
ryanmitchell Oct 18, 2024
3c4683a
Merge remote-tracking branch 'upstream/master'
ryanmitchell Aug 22, 2025
0dd6b00
Merge branch '4.x'
ryanmitchell Aug 22, 2025
92d215c
Merge remote-tracking branch 'upstream/master'
ryanmitchell Nov 5, 2025
626c9d4
init
ryanmitchell Nov 5, 2025
07a1f21
add tests and fixes
ryanmitchell Nov 5, 2025
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: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
},
"require": {
"php": "^8.2",
"statamic/cms": "^6.0"
"statamic/cms": "dev-master"
},
"require-dev": {
"doctrine/dbal": "^3.8",
Expand Down
2 changes: 1 addition & 1 deletion src/Commands/ImportRevisions.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public function handle(): int

private function importRevisions(): void
{
$this->withProgressBar(File::allFiles(config('statamic.revisions.path')), function ($file) {
$this->withProgressBar(File::allFiles(config('statamic.stache.stores.revisions.directory')), function ($file) {
$yaml = YAML::file($file->getPathname())->parse();

$revision = (new Revision)
Expand Down
35 changes: 6 additions & 29 deletions src/Revisions/Revision.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@
namespace Statamic\Eloquent\Revisions;

use Illuminate\Database\Eloquent\Model;
use Statamic\Events\RevisionDeleted;
use Statamic\Events\RevisionSaved;
use Statamic\Events\RevisionSaving;
use Statamic\Revisions\Revision as FileEntry;
use Statamic\Revisions\WorkingCopy;

class Revision extends FileEntry
{
Expand All @@ -33,11 +29,10 @@ public static function fromModel(Model $model)
{
return (new static)
->key($model->key)
->action($model->action ?? false)
->id($model->created_at->timestamp)
->action($model->action ?? null)
->date($model->created_at)
->user($model->user ?? false)
->message($model->message ?? '')
->user($model->user ?? null)
->message($model->message ?? null)
->attributes($model->attributes ?? [])
->model($model);
}
Expand All @@ -59,10 +54,10 @@ public function fromRevisionOrWorkingCopy($item)
{
return (new static)
->key($item->key())
->action($item instanceof WorkingCopy ? 'working' : $item->action())
->action($item->isWorkingCopy() ? 'working' : $item->action())
->date($item->date())
->user($item->user()?->id() ?? false)
->message($item->message() ?? '')
->user($item->user()?->id() ?? null)
->message($item->message() ?? null)
->attributes($item->attributes() ?? []);
}

Expand All @@ -76,22 +71,4 @@ public function model($model = null)

return $this;
}

public function save()
{
if (RevisionSaving::dispatch($this) === false) {
return false;
}

$this->model->save();

RevisionSaved::dispatch($this);
}

public function delete()
{
$this->model->delete();

RevisionDeleted::dispatch($this);
}
}
46 changes: 46 additions & 0 deletions src/Revisions/RevisionQueryBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace Statamic\Eloquent\Revisions;

use Illuminate\Support\Collection as IlluminateCollection;
use Illuminate\Support\Str;
use Statamic\Contracts\Revisions\Revision as RevisionContract;
use Statamic\Contracts\Revisions\RevisionQueryBuilder as QueryBuilderContract;
use Statamic\Query\EloquentQueryBuilder;

class RevisionQueryBuilder extends EloquentQueryBuilder implements QueryBuilderContract
{
private $selectedQueryColumns;

const COLUMNS = [
'id', 'key', 'action', 'user', 'message', 'attributes',
];

protected function transform($items, $columns = [])
{
return IlluminateCollection::make($items)->map(function ($model) use ($columns) {
return app(RevisionContract::class)::fromModel($model)
->selectedQueryColumns($this->selectedQueryColumns ?? $columns);
});
}

protected function column($column)
{
if (! is_string($column)) {
return $column;
}

if (! in_array($column, self::COLUMNS)) {
if (! Str::startsWith($column, 'attributes->')) {
$column = 'attributes->'.$column;
}
}

return $column;
}

public function with($relations, $callback = null)
{
return $this;
}
}
24 changes: 4 additions & 20 deletions src/Revisions/RevisionRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,11 @@
namespace Statamic\Eloquent\Revisions;

use Statamic\Contracts\Revisions\Revision as RevisionContract;
use Statamic\Contracts\Revisions\RevisionQueryBuilder as QueryBuilderContract;
use Statamic\Revisions\RevisionRepository as StacheRepository;
use Statamic\Revisions\WorkingCopy;

class RevisionRepository extends StacheRepository
{
public function make(): RevisionContract
{
return new (app('statamic.eloquent.revisions.model'));
}

public function whereKey($key)
{
return app('statamic.eloquent.revisions.model')::where('key', $key)
->orderBy('created_at')
->get()
->map(function ($revision) use ($key) {
return $this->makeRevisionFromFile($key, $revision);
})->keyBy(function ($revision) {
return $revision->date()->timestamp;
});
}

public function findWorkingCopyByKey($key)
{
$class = app('statamic.eloquent.revisions.model');
Expand All @@ -37,7 +20,7 @@ public function findWorkingCopyByKey($key)

public function save(RevisionContract $copy)
{
if ($copy instanceof WorkingCopy) {
if ($copy->isWorkingCopy()) {
app('statamic.eloquent.revisions.model')::where([
'key' => $copy->key(),
'action' => 'working',
Expand All @@ -52,7 +35,7 @@ public function save(RevisionContract $copy)

public function delete(RevisionContract $revision)
{
if ($revision instanceof WorkingCopy) {
if ($revision->isWorkingCopy()) {
$this->findWorkingCopyByKey($revision->key())?->delete();

return;
Expand All @@ -70,6 +53,7 @@ public static function bindings(): array
{
return [
RevisionContract::class => Revision::class,
QueryBuilderContract::class => RevisionQueryBuilder::class,
];
}
}
7 changes: 7 additions & 0 deletions src/ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
use Statamic\Eloquent\Forms\SubmissionRepository;
use Statamic\Eloquent\Globals\GlobalRepository;
use Statamic\Eloquent\Globals\GlobalVariablesRepository;
use Statamic\Eloquent\Revisions\RevisionQueryBuilder;
use Statamic\Eloquent\Revisions\RevisionRepository;
use Statamic\Eloquent\Structures\CollectionTreeRepository;
use Statamic\Eloquent\Structures\NavigationRepository;
Expand Down Expand Up @@ -466,6 +467,12 @@ private function registerRevisions()
return config('statamic.eloquent-driver.revisions.model');
});

$this->app->bind(RevisionQueryBuilder::class, function ($app) {
return new RevisionQueryBuilder(
$app['statamic.eloquent.revisions.model']::query()
);
});

Statamic::repository(RevisionRepositoryContract::class, RevisionRepository::class);
}

Expand Down
5 changes: 2 additions & 3 deletions tests/Commands/ImportRevisionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,9 @@ protected function setUp(): void

config()->set('statamic.revisions', [
'enabled' => true,
'path' => __DIR__.'/tmp',
]);

mkdir(__DIR__.'/tmp');
config()->set('statamic.stache.stores.revisions.directory', __DIR__.'/../__fixtures__/dev-null/storage/statamic/revisions');

Facade::clearResolvedInstance(RevisionRepositoryContract::class);

Expand All @@ -35,7 +34,7 @@ protected function setUp(): void

protected function tearDown(): void
{
app('files')->deleteDirectory(__DIR__.'/tmp');
app('files')->deleteDirectory(config('statamic.stache.stores.revisions.directory'));

parent::tearDown();
}
Expand Down
110 changes: 110 additions & 0 deletions tests/Repositories/RevisionRepositoryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php

namespace Repositories;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Collection;
use PHPUnit\Framework\Attributes\Test;
use Statamic\Eloquent\Revisions\Revision;
use Statamic\Eloquent\Revisions\RevisionQueryBuilder;
use Statamic\Eloquent\Revisions\RevisionRepository;
use Statamic\Facades\User;
use Statamic\Stache\Stache;
use Tests\TestCase;

class RevisionRepositoryTest extends TestCase
{
use RefreshDatabase;

protected function setUp(): void
{
parent::setUp();

$stache = (new Stache)->sites(['en', 'fr']);
$this->app->instance(Stache::class, $stache);
$this->repo = new RevisionRepository($stache);

\Statamic\Facades\Revision::make()
->key('123')
->action('working')
->date(now())
->save();

\Statamic\Facades\Revision::make()
->key('123')
->action('other')
->date(now()->subHour())
->save();

\Statamic\Facades\Revision::make()
->key('123')
->action('other')
->date(now()->subHours(2))
->save();

\Statamic\Facades\Revision::make()
->key('456')
->action('working')
->date(now())
->save();

\Statamic\Facades\Revision::make()
->key('456')
->action('other')
->date(now()->subHour())
->save();
}

#[Test]
public function it_gets_revisions_and_excludes_working_copies()
{
$revisions = $this->repo->whereKey('123');

$this->assertInstanceOf(Collection::class, $revisions);
$this->assertCount(2, $revisions);
$this->assertContainsOnlyInstancesOf(Revision::class, $revisions);
}

#[Test]
public function it_can_call_to_array_on_a_revision_collection()
{
User::shouldReceive('find')->andReturnNull();

$revisions = $this->repo->whereKey('123');

$this->assertIsArray($revisions->toArray());
}

#[Test]
public function it_returns_a_query_builder()
{
$builder = $this->repo->query();

$this->assertInstanceOf(RevisionQueryBuilder::class, $builder);
}

#[Test]
public function it_gets_and_filters_items_using_query_builder()
{
$builder = $this->repo->query();

$revisions = $builder->get();
$this->assertInstanceOf(Collection::class, $revisions);
$this->assertCount(5, $revisions);
$this->assertContainsOnlyInstancesOf(Revision::class, $revisions);

$revisions = $builder->where('key', '123')->get();
$this->assertInstanceOf(Collection::class, $revisions);
$this->assertCount(3, $revisions);
$this->assertContainsOnlyInstancesOf(Revision::class, $revisions);

$revisions = $builder->where('key', '123')->where('action', '!=', 'working')->get();
$this->assertInstanceOf(Collection::class, $revisions);
$this->assertCount(2, $revisions);
$this->assertContainsOnlyInstancesOf(Revision::class, $revisions);

$revisions = $builder->where('key', '1234')->get();
$this->assertInstanceOf(Collection::class, $revisions);
$this->assertCount(0, $revisions);
}
}
Loading