Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add InvalidateElementCachesEvent that fires when element TagDependency caches are invalidated #11617

Merged

Conversation

khalwat
Copy link
Contributor

@khalwat khalwat commented Jul 18, 2022

Description

This PR adds an InvalidateElementCachesEvent that is triggered by three methods in the Elements service:

  • invalidateAllCaches()
  • invalidateCachesForElementType()
  • invalidateCachesForElement()

These methods are bottleneck methods that are called from a wide variety of places in the codebase whenever an element's caches need to be invalidated.

The event has a $tags property that is an array of TagDependency tag names that are being invalidated, so the listener can take an action when the caches are invalidated. Otherwise, there is no way to know when an Element's caches have been invalidated because the TagDependency information is stored appended to the cached data via whatever the current caching method is.

Throwing these events will greatly simplify implementing a variety of middleware that needs to know when an element's caches have been invalidated. Example usage:

        // Listen for invalidated element caches
        Event::on(
            Elements::class,
            Elements::EVENT_INVALIDATE_ELEMENT_CACHES,
            static function (InvalidateElementCachesEvent $event) {
                $tags = $event->tags;
                // Do something with the $tags
            }
        );

Plugins like Blitz, Upper, and others that deal with cache invalidation would benefit from this, rather than having to roll their own solution.

These events are intentionally agnostic; you'd layer something useful on top of them. A common use-case would be to use these events in conjunction with something like:

        if (Craft::$app->getRequest()->getIsSiteRequest()) {
            // Start collecting cache tags
            Event::on(
                View::class,
                View::EVENT_BEFORE_RENDER_PAGE_TEMPLATE,
                static function (TemplateEvent $event) {
                    Craft::$app->getElements()->startCollectingCacheTags();
                }
            );
            // Stop collecting cache tags
            Event::on(
                View::class,
                View::EVENT_AFTER_RENDER_PAGE_TEMPLATE,
                static function (TemplateEvent $event) {
                    $tags = Craft::$app->getElements()->stopCollectingCacheTags();

                }
            );
        }

...so that you can collect the element caches on a given page, and when those events fire, do whatever you need to do to invalidate them.

In my case, I will be using a custom db table to store the rendering page's URI in conjunction with a JSON column type that has the array of TagDependency tag names, so whenever a tag is invalidated, I can do a reverse lookup to find all of the affected URIs.

shinybrad and others added 22 commits July 14, 2022 06:03
# Conflicts:
#	src/services/Deprecator.php
#	src/services/TemplateCaches.php
#	src/web/ErrorHandler.php
@brandonkelly
Copy link
Member

4.2.0 is out now with that event ✨

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants