knot-lib/cache

View on GitHub
src/ArrayCache.php

Summary

Maintainability
A
3 hrs
Test Coverage
<?php
declare(strict_types=1);

namespace knotlib\cache;

use knotlib\cache\config\ArrayCacheConfig;
use knotlib\cache\exception\CacheMetaDataException;
use knotlib\cache\util\CacheDataTrait;
use DateInterval;

class ArrayCache implements CacheInterface
{
    use CacheDataTrait;

    /** @var ArrayCacheConfig */
    private $config;

    /** @var array */
    private $data;

    /**
     * FileCacheDriver constructor.
     *
     * @param array $config
     */
    public function __construct(array $config = [])
    {
        $this->config = new ArrayCacheConfig($config);

        $this->data = [];
    }

    /**
     * {@inheritDoc}
     *
     * @throws CacheMetaDataException
     */
    public function get($key, $default = null)
    {
        $cache_info = $this->data[$key] ?? null;

        if ($cache_info === null){
            return $default;
        }

        // check expire date
        $expires = isset($cache_info['expires']) ? intval($cache_info['expires']) : null;
        if ($expires === null){
            throw( new CacheMetaDataException('expires not found') );
        }
        $now = time();
        if ($expires > 0 && $expires < $now){
            return $default;
        }

        // decode data
        $data = $cache_info['data'] ?? null;
        if ($data === null){
            throw( new CacheMetaDataException('data not found') );
        }
        $data = $this->decodeData($data);

        // type check
        $type = $cache_info['type'] ?? null;
        if ($type === null){
            throw( new CacheMetaDataException('type not found') );
        }
        if ($type !== gettype($data)){
            return $default;
        }

        // class check
        if ($type === 'object'){
            $class = $cache_info['class'] ?? null;
            if ($class === null){
                throw( new CacheMetaDataException('class not found') );
            }
            if (!($data instanceof $class)){
                return $default;
            }
        }

        return $data;
    }

    /**
     * {@inheritDoc}
     */
    public function set($key, $value, $ttl = null)
    {
        $cache_info = $this->data[$key] ?? [];

        if ($ttl instanceof DateInterval){
            $ttl = intval($ttl->format('s'));
        }

        $expire = $ttl ? $ttl : $this->config->getExpire();

        // If a negative or zero TTL is provided, the item MUST be deleted from the cache if it exists, as it is expired already.
        if ($expire < 0){
            unset($this->data[$key]);
            return true;
        }

        $expires = $expire > 0 ? time() + $expire : 0;

        $cache_info['expires'] = $expires;
        $cache_info['type'] = gettype($value);
        $cache_info['class'] = is_object($value) ? get_class($value) : '';
        $cache_info['data'] = $this->encodeData($value);

        $this->data[$key] = $cache_info;

        return true;
    }


    /**
     * {@inheritDoc}
     */
    public function delete($key)
    {
        unset($this->data[$key]);
        return true;
    }

    /**
     * Rewrite cache expiration time
     *
     * @param string $key         The key of the item to remove. Shell wildcards are accepted.
     * @param int $duration       specify expiration span which the cache will be removed.
     *
     * @return bool
     *
     */
    public function touch( $key, $duration = NULL )
    {
        $cache_info = $this->data[$key] ?? null;

        if ($cache_info){

            $expire = $this->config->getExpire();
            $expires = $expire > 0 ? time() + $expire : 0;

            $cache_info['expires'] = $expires;

            $this->data[$key] = $cache_info;
        }

        return true;
    }


    /**
     * {@inheritDoc}
     */
    public function clear()
    {
        $this->data = [];
        return true;
    }

    /**
     * {@inheritDoc}
     *
     * @throws CacheMetaDataException
     */
    public function getMultiple($keys, $default = null)
    {
        $ret = [];
        foreach($keys as $key){
            $ret[$key] = $this->get($key, $default);
        }
        return $ret;
    }

    /**
     * {@inheritDoc}
     */
    public function setMultiple($values, $ttl = null)
    {
        $ret = true;
        foreach($values as $key => $value){
            $ret &= $this->set($key, $value, $ttl);
        }
        return $ret;
    }

    /**
     * {@inheritDoc}
     */
    public function deleteMultiple($keys)
    {
        $ret = true;
        foreach($keys as $key){
            $ret &= $this->delete($key);
        }
        return $ret;
    }

    /**
     * {@inheritDoc}
     */
    public function has($key)
    {
        return isset($this->data[$key]);
    }

    /**
     * Returns cache data
     *
     * @return array
     */
    public function toArray() : array
    {
        return $this->data;
    }

}