Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.x] Support non-revisable fields in entries #11252

Open
wants to merge 30 commits into
base: 5.x
Choose a base branch
from
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
c33ed4d
add to base field
edalzell Dec 12, 2024
4aff3fa
tiny refactor to prep
edalzell Dec 12, 2024
8817d35
update the contract and implement in entry
edalzell Dec 12, 2024
42b23b7
better
edalzell Dec 12, 2024
cac88a7
get the non-revisable fields
edalzell Dec 13, 2024
59c9267
save the non-revisable data
edalzell Dec 13, 2024
83108ea
tidier
edalzell Dec 13, 2024
4f5106a
tidy
edalzell Dec 13, 2024
668de50
move this so all revisable data can use it
edalzell Dec 13, 2024
34b3dc5
first test
edalzell Dec 13, 2024
9a32871
Field test
edalzell Dec 13, 2024
34e8b23
fix tests
edalzell Dec 13, 2024
b7eefe1
tidy
edalzell Dec 13, 2024
bc3645a
test revision attributes
edalzell Dec 13, 2024
d7cb176
test makeFromRevision
edalzell Dec 13, 2024
5b26aa1
support terms
edalzell Dec 13, 2024
9b5c6e2
term controller
edalzell Dec 13, 2024
06028e1
entry revision tests
edalzell Dec 20, 2024
e6543e3
lint
edalzell Dec 20, 2024
3c4df11
Merge branch 'statamic:5.x' into non-revisable-fields
edalzell Jan 3, 2025
710f61f
prep for revisions
edalzell Jan 3, 2025
1f89ced
get base test going
edalzell Jan 3, 2025
5e845ff
add test and pass
edalzell Jan 4, 2025
5c149ad
lint
edalzell Jan 4, 2025
bc25912
Merge branch 'statamic:5.x' into non-revisable-fields
edalzell Jan 6, 2025
75dbadb
Merge branch '5.x' into non-revisable-fields
edalzell Jan 27, 2025
2149c64
whoops need to return all data to the front end
edalzell Jan 28, 2025
0e2ea62
remove debugging
edalzell Jan 28, 2025
17067fa
Discard changes to src/Http/Controllers/CP/Taxonomies/TermsController…
edalzell Jan 28, 2025
0473902
Discard changes to src/Taxonomies/LocalizedTerm.php
edalzell Jan 28, 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
4 changes: 2 additions & 2 deletions src/Entries/Entry.php
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,7 @@ protected function revisionAttributes()
'slug' => $this->slug(),
'published' => $this->published(),
'date' => $this->collection()->dated() ? $this->date()->timestamp : null,
'data' => $this->data()->except(['updated_by', 'updated_at'])->all(),
'data' => $this->data()->except(['updated_by', 'updated_at', ...$this->nonRevisableFields()])->all(),
];
}

Expand All @@ -689,7 +689,7 @@ public function makeFromRevision($revision)

$entry
->published($attrs['published'])
->data($attrs['data'])
->data($this->data()->merge($attrs['data']))
->slug($attrs['slug']);

if ($this->collection()->dated() && ($date = Arr::get($attrs, 'date'))) {
Expand Down
13 changes: 13 additions & 0 deletions src/Fields/Field.php
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@ public function isFilterable()
return (bool) $this->get('filterable');
}

public function isRevisable()
{
return (bool) $this->get('revisable', true);
}

public function shouldBeDuplicated()
{
if (is_null($this->get('duplicate'))) {
Expand All @@ -269,6 +274,7 @@ public function toPublishArray()
'visibility' => $this->visibility(),
'read_only' => $this->visibility() === 'read_only', // Deprecated: Addon fieldtypes should now reference new `visibility` state.
'always_save' => $this->alwaysSave(),
'revisable' => $this->isRevisable(),
]);
}

