Skip to content

Commit e8721ca

Browse files
committed
Add support for non-staged Versioned DataObjects
1 parent 6f4a631 commit e8721ca

File tree

3 files changed

+67
-35
lines changed

3 files changed

+67
-35
lines changed

src/Extensions/CacheKeyExtension.php

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
use Terraformers\KeysForCache\State\StagingState;
1818

1919
/**
20-
* @property DataObject|$this $owner
20+
* @property DataObject|Versioned|$this $owner
2121
* @method HasManyList|CacheKey CacheKeys()
2222
*/
2323
class CacheKeyExtension extends DataExtension
@@ -72,16 +72,18 @@ public function getCacheKey(): ?string
7272
public function onAfterWrite(): void
7373
{
7474
// We will want to publish changes to the CacheKey onAfterWrite if the instance triggering this event is *not*
75-
// Versioned (the changes should be seen immediately even though the object wasn't Published)
76-
$publishUpdates = !$this->owner->hasExtension(Versioned::class);
75+
// a Staged Versioned DataObject (the changes should be seen immediately even though the object wasn't
76+
// Published)
77+
$publishUpdates = !$this->ownerHasStages();
7778
$this->owner->triggerCacheEvent($publishUpdates);
7879
}
7980

8081
public function onAfterDelete(): void
8182
{
8283
// We will want to publish changes to the CacheKey onAfterWrite if the instance triggering this event is *not*
83-
// Versioned (the changes should be seen immediately even though the object wasn't Published)
84-
$publishUpdates = !$this->owner->hasExtension(Versioned::class);
84+
// a Staged Versioned DataObject (the changes should be seen immediately even though the object wasn't
85+
// Published)
86+
$publishUpdates = !$this->ownerHasStages();
8587
// Note: doArchive will call deleteFromStage() which will in turn trigger this extension hook
8688
$this->owner->triggerCacheEvent($publishUpdates);
8789
CacheKey::remove($this->owner);
@@ -194,4 +196,19 @@ private function findCacheKeyHash(): ?string
194196

195197
return $cacheKey->KeyHash;
196198
}
199+
200+
private function ownerHasStages(): bool
201+
{
202+
// This DataObject does not have the Versioned extension, so it definitely doesn't have stages (IE: Draft and
203+
// Live versions)
204+
if (!$this->owner->hasExtension(Versioned::class)) {
205+
return false;
206+
}
207+
208+
// The Versioned extensions has two modes. The one that we're (probably) all familiar with, where we have a
209+
// Draft and Live version, but there is also a mode that does not have stages, and instead only has _Versions.
210+
// If this DataObject does not have stages, then we're going to want to treat this the same as a non-Versioned
211+
// DataObject
212+
return $this->owner->hasStages();
213+
}
197214
}

src/Extensions/GridFieldOrderableRowsExtension.php

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,27 @@
1414
use SilverStripe\Versioned\Versioned;
1515

