Merge pull request #9639 from creative-commoners/pulls/4/embed-performance

NEW Cache embed shortcodes
This commit is contained in:
Garion Herman 2020-08-27 12:15:24 +12:00 committed by GitHub
commit 9aa2642d03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 105 additions and 6 deletions

View File

@ -37,3 +37,8 @@ SilverStripe\Core\Injector\Injector:
factory: SilverStripe\Core\Cache\CacheFactory factory: SilverStripe\Core\Cache\CacheFactory
constructor: constructor:
namespace: 'DatabaseAdapterRegistry' namespace: 'DatabaseAdapterRegistry'
Psr\SimpleCache\CacheInterface.EmbedShortcodeProvider:
factory: SilverStripe\Core\Cache\CacheFactory
constructor:
namespace: 'EmbedShortcodeProvider'
defaultLifetime: 86400

View File

@ -3,7 +3,11 @@
namespace SilverStripe\View\Shortcodes; namespace SilverStripe\View\Shortcodes;
use Embed\Http\DispatcherInterface; use Embed\Http\DispatcherInterface;
use League\Flysystem\Exception;
use Psr\SimpleCache\CacheInterface;
use Psr\SimpleCache\InvalidArgumentException;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Core\Extensible;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\ArrayList; use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\FieldType\DBField; use SilverStripe\ORM\FieldType\DBField;
@ -13,7 +17,6 @@ use SilverStripe\View\Embed\EmbedResource;
use SilverStripe\View\HTML; use SilverStripe\View\HTML;
use SilverStripe\View\Parsers\ShortcodeHandler; use SilverStripe\View\Parsers\ShortcodeHandler;
use Embed\Adapters\Adapter; use Embed\Adapters\Adapter;
use Embed\Embed;
use Embed\Exceptions\InvalidUrlException; use Embed\Exceptions\InvalidUrlException;
use SilverStripe\View\Parsers\ShortcodeParser; use SilverStripe\View\Parsers\ShortcodeParser;
use SilverStripe\Control\Director; use SilverStripe\Control\Director;
@ -59,6 +62,16 @@ class EmbedShortcodeProvider implements ShortcodeHandler
return ''; return '';
} }
// Try to use cached result
$cache = static::getCache();
$key = static::deriveCacheKey($serviceURL);
try {
if ($cache->has($key)) {
return $cache->get($key);
}
} catch (InvalidArgumentException $e) {
}
// See https://github.com/oscarotero/Embed#example-with-all-options for service arguments // See https://github.com/oscarotero/Embed#example-with-all-options for service arguments
$serviceArguments = []; $serviceArguments = [];
if (!empty($arguments['width'])) { if (!empty($arguments['width'])) {
@ -113,13 +126,19 @@ class EmbedShortcodeProvider implements ShortcodeHandler
// Convert embed object into HTML // Convert embed object into HTML
if ($embed && $embed instanceof Adapter) { if ($embed && $embed instanceof Adapter) {
$result = static::embedForTemplate($embed, $arguments); $result = static::embedForTemplate($embed, $arguments);
if ($result) { }
return $result; // Fallback to link to service
if (!$result) {
$result = static::linkEmbed($arguments, $serviceURL, $serviceURL);
}
// Cache result
if ($result) {
try {
$cache->set($key, $result);
} catch (InvalidArgumentException $e) {
} }
} }
return $result;
// Fallback to link to service
return static::linkEmbed($arguments, $serviceURL, $serviceURL);
} }
/** /**
@ -242,4 +261,50 @@ class EmbedShortcodeProvider implements ShortcodeHandler
return $attributes; return $attributes;
} }
/**
* @param ShortcodeParser $parser
* @param string $content
*/
public static function flushCachedShortcodes(ShortcodeParser $parser, string $content): void
{
$cache = static::getCache();
$tags = $parser->extractTags($content);
foreach ($tags as $tag) {
if (!isset($tag['open']) || $tag['open'] != 'embed') {
continue;
}
$url = $tag['content'] ?? $tag['attrs']['url'] ?? null;
if (!$url) {
continue;
}
$key = static::deriveCacheKey($url);
try {
if (!$cache->has($key)) {
continue;
}
$cache->delete($key);
} catch (InvalidArgumentException $e) {
continue;
}
}
}
/**
* @return CacheInterface
*/
private static function getCache(): CacheInterface
{
return Injector::inst()->get(CacheInterface::class . '.EmbedShortcodeProvider');
}
/**
* @param string $url
* @return string
*/
private static function deriveCacheKey(string $url): string
{
$key = 'embed-shortcode-' . preg_replace('/[^a-zA-Z0-9\-]/', '', $url);
return $key;
}
} }

View File

@ -2,6 +2,8 @@
namespace SilverStripe\View\Tests\Shortcodes; namespace SilverStripe\View\Tests\Shortcodes;
use Psr\SimpleCache\CacheInterface;
use SilverStripe\View\Parsers\ShortcodeParser;
use SilverStripe\View\Shortcodes\EmbedShortcodeProvider; use SilverStripe\View\Shortcodes\EmbedShortcodeProvider;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
@ -119,4 +121,31 @@ EOS
] ]
); );
} }
public function testFlushCachedShortcodes()
{
/** @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" />';
$parser = ShortcodeParser::get('default');
// 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]);
// assertions
$this->assertEquals('embed-shortcode-httpwwwtest-servicecomabc123', $key);
$cache->set($key, $embedHtml);
$this->assertTrue($cache->has($key));
EmbedShortcodeProvider::flushCachedShortcodes($parser, $content);
$this->assertFalse($cache->has($key));
}
} }