From e0defe3c2d8d90a5f2206afaea482a4b5e3f201e Mon Sep 17 00:00:00 2001 From: Kenny Quan Date: Thu, 16 Jan 2020 15:35:59 -0800 Subject: [PATCH] CloudFront option added to Clear Cache utility, globals and categories now purge all caches --- .craftplugin | 2 +- README.md | 6 ++++ composer.json | 2 +- src/CloudFrontPurge.php | 78 +++++++++++++++++++++++++++++++++++------ 4 files changed, 76 insertions(+), 12 deletions(-) diff --git a/.craftplugin b/.craftplugin index 0a99d47..c60f4b7 100644 --- a/.craftplugin +++ b/.craftplugin @@ -1 +1 @@ -{"pluginName":"CloudFront Purge","pluginDescription":"Invalidate the CloudFront cache on entry save","pluginVersion":"1.0.4","pluginAuthorName":"Kenny Quan","pluginVendorName":"kayqq","pluginAuthorUrl":"https://www.kennyquan.com","pluginAuthorGithub":"kayqq","codeComments":"yes","pluginComponents":["settings"],"consolecommandName":"","controllerName":"","cpsectionName":"","elementName":"","fieldName":"","modelName":"","purchasableName":"","recordName":"","serviceName":"","taskName":"","utilityName":"","widgetName":"","apiVersion":"api_version_3_0"} \ No newline at end of file +{"pluginName":"CloudFront Purge","pluginDescription":"Invalidate the CloudFront cache on entry save","pluginVersion":"1.0.5","pluginAuthorName":"Kenny Quan","pluginVendorName":"kayqq","pluginAuthorUrl":"https://www.kennyquan.com","pluginAuthorGithub":"kayqq","codeComments":"yes","pluginComponents":["settings"],"consolecommandName":"","controllerName":"","cpsectionName":"","elementName":"","fieldName":"","modelName":"","purchasableName":"","recordName":"","serviceName":"","taskName":"","utilityName":"","widgetName":"","apiVersion":"api_version_3_0"} \ No newline at end of file diff --git a/README.md b/README.md index 0b32ec7..60173e9 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,12 @@ Note: IAM role permissions must be configured to allow for invalidation creation Source: [aws.amazon.com/cloudfront/pricing](https://aws.amazon.com/cloudfront/pricing/) +Entries on save will invalidate themselves if their uri exists (e.g., `/blog/xyz`). + +Globals & Categories on save will invalidate the entire site (e.g., `/*` invalidation path). + +There is also a cache option to purge CloudFront under Craft's Clear Cache Utility. + ## CloudFront Purge Roadmap - Release it diff --git a/composer.json b/composer.json index f89bb21..a4fe88d 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "kayqq/craft-cloudfront-purge", "description": "A Craft CMS 3.x plugin that enables automatic Cloudfront Cache invalidation on entry save", "type": "craft-plugin", - "version": "1.0.4", + "version": "1.0.5", "keywords": [ "craft", "cms", diff --git a/src/CloudFrontPurge.php b/src/CloudFrontPurge.php index 7dfcbe8..f69aef9 100644 --- a/src/CloudFrontPurge.php +++ b/src/CloudFrontPurge.php @@ -22,10 +22,12 @@ use Craft; use craft\base\Plugin; use craft\events\ElementEvent; +use craft\events\RegisterCacheOptionsEvent; use craft\services\Elements; use craft\helpers\StringHelper; use craft\helpers\ElementHelper; use craft\behaviors\EnvAttributeParserBehavior; +use craft\utilities\ClearCaches; use yii\base\Event; @@ -73,7 +75,7 @@ class CloudFrontPurge extends Plugin * * @var string */ - public $schemaVersion = '1.0.4'; + public $schemaVersion = '1.0.5'; // Public Methods // ========================================================================= @@ -99,18 +101,49 @@ public function init() Elements::EVENT_AFTER_SAVE_ELEMENT, function (ElementEvent $event) { $element = $event->element; - if ( - $element instanceof \craft\elements\Entry // is entry - && $element->uri // has a uri - && !ElementHelper::isDraftOrRevision($element) // is not draft or revision - && !$element->propagating // not during propagating (avoid batch propagating) - && !$element->resaving // not during resaving (avoid batch resaving) - ) { - $this->invalidateCdnPath($element->uri); + + switch (true) { + case $element instanceof \craft\elements\Entry: + if ( + $element->uri // has a uri + && !ElementHelper::isDraftOrRevision($element) // is not draft or revision + && !$element->propagating // not during propagating (avoid batch propagating) + && !$element->resaving // not during resaving (avoid batch resaving) + ) { + $this->invalidateCdnPath('/' . $this->_cfPrefix() . ltrim($element->uri, '/') . $this->_cfSuffix()); + } + break; + case $element instanceof \craft\elements\Category: + case $element instanceof \craft\elements\GlobalSet: + if ( + !ElementHelper::isDraftOrRevision($element) + && !$element->propagating // not during propagating (avoid batch propagating) + && !$element->resaving // not during resaving (avoid batch resaving) + ) { + $this->invalidateCdnPath('/*'); + } + break; } } ); + // Handler: ClearCaches::EVENT_REGISTER_CACHE_OPTIONS + Event::on( + ClearCaches::class, + ClearCaches::EVENT_REGISTER_CACHE_OPTIONS, + function (RegisterCacheOptionsEvent $event) { + Craft::debug( + 'ClearCaches::EVENT_REGISTER_CACHE_OPTIONS', + __METHOD__ + ); + // Register our Cache Options + $event->options = array_merge( + $event->options, + $this->customAdminCpCacheOptions() + ); + } + ); + /** * Logging in Craft involves using one of the following methods: * @@ -157,6 +190,15 @@ public function behaviors() return $behaviors; } + /** + * Clear all the caches! + */ + public function purgeAll() + { + // Clear all of CloudFront's caches + $this->invalidateCdnPath('/*'); + } + /** * Build the config array based on a keyID and secret * @@ -223,7 +265,7 @@ protected function invalidateCdnPath(string $path): bool 'Paths' => [ 'Quantity' => 1, - 'Items' => ['/' . $this->_cfPrefix() . ltrim($path, '/') . $this->_cfSuffix()] + 'Items' => [$path] ], 'CallerReference' => 'Craft-' . StringHelper::randomString(24) ] @@ -238,6 +280,22 @@ protected function invalidateCdnPath(string $path): bool return true; } + /** + * Returns the custom Control Panel cache options. + * + * @return array + */ + protected function customAdminCpCacheOptions(): array + { + return [ + [ + 'key' => 'cloudfront-edge-caches', + 'label' => 'CloudFront Edge Caches', + 'action' => [self::$plugin, 'purgeAll'], + ], + ]; + } + /** * Creates and returns the model used to store the plugin’s settings. *