phpsymfonysymfony-cache

Advanced using of the PSR-6 cache in Symfony


I need to move the data from a relation database into a Redis store for further manipulations. I'm using the Symfony PSR-16 cache implementation with the Redis adapter for this and have 2 types of items in my cache pool:

  1. The first cache item type maps some hash onto the primary key of a record from the relational database, the item key looks like hash.[the hash value] and the item's value is the primary key accordingly.
  2. The second cache item type has the key like [table name].[primary key]

Now I need to loop through the items of the first type, take the the primary keys from them and fetch the items of the second type using these PKs.

Is it at all possible with the Symfony cache or I need to make some service working with Redis directly for a more flexible approach?

Is it possible to fetch Symfony cache items using regular expressions or tags?


Solution

  • I just created my own cache adapter allowing to fetch cache items by a pattern, it uses the redis SCAN instruction:

    use Symfony\Component\Cache\Traits\{
        RedisProxy, RedisTrait
    };
    use Symfony\Component\Cache\Adapter\AbstractAdapter;
    use Generator;
    
    /**
     * Class RedisAdapter
     * Advanced redis adapter with the ability to fetch items using expressions
     * @package App\Cache
     */
    class RedisAdapter extends AbstractAdapter
    {
        use RedisTrait;
    
        /**
         * @var RedisProxy
         */
        private $redis;
    
        /**
         * @var string
         */
        private $namespace;
    
        /**
         * @var int
         */
        private $namespaceLen;
    
        public function __construct($redisClient, string $namespace = '', int $defaultLifetime = 0)
        {
            $this->init($redisClient, $namespace, $defaultLifetime);
            $this->namespace = $namespace . ':';
            $this->namespaceLen = strlen($this->namespace);
        }
    
        /**
         * Get all cache items by pattern
         * @param string $pattern
         * @return Generator
         */
        public function getItemsByPattern(string $pattern): Generator
        {
            $iterator = null;
            $pattern = $this->prependNamespace($pattern);
    
            while ($keys = $this->redis->scan($iterator, $pattern)) {
                foreach ($this->getItems($this->cleanupNamespace($keys)) as $item) {
                    yield $item;
                }
            }
        }
    
        /**
         * Add a namespace to the key
         * @param string $key
         * @return string
         */
        private function prependNamespace(string $key): string
        {
            return $this->namespace . $key;
        }
    
        /**
         * Cleanup the namespace
         * @param array $keys
         * @return array
         */
        private function cleanupNamespace(array $keys)
        {
            $keys = array_map(function ($value) {
                return substr($value, $this->namespaceLen);
            }, $keys);
    
            return $keys;
        }
    }