Files
crm.clientright.ru/crm_extensions/RedisCache.php

256 lines
7.5 KiB
PHP
Raw Permalink Normal View History

<?php
/**
* Redis Cache для ускорения CRM
*
* Кеширует:
* - Метаданные модулей (табиды, поля)
* - Права доступа пользователей
* - Списки picklist значений
* - Настройки модулей
*/
class RedisCache {
private $redis;
private $enabled = false;
private $prefix = 'crm:cache:';
private $defaultTTL = 3600; // 1 час
public function __construct() {
try {
if (class_exists('Redis')) {
// Используем расширение Redis
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
$this->redis->auth('CRM_Redis_Pass_2025_Secure!');
$this->enabled = true;
} else {
// Используем Predis
require_once __DIR__ . '/../vendor/autoload.php';
$this->redis = new Predis\Client([
'scheme' => 'tcp',
'host' => '127.0.0.1',
'port' => 6379,
'password' => 'CRM_Redis_Pass_2025_Secure!',
]);
$this->enabled = true;
}
} catch (Exception $e) {
error_log("Redis cache disabled: " . $e->getMessage());
$this->enabled = false;
}
}
/**
* Получить значение из кеша
*/
public function get($key) {
if (!$this->enabled) {
return null;
}
try {
$value = $this->redis->get($this->prefix . $key);
if ($value === false || $value === null) {
return null;
}
return json_decode($value, true);
} catch (Exception $e) {
error_log("Redis get error: " . $e->getMessage());
return null;
}
}
/**
* Сохранить значение в кеш
*/
public function set($key, $value, $ttl = null) {
if (!$this->enabled) {
return false;
}
try {
$ttl = $ttl ?? $this->defaultTTL;
$this->redis->setex(
$this->prefix . $key,
$ttl,
json_encode($value)
);
return true;
} catch (Exception $e) {
error_log("Redis set error: " . $e->getMessage());
return false;
}
}
/**
* Удалить значение из кеша
*/
public function delete($key) {
if (!$this->enabled) {
return false;
}
try {
$this->redis->del($this->prefix . $key);
return true;
} catch (Exception $e) {
error_log("Redis delete error: " . $e->getMessage());
return false;
}
}
/**
* Очистить весь кеш
*/
public function flush() {
if (!$this->enabled) {
return false;
}
try {
// Удаляем все ключи с нашим префиксом
$keys = $this->redis->keys($this->prefix . '*');
if (!empty($keys)) {
$this->redis->del($keys);
}
return true;
} catch (Exception $e) {
error_log("Redis flush error: " . $e->getMessage());
return false;
}
}
/**
* Получить или установить значение (если не существует)
*/
public function remember($key, $callback, $ttl = null) {
$value = $this->get($key);
if ($value !== null) {
return $value;
}
// Вызываем callback для получения значения
$value = $callback();
$this->set($key, $value, $ttl);
return $value;
}
/**
* Кешировать результат SQL запроса
*/
public function cacheQuery($key, $query, $params = [], $ttl = null) {
return $this->remember($key, function() use ($query, $params) {
global $adb;
$result = $adb->pquery($query, $params);
$data = [];
while ($row = $adb->fetch_array($result)) {
$data[] = $row;
}
return $data;
}, $ttl);
}
/**
* Кешировать tabid модуля
*/
public function getTabId($moduleName) {
return $this->remember("tabid:{$moduleName}", function() use ($moduleName) {
global $adb;
$result = $adb->pquery("SELECT tabid FROM vtiger_tab WHERE name=?", [$moduleName]);
return $adb->query_result($result, 0, 'tabid');
}, 86400); // 24 часа
}
/**
* Кешировать поля модуля
*/
public function getModuleFields($moduleName) {
return $this->remember("fields:{$moduleName}", function() use ($moduleName) {
global $adb;
$tabid = getTabid($moduleName);
$query = "SELECT fieldname, fieldlabel, uitype, columnname, tablename, typeofdata
FROM vtiger_field
WHERE tabid=? AND presence IN (0,2)
ORDER BY sequence";
$result = $adb->pquery($query, [$tabid]);
$fields = [];
while ($row = $adb->fetch_array($result)) {
$fields[] = $row;
}
return $fields;
}, 3600); // 1 час
}
/**
* Кешировать picklist значения
*/
public function getPicklistValues($fieldName) {
return $this->remember("picklist:{$fieldName}", function() use ($fieldName) {
global $adb;
$query = "SELECT DISTINCT vtiger_$fieldName.*
FROM vtiger_$fieldName
ORDER BY sortorderid";
$result = $adb->query($query);
$values = [];
while ($row = $adb->fetch_array($result)) {
$values[] = $row;
}
return $values;
}, 3600); // 1 час
}
/**
* Кешировать права доступа пользователя
*/
public function getUserPrivileges($userId) {
return $this->remember("privileges:user:{$userId}", function() use ($userId) {
require_once('include/utils/UserInfoUtil.php');
$privileges = getAllUserPrivileges($userId);
return $privileges;
}, 1800); // 30 минут
}
/**
* Проверить включен ли кеш
*/
public function isEnabled() {
return $this->enabled;
}
/**
* Получить статистику кеша
*/
public function getStats() {
if (!$this->enabled) {
return ['enabled' => false];
}
try {
$info = $this->redis->info();
return [
'enabled' => true,
'keys' => $this->redis->dbsize(),
'memory' => $info['used_memory_human'] ?? 'unknown',
'hits' => $info['keyspace_hits'] ?? 0,
'misses' => $info['keyspace_misses'] ?? 0,
];
} catch (Exception $e) {
return ['enabled' => false, 'error' => $e->getMessage()];
}
}
}