Add caching layer and database helper
- Add CacheHelper for file-based caching with TTL support - Add Database helper for centralized connection management - Update WorkflowModel to cache status transitions (10 min TTL) - Update UserPreferencesModel to cache user prefs (5 min TTL) - Update manage_workflows.php to clear cache on changes - Update get_users.php to use Database helper (example migration) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,35 +1,41 @@
|
||||
<?php
|
||||
/**
|
||||
* UserPreferencesModel
|
||||
* Handles user-specific preferences and settings
|
||||
* Handles user-specific preferences and settings with caching
|
||||
*/
|
||||
require_once dirname(__DIR__) . '/helpers/CacheHelper.php';
|
||||
|
||||
class UserPreferencesModel {
|
||||
private $conn;
|
||||
private static $CACHE_PREFIX = 'user_prefs';
|
||||
private static $CACHE_TTL = 300; // 5 minutes
|
||||
|
||||
public function __construct($conn) {
|
||||
$this->conn = $conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all preferences for a user
|
||||
* Get all preferences for a user (with caching)
|
||||
* @param int $userId User ID
|
||||
* @return array Associative array of preference_key => preference_value
|
||||
*/
|
||||
public function getUserPreferences($userId) {
|
||||
$sql = "SELECT preference_key, preference_value
|
||||
FROM user_preferences
|
||||
WHERE user_id = ?";
|
||||
$stmt = $this->conn->prepare($sql);
|
||||
$stmt->bind_param("i", $userId);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
return CacheHelper::remember(self::$CACHE_PREFIX, $userId, function() use ($userId) {
|
||||
$sql = "SELECT preference_key, preference_value
|
||||
FROM user_preferences
|
||||
WHERE user_id = ?";
|
||||
$stmt = $this->conn->prepare($sql);
|
||||
$stmt->bind_param("i", $userId);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
$prefs = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$prefs[$row['preference_key']] = $row['preference_value'];
|
||||
}
|
||||
return $prefs;
|
||||
$prefs = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$prefs[$row['preference_key']] = $row['preference_value'];
|
||||
}
|
||||
$stmt->close();
|
||||
return $prefs;
|
||||
}, self::$CACHE_TTL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,7 +51,15 @@ class UserPreferencesModel {
|
||||
ON DUPLICATE KEY UPDATE preference_value = VALUES(preference_value)";
|
||||
$stmt = $this->conn->prepare($sql);
|
||||
$stmt->bind_param("iss", $userId, $key, $value);
|
||||
return $stmt->execute();
|
||||
$result = $stmt->execute();
|
||||
$stmt->close();
|
||||
|
||||
// Invalidate cache for this user
|
||||
if ($result) {
|
||||
CacheHelper::delete(self::$CACHE_PREFIX, $userId);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,17 +70,8 @@ class UserPreferencesModel {
|
||||
* @return mixed Preference value or default
|
||||
*/
|
||||
public function getPreference($userId, $key, $default = null) {
|
||||
$sql = "SELECT preference_value FROM user_preferences
|
||||
WHERE user_id = ? AND preference_key = ?";
|
||||
$stmt = $this->conn->prepare($sql);
|
||||
$stmt->bind_param("is", $userId, $key);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
if ($row = $result->fetch_assoc()) {
|
||||
return $row['preference_value'];
|
||||
}
|
||||
return $default;
|
||||
$prefs = $this->getUserPreferences($userId);
|
||||
return $prefs[$key] ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,7 +85,15 @@ class UserPreferencesModel {
|
||||
WHERE user_id = ? AND preference_key = ?";
|
||||
$stmt = $this->conn->prepare($sql);
|
||||
$stmt->bind_param("is", $userId, $key);
|
||||
return $stmt->execute();
|
||||
$result = $stmt->execute();
|
||||
$stmt->close();
|
||||
|
||||
// Invalidate cache for this user
|
||||
if ($result) {
|
||||
CacheHelper::delete(self::$CACHE_PREFIX, $userId);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +105,21 @@ class UserPreferencesModel {
|
||||
$sql = "DELETE FROM user_preferences WHERE user_id = ?";
|
||||
$stmt = $this->conn->prepare($sql);
|
||||
$stmt->bind_param("i", $userId);
|
||||
return $stmt->execute();
|
||||
$result = $stmt->execute();
|
||||
$stmt->close();
|
||||
|
||||
// Invalidate cache for this user
|
||||
if ($result) {
|
||||
CacheHelper::delete(self::$CACHE_PREFIX, $userId);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all user preferences cache
|
||||
*/
|
||||
public static function clearCache() {
|
||||
CacheHelper::delete(self::$CACHE_PREFIX);
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,14 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* WorkflowModel - Handles status transition workflows and validation
|
||||
*
|
||||
* Uses caching for frequently accessed transition rules since they rarely change.
|
||||
*/
|
||||
require_once dirname(__DIR__) . '/helpers/CacheHelper.php';
|
||||
|
||||
class WorkflowModel {
|
||||
private $conn;
|
||||
private static $CACHE_PREFIX = 'workflow';
|
||||
private static $CACHE_TTL = 600; // 10 minutes
|
||||
|
||||
public function __construct($conn) {
|
||||
$this->conn = $conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all active transitions (with caching)
|
||||
*
|
||||
* @return array All active transitions indexed by from_status
|
||||
*/
|
||||
private function getAllTransitions() {
|
||||
return CacheHelper::remember(self::$CACHE_PREFIX, 'all_transitions', function() {
|
||||
$sql = "SELECT from_status, to_status, requires_comment, requires_admin
|
||||
FROM status_transitions
|
||||
WHERE is_active = TRUE";
|
||||
$result = $this->conn->query($sql);
|
||||
|
||||
$transitions = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$from = $row['from_status'];
|
||||
if (!isset($transitions[$from])) {
|
||||
$transitions[$from] = [];
|
||||
}
|
||||
$transitions[$from][$row['to_status']] = [
|
||||
'to_status' => $row['to_status'],
|
||||
'requires_comment' => (bool)$row['requires_comment'],
|
||||
'requires_admin' => (bool)$row['requires_admin']
|
||||
];
|
||||
}
|
||||
|
||||
return $transitions;
|
||||
}, self::$CACHE_TTL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get allowed status transitions for a given status
|
||||
*
|
||||
@@ -16,21 +51,13 @@ class WorkflowModel {
|
||||
* @return array Array of allowed transitions with requirements
|
||||
*/
|
||||
public function getAllowedTransitions($currentStatus) {
|
||||
$sql = "SELECT to_status, requires_comment, requires_admin
|
||||
FROM status_transitions
|
||||
WHERE from_status = ? AND is_active = TRUE";
|
||||
$stmt = $this->conn->prepare($sql);
|
||||
$stmt->bind_param("s", $currentStatus);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$allTransitions = $this->getAllTransitions();
|
||||
|
||||
$transitions = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$transitions[] = $row;
|
||||
if (!isset($allTransitions[$currentStatus])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
return $transitions;
|
||||
return array_values($allTransitions[$currentStatus]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,22 +74,15 @@ class WorkflowModel {
|
||||
return true;
|
||||
}
|
||||
|
||||
$sql = "SELECT requires_admin FROM status_transitions
|
||||
WHERE from_status = ? AND to_status = ? AND is_active = TRUE";
|
||||
$stmt = $this->conn->prepare($sql);
|
||||
$stmt->bind_param("ss", $fromStatus, $toStatus);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$allTransitions = $this->getAllTransitions();
|
||||
|
||||
if ($result->num_rows === 0) {
|
||||
$stmt->close();
|
||||
if (!isset($allTransitions[$fromStatus][$toStatus])) {
|
||||
return false; // Transition not defined
|
||||
}
|
||||
|
||||
$row = $result->fetch_assoc();
|
||||
$stmt->close();
|
||||
$transition = $allTransitions[$fromStatus][$toStatus];
|
||||
|
||||
if ($row['requires_admin'] && !$isAdmin) {
|
||||
if ($transition['requires_admin'] && !$isAdmin) {
|
||||
return false; // Admin required
|
||||
}
|
||||
|
||||
@@ -75,18 +95,20 @@ class WorkflowModel {
|
||||
* @return array Array of unique status values
|
||||
*/
|
||||
public function getAllStatuses() {
|
||||
$sql = "SELECT DISTINCT from_status as status FROM status_transitions
|
||||
UNION
|
||||
SELECT DISTINCT to_status as status FROM status_transitions
|
||||
ORDER BY status";
|
||||
$result = $this->conn->query($sql);
|
||||
return CacheHelper::remember(self::$CACHE_PREFIX, 'all_statuses', function() {
|
||||
$sql = "SELECT DISTINCT from_status as status FROM status_transitions
|
||||
UNION
|
||||
SELECT DISTINCT to_status as status FROM status_transitions
|
||||
ORDER BY status";
|
||||
$result = $this->conn->query($sql);
|
||||
|
||||
$statuses = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$statuses[] = $row['status'];
|
||||
}
|
||||
$statuses = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$statuses[] = $row['status'];
|
||||
}
|
||||
|
||||
return $statuses;
|
||||
return $statuses;
|
||||
}, self::$CACHE_TTL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,21 +119,23 @@ class WorkflowModel {
|
||||
* @return array|null Transition requirements or null if not found
|
||||
*/
|
||||
public function getTransitionRequirements($fromStatus, $toStatus) {
|
||||
$sql = "SELECT requires_comment, requires_admin
|
||||
FROM status_transitions
|
||||
WHERE from_status = ? AND to_status = ? AND is_active = TRUE";
|
||||
$stmt = $this->conn->prepare($sql);
|
||||
$stmt->bind_param("ss", $fromStatus, $toStatus);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$allTransitions = $this->getAllTransitions();
|
||||
|
||||
if ($result->num_rows === 0) {
|
||||
$stmt->close();
|
||||
if (!isset($allTransitions[$fromStatus][$toStatus])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$row = $result->fetch_assoc();
|
||||
$stmt->close();
|
||||
return $row;
|
||||
$transition = $allTransitions[$fromStatus][$toStatus];
|
||||
return [
|
||||
'requires_comment' => $transition['requires_comment'],
|
||||
'requires_admin' => $transition['requires_admin']
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear workflow cache (call when transitions are modified)
|
||||
*/
|
||||
public static function clearCache() {
|
||||
CacheHelper::delete(self::$CACHE_PREFIX);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user