412 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			412 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace dominion\cache;
 | 
						|
 | 
						|
use Yii;
 | 
						|
 | 
						|
class RedisCache
 | 
						|
{
 | 
						|
 | 
						|
    /**
 | 
						|
     * используется для отключения кеширования
 | 
						|
     * например при реиндексе или дебаге
 | 
						|
     * @var type
 | 
						|
     */
 | 
						|
    protected static $active = true;
 | 
						|
 | 
						|
    /**
 | 
						|
     * время жизни кеша в секундах
 | 
						|
     * @var int
 | 
						|
     */
 | 
						|
    protected static $livetime;
 | 
						|
 | 
						|
    /**
 | 
						|
     * начальная директория для кеша в редисе
 | 
						|
     * @var type
 | 
						|
     */
 | 
						|
    protected static $prefix;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Время чкрез ктр удалить кешь
 | 
						|
     * @var int
 | 
						|
     */
 | 
						|
    protected static $keysDeleteTime = 30;
 | 
						|
    protected static $setDeleteKey = false;
 | 
						|
 | 
						|
    public static function setActive($active)
 | 
						|
    {
 | 
						|
        self::$active = $active;
 | 
						|
    }
 | 
						|
 | 
						|
    public static function getActive()
 | 
						|
    {
 | 
						|
        return self::$active;
 | 
						|
    }
 | 
						|
 | 
						|
    public static function setDeleteKeyValue($setDeleteKey)
 | 
						|
    {
 | 
						|
        self::$setDeleteKey = $setDeleteKey;
 | 
						|
    }
 | 
						|
 | 
						|
    protected static function livetime()
 | 
						|
    {
 | 
						|
        if (!self::$livetime)
 | 
						|
        {
 | 
						|
            self::$livetime = isset(Yii::$app->params['redis'], Yii::$app->params['redis']['livetime']) ? (int) Yii::$app->params['redis']['livetime'] : 15*60;
 | 
						|
        }
 | 
						|
        return self::$livetime;
 | 
						|
    }
 | 
						|
 | 
						|
    protected static function prefix()
 | 
						|
    {
 | 
						|
        if (!self::$prefix)
 | 
						|
        {
 | 
						|
            self::$prefix = isset(Yii::$app->redis->parameters, Yii::$app->redis->parameters['prefix']) ? Yii::$app->redis->parameters['prefix'] : '';
 | 
						|
        }
 | 
						|
        return self::$prefix;
 | 
						|
    }
 | 
						|
 | 
						|
    public static function hdel($key, $value)
 | 
						|
    {
 | 
						|
        if (self::$setDeleteKey)
 | 
						|
        {
 | 
						|
            self::addDeleteKey($key, $value);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            Yii::$app->redis->hdel($key, $value);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public static function del($key, $realDelete = false)
 | 
						|
    {
 | 
						|
        if (self::$setDeleteKey && !$realDelete)
 | 
						|
        {
 | 
						|
            self::addDeleteKey($key);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            Yii::$app->redis->del($key);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public static function hset($key, $field, $value)
 | 
						|
    {
 | 
						|
        return self::getActive() ? Yii::$app->redis->hset($key, $field, json_encode($value)) : false;
 | 
						|
    }
 | 
						|
 | 
						|
    public static function hsetModel($key, $field, $model)
 | 
						|
    {
 | 
						|
        return self::hset($key, $field, is_object($model) ? $model->attributes : null);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     *
 | 
						|
     * @param type $key
 | 
						|
     * @param type $field
 | 
						|
     * @param type $modelArray
 | 
						|
     * @param type $page родительская модель (используется для пагинации)
 | 
						|
     * @return type
 | 
						|
     */
 | 
						|
    public static function hsetModelArray($key, $field, $modelArray, $page = null)
 | 
						|
    {
 | 
						|
        $values = [];
 | 
						|
        foreach ($modelArray as $model)
 | 
						|
        {
 | 
						|
            $values[] = $model->attributes;
 | 
						|
        }
 | 
						|
        if ($page)
 | 
						|
        {
 | 
						|
            $values['page'] = [
 | 
						|
                'totalCount' => $page->totalCount,
 | 
						|
                'perPage' => $page->perPage,
 | 
						|
                'sort' => $page->sort,
 | 
						|
            ];
 | 
						|
            $field .= ":page:{$page->page}:perPage:{$page->perPage}:sort:{$page->sort}";
 | 
						|
        }
 | 
						|
        return self::hset($key, $field, $values);
 | 
						|
    }
 | 
						|
 | 
						|
    public static function hget($key, $field)
 | 
						|
    {
 | 
						|
        $output = false;
 | 
						|
        if(self::getActive())
 | 
						|
        {
 | 
						|
            $output = json_decode(Yii::$app->redis->hget($key, $field), true);
 | 
						|
        }
 | 
						|
        return $output === null ? false : $output;;
 | 
						|
    }
 | 
						|
 | 
						|
    public static function hgetModel($key, $field, $className)
 | 
						|
    {
 | 
						|
        $value = self::hget($key, $field);
 | 
						|
        return empty($value) ? $value : (new $className($value));
 | 
						|
    }
 | 
						|
 | 
						|
    public static function hgetModelArray($key, $field, $className, $page = null)
 | 
						|
    {
 | 
						|
        if ($page)
 | 
						|
        {
 | 
						|
            $field .= ":page:{$page->page}:perPage:{$page->perPage}:sort:{$page->sort}";
 | 
						|
        }
 | 
						|
        $values = self::hget($key, $field);
 | 
						|
        if ($values === false)
 | 
						|
        {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        $ids = [];
 | 
						|
        foreach ($values as $keyVal => $value)
 | 
						|
        {
 | 
						|
            if ($keyVal !== 'page' && isset($value['id']))
 | 
						|
            {
 | 
						|
                $ids[] = $value['id'];
 | 
						|
            }
 | 
						|
        }
 | 
						|
        $output = [];
 | 
						|
        foreach ($values as $keyVal => $value)
 | 
						|
        {
 | 
						|
            if ($keyVal === 'page')
 | 
						|
            {
 | 
						|
                if ($page)
 | 
						|
                {
 | 
						|
                    $page->setMeta($value['totalCount'], $value['perPage']);
 | 
						|
                    $page->sort = $value['sort'];
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                $model = new $className($value);
 | 
						|
                if (isset($model->ids))
 | 
						|
                {
 | 
						|
                    $model->ids = $ids;
 | 
						|
                }
 | 
						|
                $output[] = $model;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return $output;
 | 
						|
    }
 | 
						|
 | 
						|
    public static function delete($key, array $patterns)
 | 
						|
    {
 | 
						|
        if (self::getActive())
 | 
						|
        {
 | 
						|
            foreach ($patterns as $pattern)
 | 
						|
            {
 | 
						|
                $cursor = 0;//NULL;
 | 
						|
                foreach ($patterns as $pattern)
 | 
						|
                {
 | 
						|
                    $arKeys = [];
 | 
						|
                    while ($values = Yii::$app->redis->hscan($key, $cursor, $pattern))
 | 
						|
                    {
 | 
						|
                        foreach ($values as $vkey => $value)
 | 
						|
                        {
 | 
						|
                            $arKeys[] = $vkey;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    foreach ($arKeys as $value)
 | 
						|
                    {
 | 
						|
                        self::hdel($key, $value);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * удаление одного элемента
 | 
						|
     * @param type $key
 | 
						|
     * @return type
 | 
						|
     */
 | 
						|
    public static function deleteAll($key, $realDelete = false)
 | 
						|
    {
 | 
						|
        if (self::getActive())
 | 
						|
        {
 | 
						|
            self::del($key, $realDelete);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public static function getKeyTypes()
 | 
						|
    {
 | 
						|
 | 
						|
        $result = Yii::$app->redis->keys('*');
 | 
						|
        $output = ['*'];
 | 
						|
        foreach ($result as $val)
 | 
						|
        {
 | 
						|
            $arVal = explode(':', $val);
 | 
						|
            if (isset($arVal[1]) && !in_array($arVal[1], $output))
 | 
						|
            {
 | 
						|
                $output[] = $arVal[1];
 | 
						|
            }
 | 
						|
        }
 | 
						|
        sort($output);
 | 
						|
        return $output;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Удаление всех элементов по шаблоку
 | 
						|
     * @param type $type
 | 
						|
     * @return boolean
 | 
						|
     */
 | 
						|
    public static function deleteType($type)
 | 
						|
    {
 | 
						|
        if (self::getActive())
 | 
						|
        {
 | 
						|
            self::deleteAll($type);
 | 
						|
            $type = $type == "*" ? "*" : "{$type}:*";
 | 
						|
            $result = Yii::$app->redis->keys($type);
 | 
						|
            foreach ($result as $val)
 | 
						|
            {
 | 
						|
                self::deleteAll(str_replace(self::prefix(), '', $val));
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    public static function set($key, $value, $options = null)
 | 
						|
    {
 | 
						|
        $result = false;
 | 
						|
        if (self::getActive())
 | 
						|
        {
 | 
						|
            if ($options === true)
 | 
						|
            {
 | 
						|
                $options = ['EX' => self::livetime()];
 | 
						|
            }
 | 
						|
            elseif (is_int($options))
 | 
						|
            {
 | 
						|
                $options = ['EX' => $options];
 | 
						|
            }
 | 
						|
            Yii::$app->redis->set($key, json_encode($value), $options);
 | 
						|
        }
 | 
						|
        return $result;
 | 
						|
    }
 | 
						|
 | 
						|
    public static function setModel($key, $model, $options = true)
 | 
						|
    {
 | 
						|
        return self::set($key, is_object($model) ? $model->attributes : null, $options);
 | 
						|
    }
 | 
						|
 | 
						|
    public static function setModelArray($key, $modelArray, $page = null, $options = true)
 | 
						|
    {
 | 
						|
        $values = [];
 | 
						|
        foreach ($modelArray as $model)
 | 
						|
        {
 | 
						|
            $values[] = $model->attributes;
 | 
						|
        }
 | 
						|
        if ($page)
 | 
						|
        {
 | 
						|
            $values['page'] = [
 | 
						|
                'totalCount' => $page->totalCount,
 | 
						|
                'perPage' => $page->perPage,
 | 
						|
                'sort' => $page->sort,
 | 
						|
            ];
 | 
						|
        }
 | 
						|
        return self::set($key, $values, $options);
 | 
						|
    }
 | 
						|
 | 
						|
    public static function get(string $key)
 | 
						|
    {
 | 
						|
        $result = false;
 | 
						|
        if (self::getActive())
 | 
						|
        {
 | 
						|
            $result = json_decode(Yii::$app->redis->get($key), true);
 | 
						|
        }
 | 
						|
        return $result === null ? false : $result;
 | 
						|
    }
 | 
						|
 | 
						|
    public static function getModel($key, $className)
 | 
						|
    {
 | 
						|
        $value = self::get($key);
 | 
						|
        return empty($value) ? $value : (new $className($value));
 | 
						|
    }
 | 
						|
 | 
						|
    public static function getModelArray($key, $className, $page = null)
 | 
						|
    {
 | 
						|
        $values = self::get($key);
 | 
						|
        if ($values === false)
 | 
						|
        {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        $ids = [];
 | 
						|
        foreach ($values as $keyVal => $value)
 | 
						|
        {
 | 
						|
            if ($keyVal !== 'page' && isset($value['id']))
 | 
						|
            {
 | 
						|
                $ids[] = $value['id'];
 | 
						|
            }
 | 
						|
        }
 | 
						|
        $output = [];
 | 
						|
        foreach ($values as $keyVal => $value)
 | 
						|
        {
 | 
						|
            if ($keyVal === 'page')
 | 
						|
            {
 | 
						|
                if ($page)
 | 
						|
                {
 | 
						|
                    $page->setMeta($value['totalCount'], $value['perPage']);
 | 
						|
                    $page->sort = $value['sort'];
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                $model = new $className($value);
 | 
						|
                if (isset($model->ids))
 | 
						|
                {
 | 
						|
                    $model->ids = $ids;
 | 
						|
                }
 | 
						|
                $output[] = $model;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return $output;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Доюавляем в лист удаляемый индекс
 | 
						|
     * @param type $key
 | 
						|
     * @param type $field
 | 
						|
     * @return type
 | 
						|
     */
 | 
						|
    public static function addDeleteKey($key, $field = '-')
 | 
						|
    {
 | 
						|
        return self::hset('del:' . $key, $field, time() + self::$keysDeleteTime);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Удаляет устаревший кеш
 | 
						|
     * @return type
 | 
						|
     */
 | 
						|
    public static function oldCacheDelete()
 | 
						|
    {
 | 
						|
        $result = Yii::$app->redis->keys('del:*');
 | 
						|
        foreach ($result as $val)
 | 
						|
        {
 | 
						|
            $cursor = 0;//null;
 | 
						|
            $key = str_replace(self::prefix(), '', $val);
 | 
						|
            $pattern = '*';
 | 
						|
            $arKeys = [];
 | 
						|
            while ($values = Yii::$app->redis->hscan($key, $cursor, $pattern))
 | 
						|
            {
 | 
						|
                foreach ($values as $vkey => $value)
 | 
						|
                {
 | 
						|
                    if ($value < time())
 | 
						|
                    {
 | 
						|
                        $arKeys[] = $vkey;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            $keyCache = str_replace(self::prefix() . "del:", '', $val);
 | 
						|
            foreach ($arKeys as $value)
 | 
						|
            {
 | 
						|
                self::$setDeleteKey = false;
 | 
						|
                if ($value == '-')
 | 
						|
                {
 | 
						|
                    self::del($keyCache);
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    self::hdel($keyCache, $value);
 | 
						|
                }
 | 
						|
                self::hdel($key, $value);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |