skrip42/cachelayer-bundle

Symfony 缓存层包

v1.2.7 2020-11-19 06:06 UTC

This package is auto-updated.

Last update: 2024-09-10 11:38:16 UTC


README

服务缓存层

安装

  • 运行 composer require skrip42/cachelayer-bundle

基本用法

实现缓存接口

//redis cache example
namespace App\Services\Cache;

use Skrip42\Bundle\CacheLayerBundle\CacheInterface;
use App\Services\Redis;

class RedisCache implements CacheInterface
{
    private $client;

    /** @required */
    public function setRedisClient(...)
    {
        //inject you redis client
    }

    /**
     * Check is cache exist value
     *
     * @param mixed  $instance  request service instance
     * @param string $method    request method
     * @param array  $params    request params
     * @param array  $attr      custom attribute
     *
     * @return bool
     */
    public function has(
        $instance,
        string $method,
        array $params,
        array $attr
    ) : bool {
        return $this->client->exists(
            $this->getKey($instance, $method, $params)
        );
    }

    /**
     * Get value from cache
     *
     * @param mixed  $instance  request service instance
     * @param string $method    request method
     * @param array  $params    request params
     * @param array  $attr      custom attribute
     *
     * @return mixed
     */
    public function get(
        $instance,
        string $method,
        array $params,
        array $attr
    ) {
        return unserialize($this->client->get(
            $this->getKey($instance, $method, $params)
        ));
    }

    /**
     * Set data to cache
     *
     * @param mixed  $instance  request service instance
     * @param string $method    request method
     * @param array  $params    request params
     * @param mixed  $data      service return value
     * @param array  $attr      custom attribute
     */
    public function set(
        $instance,
        string $method,
        array $params,
        $data,
        array $attr
    ) {
        $ttl = empty($attr['ttl']) ? 0 : $attr['ttl'];
        $this->client->setex(
            $this->getKey($instance, $method, $params),
            $ttl,
            serialize($data)
        );
    }
    /**
     * Clear cache
     *
     * @param mixed  $instance  request service instance
     * @param string $method    request method
     * @param array  $params    request params
     * @param array  $attr      custom attribute
     */
    public function clear(
        $instance,
        string $method,
        array $params,
        array $attr
    ) {
        $pattern = get_class($instance) . '::' . $method . '*';
        $pattern = str_replace('\\', '\\\\', $pattern); //escape '\'
        $keys = $this->client->keys($pattern);
        $this->client->del($keys);
    }

    public function getKey($instance, string $method, array $params) : string
    {
        return get_class($instance) . '::' . $method . '[' . serialize($params) . ']';
    }
}

使缓存服务公开

App\Services\Cache\RedisCache:
    public: true

将目标服务标记为可缓存

App\Services\TargetService:
    tags: [skrip42.cachelayer]

为目标服务方法添加注解

     /**
      * @Cache(
      *      RedisCache::class,
      *      attribute = {
      *          "ttl" = 900
      *      }
      * )
      */
    public function foo(...) {
        //do something
    }

附加功能

缓存链

您可以添加多个缓存注解,缓存将按照指定的顺序执行

    /**
     * @Cache(LocalCache::class) //execute first
     * @Cache(RedisCache::class) //if LocalCache exist value, RedisCache will not be called
     */
    public function foo(...)
    {
        .....

自定义属性

您可以定义将传递给所有缓存方法的附加属性

    /**
     * @Cache(
     *      RedisCache::class,
     *      attribute = {
     *          "ttl" = 900 //this attribute will be passed to all method of RedisCache
     *      }
     * )
     */
    public function foo(...)
    {
        .....

忽略参数

您可以指定在缓存过程中将被忽略的参数

    /**
     * @Cache(
     *      RedisCache::class,
     *      ignore_params = {
     *          "param"
     *      }
     * )
     */
    public function foo(bool $param) // the cache for foo (three) is the same as for foo (false)
    {
        .....

条件执行

您可以指定在什么条件下缓存将被执行

    /**
     * @Cache(
     *      RedisCache::class,
     *      condition = {
     *          "nocache" = false // execute only if $nocache = false
     *      }
     * )
     */
    public function foo(bool $nocache = false)

缓存清理器

您可以指定清理缓存的策略

    /**
     * @Cache(
     *      RedisCache::class,
     *      attribute = {
     *          "target" = "getData"
     *      }
     *      action = "clear" //cache chear method will be called when setData is called
     * )
     */
    public function setData(...)

如果您想清理另一个方法(例如设置方法)的缓存,您可以添加具有方法名称的属性,并修改您的缓存类如下

    public function clear(
        $instance,
        string $method,
        array $params,
        array $attr
    ) {
        if (!empty($attr['target'])) {
            $pattern = get_class($instance) . '::' . $attr['target'] . '*';
        } else {
            $pattern = get_class($instance) . '::' . $method . '*';
        }
        ...

缓存更新

您可以指定更新缓存的策略

    /**
     * @Cache(
     *      RedisCache::class,
     *      action = "actualize" //cache chear method will be called when setData is called
     * )
     */
    public function setData(...)

条件清除和更新

您可以指定在什么条件下缓存覆盖操作

    /**
     * @Cache(
     *      RedisCache::class,
     *      actualize_condition = { //cache willbe actualize when foo is called eitch $actualize = true parameters
     *          "actualize" = true
     *      },
     *      clear_condition = { //cache chear method will be called when foo is called witch $clear = true parameters
     *          "clear" = true
     *      },
     *      ignore_params = {
     *          "clear", "actualize"
     *      }
     * )
     */
    public function foo(bool $clear, bool $actualize)
    {
        ......

重新缓存方法

您可以指定在清除缓存后自动调用的重新缓存方法

```php
    /**
     * @Cache(
     *      RedisCache::class,
     *      attribute = {
     *          "target" = "getData"
     *      }
     *      action = "clear",
     *      recache_method = "recacheData" // recacheData(...) will be called after cache clear
     * )
     */
    public function setData(...)

CacheManager 和 CacheAccessor

CacheAccessor 允许您直接控制特定服务的缓存

要获取 CacheAccessor,请使用静态 CacheManager

use Skrip42\Bundle\CacheLayerBundle\CacheManager;
use App\Services\SomeClass;

......

$cacheAccessor = CacheManager::getBy(SomeClass::class); //return CacheAccessor instance

⚠️ 如果您没有使用单例服务,您只能为最后一个服务实例获取 CacheAccessor;

CacheAccessor 的签名

class CacheAccessor
{
    has(string $methodName, array $params = [], array $attr = []) : bool;
    find(string $methodName, array $params = [], array $attr = []) : array; //return array of CacheInterface witch the value is founded;
    get(string $methodName, array $params = [], array $attr = []);
    set(string $methodName, $data, $params = [], array $attr = []);
    clear(string $methodName, $params = [], array $attr = []);

    getLayer(string $cacheServiceName) : CacheAccessor; //return cache accessor for specific cache class (get RedisCache only for example)
    getCacheMap() : array; //return cache map schem for current object
}

AdditionalCache

您可以通过 CacheManager 定义缓存,而无需类方法,并通过它进行操作

/**
 * @AdditionalCache(
 *      "additionalCacheName", //virtual method name
 *      layers = {             //cache layers
 *          @Cache(RedisCache::class, attribute={"ttl" = 86400}) //just @Cache annotation
 *      }
 * )
 */
class SomeClass
{
....