FIX Flush embed shortcode provider cache on SiteTree write

This commit is contained in:
Steve Boyd 2020-08-26 10:13:39 +12:00
parent 956478db83
commit c5a96a2a87
2 changed files with 61 additions and 0 deletions

View File

@ -70,6 +70,7 @@ use SilverStripe\View\ArrayData;
use SilverStripe\View\HTML;
use SilverStripe\View\Parsers\ShortcodeParser;
use SilverStripe\View\Parsers\URLSegmentFilter;
use SilverStripe\View\Shortcodes\EmbedShortcodeProvider;
use SilverStripe\View\SSViewer;
/**
@ -1607,6 +1608,24 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
if ($oneChangedFields && !array_diff($changedFields, $fieldsIgnoredByVersioning)) {
$this->setNextWriteWithoutVersion(true);
}
// Flush cached [embed] shortcodes
// Flush on both DRAFT and LIVE because VersionedCacheAdapter has separate caches for both
// Clear both caches at once for the scenario where a CMS-author updates a remote resource
// on a 3rd party service and the url for the resource stays the same. Either saving or publishing
// the page will clear both caches. This allow a CMS-author to clear the live cache by only
// saving the draft page and not publishing any changes they may not want live yet.
$parser = ShortcodeParser::get('default');
foreach ([Versioned::DRAFT, Versioned::LIVE] as $stage) {
Versioned::withVersionedMode(function () use ($parser, $stage) {
Versioned::set_reading_mode("Stage.$stage");
// $this->Content may be null on brand new SiteTree objects
if (!$this->Content) {
return;
}
EmbedShortcodeProvider::flushCachedShortcodes($parser, $this->Content);
});
}
}
/**

View File

@ -4,6 +4,7 @@ namespace SilverStripe\CMS\Tests\Model;
use LogicException;
use Page;
use Psr\SimpleCache\CacheInterface;
use ReflectionMethod;
use SilverStripe\CMS\Model\RedirectorPage;
use SilverStripe\CMS\Model\SiteTree;
@ -30,6 +31,7 @@ use SilverStripe\Versioned\Versioned;
use SilverStripe\View\Parsers\Diff;
use SilverStripe\View\Parsers\ShortcodeParser;
use SilverStripe\View\Parsers\URLSegmentFilter;
use SilverStripe\View\Shortcodes\EmbedShortcodeProvider;
use TractorCow\Fluent\Extension\FluentSiteTreeExtension;
use const RESOURCES_DIR;
@ -1691,4 +1693,44 @@ class SiteTreeTest extends SapphireTest
$pages = $record->DependentPages();
$this->assertCount(0, $pages, 'Unsaved pages should have no dependent pages');
}
public function testOnBeforeWriteClearsEmbedShortcodeCache()
{
/** @var CacheInterface $cache */
$url = 'http://www.test-service.com/abc123';
$content = '<p>Some content with an [embed url="' . $url . '" thumbnail="https://example.com/mythumb.jpg" ' .
'class="leftAlone ss-htmleditorfield-file embed" width="480" height="270"]' . $url . '[/embed]</p>';
$embedHtml = '<iframe myattr="something" />';
// use reflection to access private methods
$provider = new EmbedShortcodeProvider();
$reflector = new \ReflectionClass(EmbedShortcodeProvider::class);
$method = $reflector->getMethod('getCache');
$method->setAccessible(true);
$cache = $method->invokeArgs($provider, []);
$method = $reflector->getMethod('deriveCacheKey');
$method->setAccessible(true);
$key = $method->invokeArgs($provider, [$url]);
// Set cache (VersionedCacheAdapter) on both DRAFT and LIVE
foreach ([Versioned::DRAFT, Versioned::LIVE] as $stage) {
Versioned::withVersionedMode(function () use ($cache, $key, $embedHtml, $stage) {
Versioned::set_reading_mode("Stage.$stage");
$cache->set($key, $embedHtml);
});
}
// Create new page on DRAFT
$page = SiteTree::create();
$page->Content = $content;
$page->write();
// Assert both DRAFT and LIVE caches were cleared on DRAFT $page->write()
foreach ([Versioned::DRAFT, Versioned::LIVE] as $stage) {
Versioned::withVersionedMode(function () use ($cache, $key, $stage) {
Versioned::set_reading_mode("Stage.$stage");
$this->assertFalse($cache->has($key));
});
}
}
}