Files
api/services/nginx/app/classes/redis.php
T
Jeppe Bundgaard 5cc311ae32 Add Redis-based permission caching for users and subusers
- Introduced Redis-backed caching for user and subuser permission evaluations in the `route_t` trait, reducing database queries.
- Enhanced `Redis` class with methods for permission caching: `cache_permission`, `get_permission`, and `clear_permission`.
- Added test coverage for the new caching logic in `PermissionRedisCacheTest.php`.
- Implemented Redis caching for authentication sessions with `cache_auth_session`, `get_auth_session`, and `clear_auth_session`.
- Improved CORS handling for preflight requests in `index.php`.
2026-02-24 15:00:22 +01:00

488 lines
12 KiB
PHP

<?php
namespace classes;
use interfaces\redis_i;
class redis implements redis_i
{
use \traits\redis_t;
public function __construct()
{
global $REDIS_CONFIG;
// Make sure the Redis configuration is set
if (!isset($REDIS_CONFIG)) {
throw new \Exception('Redis configuration is not set');
}
// Apply the Redis configuration
$this->redis_host = $REDIS_CONFIG['host'];
$this->redis_database = $REDIS_CONFIG['database'];
$this->redis_password = $REDIS_CONFIG['password'];
}
/**
* @inheritDoc
*/
public function cache_department_booking_count(int $department_id, int $count): redis_i
{
// Cache the department booking count
$this->set('department_booking_count_' . $department_id, $count);
return $this;
}
/**
* @inheritDoc
*/
public function get_department_booking_count(int $department_id): int|null
{
// Get the department booking count
return $this->get('department_booking_count_' . $department_id);
}
/**
* @inheritDoc
*/
public function clear_department_booking_count(int $department_id): redis_i
{
// Clear the department booking count
$this->delete('department_booking_count_' . $department_id);
return $this;
}
/**
* @inheritDoc
*/
public function cache_department_webhook(int $department_id, string $webhook): self
{
// Cache the department webhook
$this->set('department_webhook_' . $department_id, $webhook);
$this->expire('department_webhook_' . $department_id, 300); // Expire in 5 minutes
return $this;
}
/**
* @inheritDoc
*/
public function get_department_webhook(int $department_id): string|null
{
// Get the department webhook
return $this->get('department_webhook_' . $department_id);
}
/**
* @inheritDoc
*/
public function clear_department_webhook(int $department_id): self
{
// Clear the department webhook
$this->delete('department_webhook_' . $department_id);
return $this;
}
/**
* @inheritDoc
*/
public function cache_department_name(int $department_id, string $department_name): self
{
// Cache the department name (If it is not empty or null)
if (empty($department_name)) {
$department_name = 'IS_EMPTY_OR_NULL';
return $this;
}
// Set the department's name in the cache
if ($this->get_department_name($department_id) === null) {
$this->set('department_' . $department_id, json_encode(['name' => $department_name]
));
};
return $this;
}
/**
* @inheritDoc
*/
public function get_department_name(int $department_id): string|null
{
// Get the department name
$tmp_department = $this->get('department_' . $department_id) ?? null;
if ($tmp_department === 'IS_EMPTY_OR_NULL' || $tmp_department === null) {
return null;
}
$tmp_department = json_decode($tmp_department);
// Return the department name
return $tmp_department->name ?: $tmp_department['name'] ?? null;
}
/**
* @inheritDoc
*/
public function clear_department_name(int $department_id): self
{
// Clear the department name
$this->delete('department_' . $department_id);
return $this;
}
/**
* @inheritDoc
*/
public function cache_economic_customer_discount_percentage(int $user_id, int $discount_percentage): self
{
// Cache the economic customer discount percentage
$this->set('users_' . $user_id . '_economic_customer_discount_percentage', $discount_percentage);
return $this;
}
/**
* @inheritDoc
*/
public function get_economic_customer_discount_percentage(int $user_id): int|null
{
// Get the economic customer discount percentage
return $this->get('users_' . $user_id . '_economic_customer_discount_percentage');
}
/**
* @inheritDoc
*/
public function clear_economic_customer_discount_percentage(int $user_id): self
{
// Clear the economic customer discount percentage
$this->delete('users_' . $user_id . '_economic_customer_discount_percentage');
return $this;
}
/**
* @inheritDoc
*/
public function cache_customer_notes(int $user_id, array $customer_notes): self
{
// Cache the customer notes
$this->set_array('users_' . $user_id . '_customer_notes', $customer_notes);
return $this;
}
/**
* @inheritDoc
*/
public function get_customer_notes(int $user_id): array|null
{
// Get the customer notes
return $this->get_array('users_' . $user_id . '_customer_notes');
}
/**
* @inheritDoc
*/
public function clear_customer_notes(int $user_id): self
{
// Clear the customer notes
$this->delete('users_' . $user_id . '_customer_notes');
return $this;
}
/**
* @inheritDoc
*/
public function add_log(string $module, string $department, int $type, int $user_id, string $action, string $message): redis_i
{
// Get the current timestamp
$timestamp = strtotime('now');
// Get unique id for the log
$log_id = uniqid();
// Add the log to the cache
$this->set_array('log_' . $log_id, [
'id' => $log_id,
'module' => $module,
'department' => $department,
'type' => $type,
'user_id' => $user_id,
'action' => $action,
'message' => $message,
'timestamp' => $timestamp
]);
return $this;
}
/**
* @inheritDoc
*/
public function get_logs(): array|null
{
// Get all logs from the cache
return $this->get_arrays('log_*');
}
/**
* @inheritDoc
*/
public function clear_logs(): self
{
// Clear all logs from the cache
$keys = $this->get_keys('log_*');
foreach ( $keys as $key ) {
$this->delete($key);
}
return $this;
}
/**
* @inheritDoc
*/
public function get_department(int $department_id): array|null
{
// Get the department
return $this->get_array('department_' . $department_id);
}
/**
* @inheritDoc
*/
public function clear_department(int $department_id): self
{
// Clear the departments
$this->clear_departments();
return $this;
}
/**
* @inheritDoc
*/
public function clear_departments(): self
{
// Clear all departments from the cache
$this->delete('departments');
$keys = $this->get_keys('department_*');
foreach ( $keys as $key ) {
$this->delete($key);
}
return $this;
}
/**
* @inheritDoc
*/
public function get_departments(): array|null
{
// Get all departments from the cache
return $this->get_array('departments');
}
/**
* @inheritDoc
*/
public function cache_departments(array $departments): self
{
// Cache the departments
foreach ( $departments as $department ) {
$this->cache_department($department['id'], $department);
}
redis->set_array('departments', $departments);
return $this;
}
/**
* @inheritDoc
*/
public function cache_department(int $department_id, array $department): self
{
// Cache the department
$this->set_array('department_' . $department_id, $department);
return $this;
}
/**
* @inheritDoc
*/
public function get_log_count(): int
{
// Get the log count
return $this->count_keys('log_*');
}
/**
* @inheritDoc
*/
public function cache_token(string $token, array $row): self
{
// Cache the token
$this->set_array('token_' . $token, $row);
return $this;
}
/**
* @inheritDoc
*/
public function get_token(string $token): array|null
{
// Get the token
return $this->get_array('token_' . $token);
}
/**
* @inheritDoc
*/
public function clear_token(string $token): self
{
// Clear the token
$this->delete('token_' . $token);
return $this;
}
/**
* Cache auth session payload for a token with TTL
*/
public function cache_auth_session(string $token, array $data, int $ttl = 60): self
{
$key = 'auth_session_' . $token;
$this->set_array($key, $data);
$this->expire($key, $ttl);
return $this;
}
/**
* Get cached auth session payload by token
*/
public function get_auth_session(string $token): array|null
{
return $this->get_array('auth_session_' . $token);
}
/**
* Clear cached auth session payload by token
*/
public function clear_auth_session(string $token): self
{
$this->delete('auth_session_' . $token);
return $this;
}
/**
* @inheritDoc
*/
public function get_last_crond_run(string $task): int|null
{
// Get the last cron task
return $this->get('last_cron_task_' . $task) ?? null;
}
/**
* @inheritDoc
*/
public function set_last_crond_run(string $task, int $time): self
{
// Set the last cron task
$this->set('last_cron_task_' . $task, $time);
return $this;
}
/**
* @inheritDoc
*/
public function cache_user_id_from_customer_number(int $customer_number, int $user_id): self
{
// Cache the user id from customer number
$this->set('user_id_from_customer_number_' . $customer_number, $user_id);
return $this;
}
/**
* @inheritDoc
*/
public function get_user_id_from_customer_number(int $customer_number): int|null
{
// Get the user id from customer number
return $this->get('user_id_from_customer_number_' . $customer_number);
}
/**
* @inheritDoc
*/
public function clear_user_id_from_customer_number(int $customer_number): self
{
// Clear the user id from customer number
$this->delete('user_id_from_customer_number_' . $customer_number);
return $this;
}
/**
* @inheritDoc
*/
public function cache_customer_number_from_user_id(int $user_id, int $customer_number): self
{
// Cache the customer number from user id
$this->set('customer_number_from_user_id_' . $user_id, $customer_number);
return $this;
}
/**
* @inheritDoc
*/
public function get_customer_number_from_user_id(int $user_id): int|null
{
// Get the customer number from user id
return $this->get('customer_number_from_user_id_' . $user_id);
}
/**
* @inheritDoc
*/
public function clear_customer_number_from_user_id(int $user_id): self
{
// Clear the customer number from user id
$this->delete('customer_number_from_user_id_' . $user_id);
return $this;
}
public function expire(string $key, int $seconds): self
{
// Set the expiration time for a key
$this->redis->expire($key, $seconds);
return $this;
}
public function generateTemporaryCacheKey(): string
{
// Generate a temporary cache key
return 'temporary_cache_' . uniqid();
}
public function mget(array $array_map): array
{
// Get multiple keys from Redis
return $this->redis->mget($array_map);
}
/**
* @inheritDoc
*/
public function cache_permission(string $cache_key, bool $allowed, int $ttl = 300): self
{
$this->setEx('perm:' . $cache_key, $allowed ? '1' : '0', $ttl);
return $this;
}
/**
* @inheritDoc
*/
public function get_permission(string $cache_key): bool|null
{
$val = $this->get('perm:' . $cache_key);
if ($val === null) {
return null;
}
return $val === '1';
}
/**
* @inheritDoc
*/
public function clear_permission(string $cache_key): self
{
$this->delete('perm:' . $cache_key);
return $this;
}
}