1616
/**
17-
* You do not need this Extension for Versioned DataObject. They are supported out of the box because
18-
* GridFieldOrderableRows already performs a write() through the ORM when sorting Versioned DataObjects.
17+
* You do not need this Extension if you are using `symbiote/silverstripe-gridfieldextensions` version `3.5.0` or newer.
18+
* Full support for Versioned and non-Versioned DataObjects is out of the box.
19+
*
20+
* You also do not need this Extension for Versioned DataObject. They are supported out of the box because
21+
* GridFieldOrderableRows already performs write() through the ORM when sorting Versioned DataObjects.
1922
*
2023
* WARNING: We absolutely plan to remove this extension once GridFieldOrderableRows supports sorting on non-Versioned
21-
* DataObjects. If you need it, probably best to copy/paste it to your project, and we empower you to own it from that
24+
* DataObjects. If you need it, probably best to copy/paste this to your project, and we empower you to own it from that
2225
* point forward.
2326
*
2427
* This Extension is *not* automatically applied because I think you should seriously consider Versioning your
2528
* DataObject. If you are adding this DataObject to (something like) an Element, which *is* Versioned, then (imo) it is
26-
* best that all of the related DataObjects (like its "Items") are also Versioned. This gives a consistent author
29+
* best that all the related DataObjects (like its "Items") are also Versioned. This gives a consistent author
2730
* experience - where they can have draft/live versions of things. You can then also rely on the existing support from
2831
* GridFieldOrderableRows.
2932
*
30-
* There is an open ticket on the GridFieldExtensions module to try and get GridFieldOrderableRows to use the ORM for
31-
* both Versioned and non-Versioned DataObjects:
33+
* There is a closed ticket on the GridFieldExtensions module that explains the issue (now fixed in v3.5.0):
3234
* https://github.com/symbiote/silverstripe-gridfieldextensions/issues/335
3335
*
34-
* In the meantime though, this Extension provides you a way to support the clearing of CacheKeys on non-Versioned
35-
* DataObjects when you are using the GridFieldOrderableRows component.
36+
* For folks on a version lower than 3.5.0, this Extension provides you a way to support the clearing of CacheKeys on
37+
* non-Versioned DataObjects when you are using the GridFieldOrderableRows component.
3638
*
3739
* This Extension also doesn't have any test coverage (because of everything we mentioned above). It has only gone
3840
* through manual testing. Use at your own risk and be prepared to submit tickets if you find any issues or use cases

tests/Scenarios/CaresTest.php

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -157,32 +157,45 @@ public function testCaresHasOneNonVersioned(string $readingMode): void
157157
});
158158
}
159159

160-
public function testCaresHasOneVersionedNonStaged(): void
160+
/**
161+
* @dataProvider readingModes
162+
*/
163+
public function testCaresHasOneVersionedNonStaged(string $readingMode): void
161164
{
162-
// Updates are processed as part of scaffold, so we need to flush before we kick off
163-
ProcessedUpdatesService::singleton()->flush();
164-
165165
$page = $this->objFromFixture(CaresPage::class, 'page1');
166166
$model = $this->objFromFixture(CaredHasOneVersionedNonStaged::class, 'model1');
167167

168+
// Make sure our page is published (the model is not Versioned)
169+
$page->publishRecursive();
170+
168171
// Check that we're set up correctly
169172
$this->assertEquals(CaredHasOneVersionedNonStaged::class, $model->ClassName);
170173
$this->assertEquals($page->CaredHasOneVersionedNonStagedID, $model->ID);
171174

172-
$originalKey = $page->getCacheKey();
175+
Versioned::withVersionedMode(function () use ($page, $model, $readingMode): void {
176+
// We perform our save method and read in the same reading mode
177+
Versioned::set_stage($readingMode);
173178

174-
$this->assertNotNull($originalKey);
175-
$this->assertNotEmpty($originalKey);
179+
// Specifically fetching this way to make sure it's us fetching without any generation of KeyHash
180+
$originalKey = CacheKey::findInStage($page);
176181

177-
// Begin changes
178-
$model->forceChange();
179-
$model->write();
182+
$this->assertNotNull($originalKey);
183+
$this->assertNotEmpty($originalKey);
184+
185+
// Flush updates so that new changes generate new CacheKey hashes
186+
ProcessedUpdatesService::singleton()->flush();
180187

181-
$newKey = $page->getCacheKey();
188+
// Begin changes
189+
$model->forceChange();
190+
$model->write();
182191

183-
$this->assertNotNull($newKey);
184-
$this->assertNotEmpty($newKey);
185-
$this->assertNotEquals($originalKey, $newKey);
192+
// Specifically fetching this way to make sure it's us fetching without any generation of KeyHash
193+
$newKey = CacheKey::findInStage($page);
194+
195+
$this->assertNotNull($newKey);
196+
$this->assertNotEmpty($newKey);
197+
$this->assertNotEquals($originalKey, $newKey);
198+
});
186199
}
187200

188201
/**
@@ -327,6 +340,14 @@ function () use ($page, $model, $readingMode, $saveMethod, $expectKeyChange): vo
327340
);
328341
}
329342

343+
public function readingModes(): array
344+
{
345+
return [
346+
[Versioned::DRAFT],
347+
[Versioned::LIVE],
348+
];
349+
}
350+
330351
public function readingModesWithSaveMethods(): array
331352
{
332353
return [
@@ -345,14 +366,6 @@ public function readingModesWithSaveMethods(): array
345366
];
346367
}
347368

348-
public function readingModes(): array
349-
{
350-
return [
351-
[Versioned::DRAFT],
352-
[Versioned::LIVE],
353-
];
354-
}
355-
356369
protected function tearDown(): void
357370
{
358371
Injector::inst()->get(Graph::CACHE_KEY)->clear();

0 commit comments

Comments
 (0)