Expand Down Expand Up @@ -567,6 +573,13 @@ public static function commonFieldOptions(): Fields
'validate' => 'boolean',
'default' => true,
],
'revisable' => [
'display' => __('Revisable'),
'instructions' => __('statamic::messages.fields_revisable_instructions'),
'type' => 'toggle',
'validate' => 'boolean',
'default' => true,
],
])->map(fn ($field, $handle) => compact('handle', 'field'))->values()->all();

return new ConfigFields($fields);
Expand Down
17 changes: 17 additions & 0 deletions src/Http/Controllers/CP/Collections/EntriesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
use Illuminate\Validation\ValidationException;
use Statamic\Contracts\Entries\Entry as EntryContract;
use Statamic\CP\Breadcrumbs;
use Statamic\Entries\Entry as EntriesEntry;
use Statamic\Exceptions\BlueprintNotFoundException;
use Statamic\Facades\Action;
use Statamic\Facades\Asset;
use Statamic\Facades\Entry;
use Statamic\Facades\Site;
use Statamic\Facades\Stache;
use Statamic\Facades\User;
use Statamic\Fields\Field;
use Statamic\Hooks\CP\EntriesIndexQuery;
use Statamic\Http\Controllers\CP\CpController;
use Statamic\Http\Requests\FilteredRequest;
Expand Down Expand Up @@ -261,6 +263,9 @@ public function update(Request $request, $collection, $entry)
->user(User::current())
->save();

// have to save in case there are non-revisable fields
$this->saveNonRevisableFields($entry);

// catch any changes through RevisionSaving event
$entry = $entry->fromWorkingCopy();
} else {
Expand Down Expand Up @@ -563,4 +568,16 @@ protected function ensureCollectionIsAvailableOnSite($collection, $site)
return redirect()->back()->with('error', __('Collection is not available on site ":handle".', ['handle' => $site->handle]));
}
}

private function saveNonRevisableFields(EntriesEntry $entry): void
{
/** @var EntriesEntry */
$savedVersion = $entry->fresh();

$entry->blueprint()->fields()->all()
->reject(fn (Field $field) => $field->isRevisable())
->each(fn ($ignore, string $fieldHandle) => $savedVersion->set($fieldHandle, $entry->{$fieldHandle}));

$savedVersion->save();
}
}
10 changes: 10 additions & 0 deletions src/Revisions/Revisable.php
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,16 @@ public function revisionsEnabled()
return config('statamic.revisions.enabled') && Statamic::pro();
}

public function nonRevisableFields(): array
{
return $this->blueprint()
->fields()
->all()
->reject(fn ($field) => $field->isRevisable())
->keys()
->all();
}

abstract protected function revisionKey();

abstract protected function revisionAttributes();
Expand Down
52 changes: 48 additions & 4 deletions tests/Feature/Entries/EntryRevisionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,16 @@ public function it_gets_revisions()
{
$now = Carbon::parse('2017-02-03');
Carbon::setTestNow($now);
$this->setTestBlueprint('test', ['foo' => ['type' => 'text']]);
$this->setTestBlueprint(
'test',
[
'foo' => ['type' => 'text'],
'bar' => [
'type' => 'text',
'revisable' => false,
],
]
);
$this->setTestRoles(['test' => ['access cp', 'publish blog entries']]);
$user = User::make()->id('user-1')->assignRole('test')->save();

Expand All @@ -58,6 +67,7 @@ public function it_gets_revisions()
'blueprint' => 'test',
'title' => 'Original title',
'foo' => 'bar',
'bar' => 'foo',
])->create();

