@@ -40,6 +40,7 @@ public function updateCMSFields(FieldList $fields): void
4040 return ;
4141 }
4242
43+ // The configuration for this DataObject has specified that it does not use CacheKeys
4344 if (!$ this ->owner ->config ()->get ('has_cache_key ' )) {
4445 return ;
4546 }
@@ -81,6 +82,7 @@ public function onAfterDelete(): void
8182 // We will want to publish changes to the CacheKey onAfterWrite if the instance triggering this event is *not*
8283 // Versioned (the changes should be seen immediately even though the object wasn't Published)
8384 $ publishUpdates = !$ this ->owner ->hasExtension (Versioned::class);
85+ // Note: doArchive will call deleteFromStage() which will in turn trigger this extension hook
8486 $ this ->owner ->triggerCacheEvent ($ publishUpdates );
8587 CacheKey::remove ($ this ->owner );
8688 }
@@ -90,8 +92,17 @@ public function onAfterPublish(): void
9092 $ this ->owner ->triggerCacheEvent (true );
9193 }
9294
95+ public function onAfterPublishRecursive (): void
96+ {
97+ // This can sometimes be called in the same request as onAfterPublish(), but the duplication of effort is
98+ // minimal since we keep track of which records have been processed
99+ $ this ->owner ->triggerCacheEvent (true );
100+ }
101+
93102 public function onAfterUnpublish (): void
94103 {
104+ // Note: doArchive() will call doUnpublish(), so this extension hook is called when published records are
105+ // archived
95106 $ this ->owner ->triggerCacheEvent (true );
96107 }
97108
@@ -117,47 +128,68 @@ private function findCacheKeyHash(): ?string
117128 return null ;
118129 }
119130
120- $ hasCacheKey = $ this ->owner ->config ()->get ('has_cache_key ' );
121-
122- // You have requested that this DataObject class does not use cache keys
123- if (!$ hasCacheKey ) {
131+ // The configuration for this DataObject has specified that it does not use CacheKeys
132+ if (!$ this ->owner ->config ()->get ('has_cache_key ' )) {
124133 return null ;
125134 }
126135
127- // Find an existing CacheKey, or create a new one for this DataObject
136+ // First we'll try to find this CacheKey in whatever your current Stage is (IE: We'll fetch LIVE records when
137+ // you're in the LIVE reading_mode, and DRAFT records when you're in the DRAFT reading_mode)
138+ $ cacheKey = CacheKey::findInStage ($ this ->owner );
139+
140+ // A key exists in your active Stage, so we can return it immediately
141+ if ($ cacheKey ) {
142+ return $ cacheKey ->KeyHash ;
143+ }
144+
145+ // We know that a CacheKey did not exist in your active Stage (that could have been DRAFT or LIVE). We'll now
146+ // attempt to find an existing CacheKey (specifically in DRAFT), or we'll create a new one
147+
148+ // Given this context, our goal is now to make sure that we have a CacheKey for this record in the appropriate
149+ // Stage. EG: If you are browsing this record in LIVE, then we'd expect to have a published CacheKey
128150 $ cacheKey = CacheKey::findOrCreate ($ this ->owner );
129151
130- // In this context (that being, in a time where we are not actively generating Cache Keys, and are instead just
131- // trying to find them) we will not perform a write() when/if the StagingState indicates that we should not
152+ // Safety first, but there shouldn't really have been a reason for this to be null
153+ if (!$ cacheKey ) {
154+ return null ;
155+ }
156+
157+ // In this context (that being, in a time when we are not actively generating Cache Keys, and are instead just
158+ // trying to find them) we will not write() when/if the StagingState indicates that we should not
159+ // One example is when browsing CMS Previews. We do not save CacheKeys in that context
132160 if (!StagingState::singleton ()->canWrite ()) {
133161 return $ cacheKey ->KeyHash ;
134162 }
135163
136- // Check that our CacheKey has been saved to the Database
164+ // Make sure that our CacheKey is saved to the Database
137165 if (!$ cacheKey ->isInDB ()) {
138- $ cacheKey ->write ();
166+ // We need to make sure that we are specifically writing this with reading mode set to DRAFT. If we write()
167+ // while a user is browsing in a LIVE reading mode, then this CacheKey will be "live" immediately
168+ // @see https://github.com/silverstripe/silverstripe-versioned/issues/382
169+ Versioned::withVersionedMode (static function () use ($ cacheKey ): void {
170+ Versioned::set_stage (Versioned::DRAFT );
171+
172+ $ cacheKey ->write ();
173+ });
139174 }
140175
141- // The Cache Key is already published, so there is nothing left for us to do except return the KeyHash
142- if ($ cacheKey ->isPublished ()) {
176+ // In this context we will not publish() when/if the StagingState indicates that we should not
177+ // Generally, any time we're in a DRAFT reading_mode, we will not publish
178+ if (!StagingState::singleton ()->canPublish ()) {
143179 return $ cacheKey ->KeyHash ;
144180 }
145181
146- // In this context we will not perform a publish() when/if the StagingState indicates that we should not
147- if (!StagingState:: singleton ()-> canPublish ()) {
182+ // The Cache Key is already published, so there is nothing left for us to do except return the KeyHash
183+ if ($ cacheKey -> isPublished ()) {
148184 return $ cacheKey ->KeyHash ;
149185 }
150186
151- // If the owner is not Versioned (essentially meaning that it is *always* published), or if the owner is
152- // currently published, then we want to make sure we publish our CacheKey as well
153- if (!$ this ->owner ->hasExtension (Versioned::class) || $ this ->owner ->isPublished ()) {
154- // Default behaviour is that publish_recursive is disabled. There is only value in using publishRecursive()
155- // if you decide that your CacheKey model needs to $own something
156- if (CacheKey::config ()->get ('publish_recursive ' )) {
157- $ cacheKey ->publishRecursive ();
158- } else {
159- $ cacheKey ->publishSingle ();
160- }
187+ // Default behaviour is that publish_recursive is disabled. There is only value in using publishRecursive()
188+ // if you decide that your CacheKey model needs to $own something
189+ if (CacheKey::config ()->get ('publish_recursive ' )) {
190+ $ cacheKey ->publishRecursive ();
191+ } else {
192+ $ cacheKey ->publishSingle ();
161193 }
162194
163195 return $ cacheKey ->KeyHash ;
0 commit comments