Files
crm.clientright.ru/crm_extensions/RedisCache.php
Fedor 9245768987 🚀 CRM Files Migration & Real-time Features
 Features:
- Migrated ALL files to new S3 structure (Projects, Contacts, Accounts, HelpDesk, Invoice, etc.)
- Added Nextcloud folder buttons to ALL modules
- Fixed Nextcloud editor integration
- WebSocket server for real-time updates
- Redis Pub/Sub integration
- File path manager for organized storage
- Redis caching for performance (Functions.php)

📁 New Structure:
Documents/Project/ProjectName_ID/file_docID.ext
Documents/Contacts/FirstName_LastName_ID/file_docID.ext
Documents/Accounts/AccountName_ID/file_docID.ext

🔧 Technical:
- FilePathManager for standardized paths
- S3StorageService integration
- WebSocket server (Node.js + Docker)
- Redis cache for getBasicModuleInfo()
- Predis library for Redis connectivity

📝 Scripts:
- Migration scripts for all modules
- Test pages for WebSocket/SSE/Polling
- Documentation (MIGRATION_*.md, REDIS_*.md)

🎯 Result: 15,000+ files migrated successfully!
2025-10-24 19:59:28 +03:00

256 lines
7.5 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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()];
}
}
}