tap($entry->makeRevision(), function ($copy) {
Expand Down Expand Up @@ -85,6 +95,7 @@ public function it_gets_revisions()
->assertJsonPath('0.revisions.0.message', 'Revision one')
->assertJsonPath('0.revisions.0.attributes.data.title', 'Original title')
->assertJsonPath('0.revisions.0.attributes.item_url', 'http://localhost/cp/collections/blog/entries/1/revisions/'.Carbon::parse('2017-02-01')->timestamp)
->assertJsonPath('0.revisions.0.attributes.data.bar', null)

->assertJsonPath('1.revisions.0.action', 'revision')
->assertJsonPath('1.revisions.0.message', false)
Expand All @@ -102,7 +113,16 @@ public function it_publishes_an_entry()
{
$now = Carbon::parse('2017-02-03');
Carbon::setTestNow($now);
$this->setTestBlueprint('test', ['foo' => ['type' => 'text']]);
$this->setTestBlueprint(
'test',
[
'foo' => ['type' => 'text'],
'bar' => [
'type' => 'text',
'revisable' => false,
],
]
);
$this->setTestRoles(['test' => ['access cp', 'publish blog entries']]);
$user = User::make()->id('user-1')->assignRole('test')->save();

Expand All @@ -115,6 +135,7 @@ public function it_publishes_an_entry()
'blueprint' => 'test',
'title' => 'Title',
'foo' => 'bar',
'bar' => 'foo',
])->create();

tap($entry->makeWorkingCopy(), function ($copy) {
Expand All @@ -137,6 +158,7 @@ public function it_publishes_an_entry()
'blueprint' => 'test',
'title' => 'Title',
'foo' => 'foo modified in working copy',
'bar' => 'foo',
'updated_at' => $now->timestamp,
'updated_by' => $user->id(),
], $entry->data()->all());
Expand Down Expand Up @@ -166,7 +188,16 @@ public function it_unpublishes_an_entry()
{
$now = Carbon::parse('2017-02-03');
Carbon::setTestNow($now);
$this->setTestBlueprint('test', ['foo' => ['type' => 'text']]);
$this->setTestBlueprint(
'test',
[
'foo' => ['type' => 'text'],
'bar' => [
'type' => 'text',
'revisable' => false,
],
]
);
$this->setTestRoles(['test' => ['access cp', 'publish blog entries']]);
$user = User::make()->id('user-1')->assignRole('test')->save();

Expand All @@ -179,6 +210,7 @@ public function it_unpublishes_an_entry()
'blueprint' => 'test',
'title' => 'Title',
'foo' => 'bar',
'bar' => 'foo',
])->create();

$this->assertTrue($entry->published());
Expand All @@ -194,6 +226,7 @@ public function it_unpublishes_an_entry()
'blueprint' => 'test',
'title' => 'Title',
'foo' => 'bar',
'bar' => 'foo',
'updated_at' => $now->timestamp,
'updated_by' => $user->id(),
], $entry->data()->all());
Expand All @@ -219,7 +252,16 @@ public function it_unpublishes_an_entry()
#[Test]
public function it_creates_a_revision()
{
$this->setTestBlueprint('test', ['foo' => ['type' => 'text']]);
$this->setTestBlueprint(
'test',
[
'foo' => ['type' => 'text'],
'bar' => [
'type' => 'text',
'revisable' => false,
],
]
);
$this->setTestRoles(['test' => ['access cp', 'edit blog entries']]);
$user = User::make()->id('user-1')->assignRole('test')->save();

Expand All @@ -232,6 +274,7 @@ public function it_creates_a_revision()
'blueprint' => 'test',
'title' => 'Title',
'foo' => 'bar',
'bar' => 'foo',
])->create();

tap($entry->makeWorkingCopy(), function ($copy) {
Expand All @@ -253,6 +296,7 @@ public function it_creates_a_revision()
'blueprint' => 'test',
'title' => 'Title',
'foo' => 'bar',
'bar' => 'foo',
], $entry->data()->all());
$this->assertFalse($entry->published());
$this->assertCount(1, $entry->revisions());
Expand Down
60 changes: 57 additions & 3 deletions tests/Feature/Entries/UpdateEntryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Statamic\Facades\Blueprint;
use Statamic\Facades\Collection;
use Statamic\Facades\Entry;
use Statamic\Facades\Folder;
use Statamic\Facades\Role;
use Statamic\Facades\User;
use Statamic\Structures\CollectionStructure;
Expand All @@ -23,6 +24,25 @@ class UpdateEntryTest extends TestCase
use FakesRoles;
use PreventSavingStacheItemsToDisk;

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

