phpcachingshopware6

Invalidate Shopware 6 page cache on entity update via API


We created a custom CMS element which displays entries which are managed via API.

Now when entries are updated and Shopware 6 runs ins production mode, the changes are not reflected on the page. I believe this is due to the page cache. (APP_ENV=prod)

What do we have to do to invalidate the cache automatically?

I checked the docs, but did not find the necessary information.

For the product box it works: When I place a product CMS element on the main page and change the product, the page is updated when I reload in the browser. I was expecting to find some hint in \Shopware\Core\Content\Product\Cms\ProductBoxCmsElementResolver but there are no cache tags or something like this added there.

EDIT: Actually I was a bit inaccurate. The page I have lists the entities, and it is a category page.

So I believe I have too hook into CategoryRouteCacheTagsEvent.

For testing I hard-coded into:

\Shopware\Core\Content\Category\SalesChannel\CachedCategoryRoute::extractProductIds

    $slots = $page->getElementsOfType('jobs');
    /** @var CmsSlotEntity $slot */
    foreach ($slots as $slot) {
        $box = $slot->getData();
        $ids = array_merge($ids, $box['jobs']->getIds());
    }

But this does not yet work.

PS: Also I noticed some code duplication in the core in \Shopware\Core\Content\Category\SalesChannel\CachedCategoryRoute::extractProductIds and \Shopware\Core\Content\LandingPage\SalesChannel\CachedLandingPageRoute::extractIds


Solution

  • Based on the answers of dneustadt and Uwe, as for the job listings I solved it like with this two subscribes. I do not need any single ID here, because the full listing page has to be invalidated in case a job is deleted or added. This is why I went with the any-jobs tag:

    use Shopware\Core\Content\Category\Event\CategoryRouteCacheTagsEvent;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    
    class CacheKeyEventSubscriber implements EventSubscriberInterface
    {
        public static function getSubscribedEvents(): array
        {
        return [
            CategoryRouteCacheTagsEvent::class => 'generateTags'
        ];
        }
    
        public function generateTags(CategoryRouteCacheTagsEvent $event): void
        {
        $page = $event->getResponse()->getCategory()->getCmsPage();
        $slots = $page->getElementsOfType('jobs');
        if (!empty($slots)) {
            $event->setTags(
                array_merge($event->getTags(), ['any-jobs'])
            );
        }
        }
    }
    

    and

    class CacheInvalidationSubscriber implements EventSubscriberInterface
    {
        private CacheInvalidator $cacheInvalidator;
    
        public static function getSubscribedEvents(): array
        {
        return [
            EntityWrittenContainerEvent::class => 'invalidateJobs'
        ];
        }
    
        public function __construct(CacheInvalidator $cacheInvalidator)
        {
        $this->cacheInvalidator = $cacheInvalidator;
        }
    
    
        public function invalidateJobs(EntityWrittenContainerEvent $event): void
        {
        if (!empty($event->getPrimaryKeys(\ApplicationManagement\Core\Content\JobAd\JobAdDefinition::ENTITY_NAME))) {
            $this->cacheInvalidator->invalidate(
                ['any-jobs']
            );
        }
        }
    }