GithubHelp home page GithubHelp logo

cachelayer-bundle's Introduction

cachelayer-bundle

cache layer for services

install:

  • run composer require skrip42/cachelayer-bundle

base usage:

implement cache interface:

//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) . ']';
    }
}

make cache service is public:

App\Services\Cache\RedisCache:
    public: true

tagged target service as cachable:

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

add annotation to target service methods:

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

additional features:

cache chain

you can add multiple cache annotations, caches will be executed in the specified order

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

custom attribute

you can define additional attributes that will be passed to all cache methods

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

ignored parameters

you can specify parameters that will be ignored during caching

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

conditional execution

You can specify a condition under which cache will be executed

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

cache cleaner

You can specify the method for clearing the cache

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

if you want to clear the cache of another method (for example for setter method), you can add attribute with the method name and modify toy cache class like this:

    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 actualize

You can specify the method for actualize the cache

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

conditional clear and actualize

You can specify a condition under which cache overide action

    /**
     * @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)
    {
        ......

recache method

You can specify recache method thet will be called automatically after clearing the cache

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

CacheManager and CacheAccessor

CacheAccessor allows you to direct control for cache of a specific service

To get CacheAccessor, use static CacheManager:

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

......

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

โš ๏ธ if you use no singleton service, you can get CacheAccessor only for last service instance;

CacheAccessor has the signature:

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

You can define cache without class method and work with it through the CacheManager

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.