$this->dir = __DIR__.'/tmp';

config([
'statamic.editions.pro' => true,
'statamic.revisions.path' => $this->dir,
'statamic.revisions.enabled' => true,
]);
}

public function tearDown(): void
{
Folder::delete($this->dir);
parent::tearDown();
}

#[Test]
public function it_denies_access_if_you_dont_have_edit_permission()
{
Expand Down Expand Up @@ -416,7 +436,41 @@ public function it_can_validate_against_published_value()
#[Test]
public function published_entry_gets_saved_to_working_copy()
{
$this->markTestIncomplete();
[$user, $collection] = $this->seedUserAndCollection(true);

$this->seedBlueprintFields($collection, [
'revisable' => ['type' => 'text'],
'non_revisable' => ['type' => 'text', 'revisable' => false],
]);

$entry = EntryFactory::id('1')
->slug('test')
->collection('test')
->data(['title' => 'Revisable Test', 'published' => true])
->create();

$this
->actingAs($user)
->update($entry, [
'revisable' => 'revise me',
'non_revisable' => 'no revisions for you',
])
->assertOk();

$entry = Entry::find($entry->id());
$this->assertEquals('no revisions for you', $entry->non_revisable);
$this->assertEquals('Revisable Test', $entry->title);
$this->assertEquals('test', $entry->slug());
$this->assertNull($entry->revisable);

$workingCopy = $entry->fromWorkingCopy();
$this->assertEquals('updated-entry', $workingCopy->slug());
$this->assertEquals([
'title' => 'Updated entry',
'revisable' => 'revise me',
'non_revisable' => 'no revisions for you',
'published' => true,
], $workingCopy->data()->all());
}

#[Test]
Expand Down Expand Up @@ -501,7 +555,7 @@ public function does_not_validate_max_depth_when_collection_max_depth_is_null()
->assertOk();
}

private function seedUserAndCollection()
private function seedUserAndCollection(bool $enableRevisions = false)
{
$this->setTestRoles(['test' => [
'access cp',
Expand All @@ -510,7 +564,7 @@ private function seedUserAndCollection()
'access fr site',
]]);
$user = tap(User::make()->assignRole('test'))->save();
$collection = tap(Collection::make('test'))->save();
$collection = tap(Collection::make('test')->revisionsEnabled($enableRevisions))->save();

return [$user, $collection];
}
Expand Down
4 changes: 4 additions & 0 deletions tests/Fields/BlueprintTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ public function converts_to_array_suitable_for_rendering_fields_in_publish_compo
'visibility' => 'visible',
'replicator_preview' => true,
'duplicate' => true,
'revisable' => true,
'type' => 'text',
'validate' => 'required|min:2',
'input_type' => 'text',
Expand Down Expand Up @@ -474,6 +475,7 @@ public function converts_to_array_suitable_for_rendering_fields_in_publish_compo
'visibility' => 'visible',
'replicator_preview' => true,
'duplicate' => true,
'revisable' => true,
'type' => 'textarea',
'placeholder' => null,
'validate' => 'min:2',
Expand Down Expand Up @@ -563,6 +565,7 @@ public function converts_to_array_suitable_for_rendering_prefixed_conditional_fi
'visibility' => 'visible',
'replicator_preview' => true,
'duplicate' => true,
'revisable' => true,
'type' => 'text',
'input_type' => 'text',
'placeholder' => null,
Expand All @@ -589,6 +592,7 @@ public function converts_to_array_suitable_for_rendering_prefixed_conditional_fi
'visibility' => 'visible',
'replicator_preview' => true,
'duplicate' => true,
'revisable' => true,
'type' => 'text',
'input_type' => 'text',
'placeholder' => null,
Expand Down
Loading
Loading