Skip to content

Commit e9f7a8d

Browse files
ryanmitchellduncanmccleanjasonvarga
authored
[5.x] Revisions query builder (#514)
* init * add tests and fixes * Mock user facade in repository tests * fix path * fix recursion --------- Co-authored-by: Duncan McClean <duncan@duncanmcclean.com> Co-authored-by: Jason Varga <jason@pixelfear.com>
1 parent e115153 commit e9f7a8d

File tree

6 files changed

+179
-57
lines changed

6 files changed

+179
-57
lines changed

src/Commands/ImportRevisions.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Illuminate\Support\Facades\File;
88
use Statamic\Console\RunsInPlease;
99
use Statamic\Eloquent\Revisions\Revision;
10+
use Statamic\Facades\Stache;
1011
use Statamic\Facades\YAML;
1112

1213
class ImportRevisions extends Command
@@ -45,7 +46,7 @@ public function handle(): int
4546

4647
private function importRevisions(): void
4748
{
48-
$this->withProgressBar(File::allFiles(config('statamic.stache.stores.revisions.directory')), function ($file) {
49+
$this->withProgressBar(File::allFiles(Stache::store('revisions')->directory()), function ($file) {
4950
$yaml = YAML::file($file->getPathname())->parse();
5051

5152
$revision = (new Revision)

src/Revisions/Revision.php

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@
33
namespace Statamic\Eloquent\Revisions;
44

55
use Illuminate\Database\Eloquent\Model;
6-
use Statamic\Events\RevisionDeleted;
7-
use Statamic\Events\RevisionSaved;
8-
use Statamic\Events\RevisionSaving;
96
use Statamic\Revisions\Revision as FileEntry;
10-
use Statamic\Revisions\WorkingCopy;
117

128
class Revision extends FileEntry
139
{
@@ -33,11 +29,10 @@ public static function fromModel(Model $model)
3329
{
3430
return (new static)
3531
->key($model->key)
36-
->action($model->action ?? false)
37-
->id($model->created_at->timestamp)
32+
->action($model->action ?? null)
3833
->date($model->created_at)
39-
->user($model->user ?? false)
40-
->message($model->message ?? '')
34+
->user($model->user ?? null)
35+
->message($model->message ?? null)
4136
->attributes($model->attributes ?? [])
4237
->model($model);
4338
}
@@ -59,10 +54,10 @@ public function fromRevisionOrWorkingCopy($item)
5954
{
6055
return (new static)
6156
->key($item->key())
62-
->action($item instanceof WorkingCopy ? 'working' : $item->action())
57+
->action($item->isWorkingCopy() ? 'working' : $item->action())
6358
->date($item->date())
64-
->user($item->user()?->id() ?? false)
65-
->message($item->message() ?? '')
59+
->user($item->user()?->id() ?? null)
60+
->message($item->message() ?? null)
6661
->attributes($item->attributes() ?? []);
6762
}
6863

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

7772
return $this;
7873
}
79-
80-
public function save()
81-
{
82-
if (RevisionSaving::dispatch($this) === false) {
83-
return false;
84-
}
85-
86-
$this->model->save();
87-
88-
RevisionSaved::dispatch($this);
89-
}
90-
91-
public function delete()
92-
{
93-
$this->model->delete();
94-
95-
RevisionDeleted::dispatch($this);
96-
}
9774
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
namespace Statamic\Eloquent\Revisions;
4+
5+
use Illuminate\Support\Collection as IlluminateCollection;
6+
use Illuminate\Support\Str;
7+
use Statamic\Contracts\Revisions\Revision as RevisionContract;
8+
use Statamic\Contracts\Revisions\RevisionQueryBuilder as QueryBuilderContract;
9+
use Statamic\Query\EloquentQueryBuilder;
10+
11+
class RevisionQueryBuilder extends EloquentQueryBuilder implements QueryBuilderContract
12+
{
13+
private $selectedQueryColumns;
14+
15+
const COLUMNS = [
16+
'id', 'key', 'action', 'user', 'message', 'attributes',
17+
];
18+
19+
protected function transform($items, $columns = [])
20+
{
21+
return IlluminateCollection::make($items)->map(function ($model) use ($columns) {
22+
return app(RevisionContract::class)::fromModel($model)
23+
->selectedQueryColumns($this->selectedQueryColumns ?? $columns);
24+
});
25+
}
26+
27+
protected function column($column)
28+
{
29+
if (! is_string($column)) {
30+
return $column;
31+
}
32+
33+
if (! in_array($column, self::COLUMNS)) {
34+
if (! Str::startsWith($column, 'attributes->')) {
35+
$column = 'attributes->'.$column;
36+
}
37+
}
38+
39+
return $column;
40+
}
41+
42+
public function with($relations, $callback = null)
43+
{
44+
return $this;
45+
}
46+
}

src/Revisions/RevisionRepository.php

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,11 @@
33
namespace Statamic\Eloquent\Revisions;
44

55
use Statamic\Contracts\Revisions\Revision as RevisionContract;
6+
use Statamic\Contracts\Revisions\RevisionQueryBuilder as QueryBuilderContract;
67
use Statamic\Revisions\RevisionRepository as StacheRepository;
7-
use Statamic\Revisions\WorkingCopy;
88

99
class RevisionRepository extends StacheRepository
1010
{
11-
public function make(): RevisionContract
12-
{
13-
return new (app('statamic.eloquent.revisions.model'));
14-
}
15-
16-
public function whereKey($key)
17-
{
18-
return app('statamic.eloquent.revisions.model')::where('key', $key)
19-
->orderBy('created_at')
20-
->get()
21-
->map(function ($revision) use ($key) {
22-
return $this->makeRevisionFromFile($key, $revision);
23-
})->keyBy(function ($revision) {
24-
return $revision->date()->timestamp;
25-
});
26-
}
27-
2811
public function findWorkingCopyByKey($key)
2912
{
3013
$class = app('statamic.eloquent.revisions.model');
@@ -37,28 +20,22 @@ public function findWorkingCopyByKey($key)
3720

3821
public function save(RevisionContract $copy)
3922
{
40-
if ($copy instanceof WorkingCopy) {
23+
if ($copy->isWorkingCopy()) {
4124
app('statamic.eloquent.revisions.model')::where([
4225
'key' => $copy->key(),
4326
'action' => 'working',
4427
])->delete();
4528
}
4629

47-
$revision = (new Revision)
30+
(new Revision)
4831
->fromRevisionOrWorkingCopy($copy)
4932
->toModel()
5033
->save();
5134
}
5235

5336
public function delete(RevisionContract $revision)
5437
{
55-
if ($revision instanceof WorkingCopy) {
56-
$this->findWorkingCopyByKey($revision->key())?->delete();
57-
58-
return;
59-
}
60-
61-
$revision->model?->delete();
38+
$revision->model()?->delete();
6239
}
6340

6441
protected function makeRevisionFromFile($key, $model)
@@ -70,6 +47,7 @@ public static function bindings(): array
7047
{
7148
return [
7249
RevisionContract::class => Revision::class,
50+
QueryBuilderContract::class => RevisionQueryBuilder::class,
7351
];
7452
}
7553
}

src/ServiceProvider.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
use Statamic\Eloquent\Forms\SubmissionRepository;
3434
use Statamic\Eloquent\Globals\GlobalRepository;
3535
use Statamic\Eloquent\Globals\GlobalVariablesRepository;
36+
use Statamic\Eloquent\Revisions\RevisionQueryBuilder;
3637
use Statamic\Eloquent\Revisions\RevisionRepository;
3738
use Statamic\Eloquent\Structures\CollectionTreeRepository;
3839
use Statamic\Eloquent\Structures\NavigationRepository;
@@ -485,6 +486,12 @@ private function registerRevisions()
485486
return config('statamic.eloquent-driver.revisions.model');
486487
});
487488

489+
$this->app->bind(RevisionQueryBuilder::class, function ($app) {
490+
return new RevisionQueryBuilder(
491+
$app['statamic.eloquent.revisions.model']::query()
492+
);
493+
});
494+
488495
Statamic::repository(RevisionRepositoryContract::class, RevisionRepository::class);
489496
}
490497

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php
2+
3+
namespace Repositories;
4+
5+
use Illuminate\Foundation\Testing\RefreshDatabase;
6+
use Illuminate\Support\Collection;
7+
use PHPUnit\Framework\Attributes\Test;
8+
use Statamic\Eloquent\Revisions\Revision;
9+
use Statamic\Eloquent\Revisions\RevisionQueryBuilder;
10+
use Statamic\Eloquent\Revisions\RevisionRepository;
11+
use Statamic\Facades\User;
12+
use Statamic\Stache\Stache;
13+
use Tests\TestCase;
14+
15+
class RevisionRepositoryTest extends TestCase
16+
{
17+
use RefreshDatabase;
18+
19+
protected function setUp(): void
20+
{
21+
parent::setUp();
22+
23+
$stache = (new Stache)->sites(['en', 'fr']);
24+
$this->app->instance(Stache::class, $stache);
25+
$this->repo = new RevisionRepository($stache);
26+
27+
\Statamic\Facades\User::shouldReceive('find')->andReturnNull();
28+
\Statamic\Facades\User::shouldReceive('current')->andReturnNull();
29+
30+
\Statamic\Facades\Revision::make()
31+
->key('123')
32+
->action('working')
33+
->date(now())
34+
->save();
35+
36+
\Statamic\Facades\Revision::make()
37+
->key('123')
38+
->action('other')
39+
->date(now()->subHour())
40+
->save();
41+
42+
\Statamic\Facades\Revision::make()
43+
->key('123')
44+
->action('other')
45+
->date(now()->subHours(2))
46+
->save();
47+
48+
\Statamic\Facades\Revision::make()
49+
->key('456')
50+
->action('working')
51+
->date(now())
52+
->save();
53+
54+
\Statamic\Facades\Revision::make()
55+
->key('456')
56+
->action('other')
57+
->date(now()->subHour())
58+
->save();
59+
}
60+
61+
#[Test]
62+
public function it_gets_revisions_and_excludes_working_copies()
63+
{
64+
$revisions = $this->repo->whereKey('123');
65+
66+
$this->assertInstanceOf(Collection::class, $revisions);
67+
$this->assertCount(2, $revisions);
68+
$this->assertContainsOnlyInstancesOf(Revision::class, $revisions);
69+
}
70+
71+
#[Test]
72+
public function it_can_call_to_array_on_a_revision_collection()
73+
{
74+
User::shouldReceive('find')->andReturnNull();
75+
76+
$revisions = $this->repo->whereKey('123');
77+
78+
$this->assertIsArray($revisions->toArray());
79+
}
80+
81+
#[Test]
82+
public function it_returns_a_query_builder()
83+
{
84+
$builder = $this->repo->query();
85+
86+
$this->assertInstanceOf(RevisionQueryBuilder::class, $builder);
87+
}
88+
89+
#[Test]
90+
public function it_gets_and_filters_items_using_query_builder()
91+
{
92+
$builder = $this->repo->query();
93+
94+
$revisions = $builder->get();
95+
$this->assertInstanceOf(Collection::class, $revisions);
96+
$this->assertCount(5, $revisions);
97+
$this->assertContainsOnlyInstancesOf(Revision::class, $revisions);
98+
99+
$revisions = $builder->where('key', '123')->get();
100+
$this->assertInstanceOf(Collection::class, $revisions);
101+
$this->assertCount(3, $revisions);
102+
$this->assertContainsOnlyInstancesOf(Revision::class, $revisions);
103+
104+
$revisions = $builder->where('key', '123')->where('action', '!=', 'working')->get();
105+
$this->assertInstanceOf(Collection::class, $revisions);
106+
$this->assertCount(2, $revisions);
107+
$this->assertContainsOnlyInstancesOf(Revision::class, $revisions);
108+
109+
$revisions = $builder->where('key', '1234')->get();
110+
$this->assertInstanceOf(Collection::class, $revisions);
111+
$this->assertCount(0, $revisions);
112+
}
113+
}

0 commit comments

Comments
 (0)