Skip to content

[HttpKernel] Cache component based HttpCache Store #48304

@shyim

Description

@shyim

Description

Currently, the HttpCache Class has only one Store which saves the Cache on the Disk directly.
It would be nice to have an adapter which uses normal Symfony Caching. So you could save your Cache on Redis/Memcached and so. This is also easier if you have multiple servers

We could also use the TagAwareAdapter and allow the Users to tag the cache by adding a symfony response header to the Response object. So when they call on their adapter invalidate their normal cache and the http cache will be gone (If the caching adapter is the same)

Example

I made here an example of an CacheStore using AdapterInterface + LockFactory to have locking.

<?php

namespace Symfony\Component\HttpKernel\HttpCache;

use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Lock\Lock;
use Symfony\Component\Lock\LockFactory;

class CacheStore implements StoreInterface
{
    private ?Lock $lock = null;

    public function __construct(private readonly AdapterInterface $cache, private readonly LockFactory $lockFactory)
    {
    }

    public function lookup(Request $request): ?Response
    {
        $cacheKey = $this->generateCacheKey($request);

        $item = $this->cache->getItem($cacheKey);

        if (!$item->isHit()) {
            return null;
        }

        return $item->get();
    }

    public function write(Request $request, Response $response): string
    {
        $cacheKey = $this->generateCacheKey($request);

        $item = $this->cache->getItem($cacheKey);
        $item->set($response);

        $this->cache->save($item);

        return $cacheKey;
    }

    public function invalidate(Request $request)
    {
        $this->cache->deleteItem($this->generateCacheKey($request));
        // TODO: Implement invalidate() method.
    }

    public function lock(Request $request): bool|string
    {
        $this->lock = $this->lockFactory->createLock($this->generateCacheKey($request));
        $this->lock->acquire();

        return true;
    }

    public function unlock(Request $request): bool
    {
        if ($this->lock) {
            $this->lock->release();
            $this->lock = null;
        }

        return true;
    }

    public function isLocked(Request $request): bool
    {
        if ($this->lock) {
            return $this->lock->isAcquired();
        }

        return false;
    }

    public function purge(string $url): bool
    {
        $this->invalidate(Request::create($url));

        return true;
    }

    public function cleanup()
    {
        if ($this->lock) {
            $this->lock->release();
            $this->lock = null;
        }
    }

    protected function generateCacheKey(Request $request): string
    {
        return 'md'.hash('sha256', $request->getUri());
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions