Redis Integration
Master GEMVC's integrated Redis support. Learn how to use RedisManager for caching, data storage, pub/sub messaging, and performance optimization in your API layer.
What You'll Learn
Redis Setup
Install and configure Redis during project initialization
RedisManager API
Learn RedisManager methods and operations
API Layer Caching
Use Redis at the API level for best performance
Video Coming Soon...
What is GEMVC Redis Integration?
GEMVC comes with integrated Redis support through the RedisManager class. Redis is a powerful in-memory data structure store that can be used for caching, session storage, pub/sub messaging, and performance optimization.
🎯 Best Practice:
Use Redis at the API level (in /app/api/ folder classes). This is the recommended approach for caching API responses and optimizing performance.
- Singleton Pattern - RedisManager uses singleton pattern for connection management
- Auto-Connection - Automatically connects when needed
- Configuration via .env - All settings configured through environment variables
- Full Redis API - Supports all Redis data structures and operations
- JsonResponse Caching - Special methods for caching API responses
Installation & Setup
During Project Initialization
When you run gemvc init, you'll be asked if you want to install Redis support. Make sure to choose "Yes" if you plan to use Redis!
⚠️ Important:
If you want to use Redis in your GEMVC project, don't forget to choose Redis during the gemvc init CLI command! This will install the necessary Redis PHP extension and configure your project.
# Initialize project with Redis
gemvc init
# When prompted:
# Install Redis support? (y/n): y
# This will:
# - Install Redis PHP extension
# - Add Redis configuration to .env
# - Set up RedisManager
What Gets Installed:
- ✓ Redis PHP extension (phpredis)
- ✓ Redis configuration in
.envfile - ✓ RedisManager class ready to use
Configuration
Environment Variables
Configure Redis connection settings in your .env file:
# Redis Configuration
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DATABASE=0
REDIS_PREFIX=gemvc:
REDIS_PERSISTENT=false
REDIS_TIMEOUT=0.0
REDIS_READ_TIMEOUT=0.0
Configuration Options:
- •
REDIS_HOST- Redis server host (default: 127.0.0.1) - •
REDIS_PORT- Redis server port (default: 6379) - •
REDIS_PASSWORD- Redis password (optional) - •
REDIS_DATABASE- Redis database number (default: 0) - •
REDIS_PREFIX- Key prefix for all keys (default: gemvc:) - •
REDIS_PERSISTENT- Use persistent connection (default: false) - •
REDIS_TIMEOUT- Connection timeout in seconds (default: 0.0) - •
REDIS_READ_TIMEOUT- Read timeout in seconds (default: 0.0)
Getting Started with RedisManager
Basic Usage
RedisManager uses the singleton pattern. Get an instance and start using Redis:
<?php
namespace App\Api;
use Gemvc\Core\ApiService;
use Gemvc\Core\RedisManager;
use Gemvc\Http\Request;
use Gemvc\Http\JsonResponse;
class Product extends ApiService
{
public function list(): JsonResponse
{
// Get RedisManager instance (singleton)
$redis = RedisManager::getInstance();
// Auto-connects if not already connected
// No need to call connect() manually!
// Use Redis operations
$redis->set('key', 'value', 3600); // Set with TTL
$value = $redis->get('key'); // Get value
// ...
}
}
Key Points:
- ✓
getInstance()returns the singleton instance - ✓ Auto-connects when you call any method (no manual
connect()needed) - ✓ Connection is reused across requests (efficient!)
- ✓ All methods return safe defaults (null, false, empty array) if Redis is unavailable
Connection Management
Manual Connection Control
While RedisManager auto-connects, you can also manually control the connection:
<?php
use Gemvc\Core\RedisManager;
$redis = RedisManager::getInstance();
// Manually connect (optional - auto-connects anyway)
$connected = $redis->connect();
if (!$connected) {
$error = $redis->getError();
// Handle connection error
}
// Check connection status
if ($redis->isConnected()) {
// Redis is connected
}
// Get raw Redis instance (advanced)
$redisInstance = $redis->getRedis();
// Disconnect (usually not needed)
$redis->disconnect();
Connection Features:
- ✓ Persistent Connections - Configure via
REDIS_PERSISTENT - ✓ Auto-Reconnect - Automatically reconnects if connection is lost
- ✓ Error Handling - Use
getError()to check for errors - ✓ Prefix Support - All keys automatically prefixed with
REDIS_PREFIX
Basic Key-Value Operations
Set, Get, Delete
Basic Redis operations for storing and retrieving data:
<?php
use Gemvc\Core\RedisManager;
$redis = RedisManager::getInstance();
// Set value with TTL (expires in 1 hour)
$redis->set('user:1', 'John Doe', 3600);
// Set value without expiration
$redis->set('config:app_name', 'My App');
// Get value
$user = $redis->get('user:1');
$appName = $redis->get('config:app_name');
// Check if key exists
if ($redis->exists('user:1')) {
// Key exists
}
// Get TTL (time to live)
$ttl = $redis->ttl('user:1'); // Returns seconds until expiration
// Delete key
$redis->delete('user:1');
// Delete multiple keys
$redis->delete('key1', 'key2', 'key3');
// Flush entire database (use with caution!)
$redis->flush();
TTL (Time To Live):
Use TTL to automatically expire keys. This is perfect for caching! Set a TTL in seconds, and Redis will automatically delete the key when it expires.
API Layer Caching (Best Practice)
Cache API Responses
Best Practice: Use Redis at the API level to cache API responses. This dramatically improves performance by avoiding database queries and business logic execution.
🎯 Recommended Approach:
Always use Redis caching in /app/api/ folder classes. This is the best practice for performance optimization.
<?php
namespace App\Api;
use App\Controller\ProductController;
use Gemvc\Core\ApiService;
use Gemvc\Core\RedisManager;
use Gemvc\Http\Request;
use Gemvc\Http\JsonResponse;
class Product extends ApiService
{
public function list(): JsonResponse
{
// Get RedisManager instance
$redis = RedisManager::getInstance();
// Create cache key from request URL
$cacheKey = 'product:list:' . md5($this->request->requestedUrl . serialize($this->request->get));
// Try to get cached response
$cachedResponse = $redis->getJsonResponse($cacheKey);
if ($cachedResponse !== null) {
// Cache hit - return cached response
return $cachedResponse;
}
// Cache miss - execute business logic
$response = (new ProductController($this->request))->list();
// Cache the response for 5 minutes (300 seconds)
$redis->setJsonResponse($cacheKey, $response, 300);
return $response;
}
public function read(): JsonResponse
{
$id = $this->request->intValueGet('id');
if (!$id) {
return $this->request->returnResponse();
}
$redis = RedisManager::getInstance();
$cacheKey = 'product:read:' . $id;
// Try cache first
$cachedResponse = $redis->getJsonResponse($cacheKey);
if ($cachedResponse !== null) {
return $cachedResponse;
}
// Get from database
$this->request->post['id'] = $id;
$response = (new ProductController($this->request))->read();
// Cache for 10 minutes
$redis->setJsonResponse($cacheKey, $response, 600);
return $response;
}
public function create(): JsonResponse
{
// ... validation ...
$response = (new ProductController($this->request))->create();
// Invalidate cache after create
$redis = RedisManager::getInstance();
$redis->delete('product:list:*'); // Clear list cache
return $response;
}
}
Key Benefits:
- ✓ Faster Responses - Cached responses return instantly
- ✓ Reduced Database Load - Fewer queries to database
- ✓ Better Performance - Especially for frequently accessed data
- ✓ Automatic Expiration - Cache expires automatically with TTL
- ✓ Easy Invalidation - Delete cache keys when data changes
Hash Operations
Storing Objects as Hashes
Redis hashes are perfect for storing objects with multiple fields:
<?php
use Gemvc\Core\RedisManager;
$redis = RedisManager::getInstance();
// Store user data as hash
$redis->hSet('user:1', 'name', 'John Doe');
$redis->hSet('user:1', 'email', 'john@example.com');
$redis->hSet('user:1', 'age', '30');
// Get single field
$name = $redis->hGet('user:1', 'name');
// Get all fields
$userData = $redis->hGetAll('user:1');
// Returns: ['name' => 'John Doe', 'email' => 'john@example.com', 'age' => '30']
// Use in API layer
class User extends ApiService
{
public function read(): JsonResponse
{
$id = $this->request->intValueGet('id');
$redis = RedisManager::getInstance();
$cacheKey = 'user:' . $id;
// Try to get from hash cache
$userData = $redis->hGetAll($cacheKey);
if (empty($userData)) {
// Cache miss - get from database
$this->request->post['id'] = $id;
$response = (new UserController($this->request))->read();
// Store in hash cache
if ($response->data) {
$redis->hSet($cacheKey, 'id', $response->data->id);
$redis->hSet($cacheKey, 'name', $response->data->name);
$redis->hSet($cacheKey, 'email', $response->data->email);
// Set TTL on the hash key
$redis->getRedis()?->expire($cacheKey, 3600);
}
return $response;
}
// Return cached data
return Response::success($userData, 1, 'User retrieved from cache');
}
}
List Operations
Queues and Lists
Redis lists are perfect for queues, logs, and ordered data:
<?php
use Gemvc\Core\RedisManager;
$redis = RedisManager::getInstance();
// Push to left (beginning of list)
$redis->lPush('queue', 'task1');
$redis->lPush('queue', 'task2');
// Push to right (end of list)
$redis->rPush('queue', 'task3');
// Pop from left (FIFO - First In First Out)
$task = $redis->lPop('queue'); // Returns 'task2'
// Pop from right (LIFO - Last In First Out)
$task = $redis->rPop('queue'); // Returns 'task3'
// Use for activity logs
class Activity extends ApiService
{
public function logActivity(string $action): void
{
$redis = RedisManager::getInstance();
$logEntry = json_encode([
'action' => $action,
'timestamp' => time(),
'user_id' => $this->request->auth() ? $this->request->auth()->id : null
]);
// Add to activity log (keep last 1000 entries)
$redis->lPush('activity:log', $logEntry);
$redis->getRedis()?->lTrim('activity:log', 0, 999);
}
}
Set Operations
Unique Collections
Redis sets store unique values - perfect for tags, categories, and unique collections:
<?php
use Gemvc\Core\RedisManager;
$redis = RedisManager::getInstance();
// Add to set (duplicates are ignored)
$redis->sAdd('tags', 'php');
$redis->sAdd('tags', 'redis');
$redis->sAdd('tags', 'php'); // Ignored - already exists
// Get all members
$tags = $redis->sMembers('tags');
// Returns: ['php', 'redis']
// Check membership
if ($redis->sIsMember('tags', 'php')) {
// 'php' is in the set
}
// Use for tracking unique visitors
class Analytics extends ApiService
{
public function trackVisit(int $userId): void
{
$redis = RedisManager::getInstance();
$date = date('Y-m-d');
// Add to daily unique visitors set
$redis->sAdd('visitors:' . $date, $userId);
// Get unique visitor count for today
$uniqueVisitors = count($redis->sMembers('visitors:' . $date));
}
}
Sorted Sets
Ordered Collections with Scores
Sorted sets maintain order by score - perfect for leaderboards, rankings, and time-series data:
<?php
use Gemvc\Core\RedisManager;
$redis = RedisManager::getInstance();
// Add with score
$redis->zAdd('leaderboard', 100, 'player1');
$redis->zAdd('leaderboard', 200, 'player2');
$redis->zAdd('leaderboard', 150, 'player3');
// Get range (sorted by score)
$topPlayers = $redis->zRange('leaderboard', 0, -1, true);
// Returns: ['player1' => 100, 'player3' => 150, 'player2' => 200]
// Get top 10
$top10 = $redis->zRange('leaderboard', 0, 9, true);
// Use for product rankings
class Product extends ApiService
{
public function updateRanking(int $productId, float $score): void
{
$redis = RedisManager::getInstance();
// Update product ranking
$redis->zAdd('product:rankings', $score, $productId);
// Get top 10 products
$topProducts = $redis->zRange('product:rankings', 0, 9, true);
}
}
Pub/Sub Messaging
Publish/Subscribe Pattern
Redis pub/sub allows real-time messaging between different parts of your application:
<?php
use Gemvc\Core\RedisManager;
$redis = RedisManager::getInstance();
// Publish message to channel
$redis->publish('news', 'Breaking news: GEMVC released!');
$redis->publish('notifications', json_encode(['user_id' => 1, 'message' => 'New order']));
// Subscribe to channels (usually in background worker)
$redis->subscribe(['news', 'notifications'], function($redis, $channel, $message) {
echo "Channel: $channel, Message: $message\n";
if ($channel === 'notifications') {
$data = json_decode($message, true);
// Process notification
}
});
// Use for cache invalidation
class Product extends ApiService
{
public function create(): JsonResponse
{
// ... create product ...
// Publish cache invalidation message
$redis = RedisManager::getInstance();
$redis->publish('cache:invalidate', 'product:list');
return $response;
}
}
Use Cases:
- • Cache Invalidation - Notify all instances to clear cache
- • Real-time Updates - Push updates to connected clients
- • Event Broadcasting - Broadcast events across services
- • Background Jobs - Trigger background processing
Pipeline & Transactions
Batch Operations
Use pipelines for batch operations (faster) or transactions for atomic operations:
<?php
use Gemvc\Core\RedisManager;
$redis = RedisManager::getInstance();
// Pipeline (faster - no atomicity guarantee)
$pipe = $redis->pipeline();
$pipe->set('key1', 'value1');
$pipe->set('key2', 'value2');
$pipe->set('key3', 'value3');
$pipe->execute(); // All commands sent at once
// Transaction (atomic - all or nothing)
$tx = $redis->transaction();
$tx->set('key1', 'value1');
$tx->set('key2', 'value2');
$tx->set('key3', 'value3');
$tx->exec(); // All commands executed atomically
// Use for batch cache updates
class Product extends ApiService
{
public function updateMultiple(array $products): void
{
$redis = RedisManager::getInstance();
$pipe = $redis->pipeline();
foreach ($products as $product) {
$cacheKey = 'product:' . $product['id'];
$pipe->set($cacheKey, json_encode($product), 3600);
}
$pipe->execute(); // All updates sent at once
}
}
Pipeline vs Transaction:
- • Pipeline - Faster, no atomicity guarantee, use for batch operations
- • Transaction - Slower, atomic (all or nothing), use when consistency is critical
Best Practices
🎯 Use Redis at API Level
Always use Redis caching in /app/api/ folder classes. This is the recommended best practice for performance optimization.
💡 Cache Key Strategy
Use descriptive, consistent cache keys:
<?php
// ✅ Good - Descriptive and consistent
'product:list:' . md5($url . serialize($params))
'product:read:' . $id
'user:profile:' . $userId
// ❌ Bad - Unclear and inconsistent
'p1'
'data'
'cache_' . rand()
💡 Set Appropriate TTL
Always set TTL (Time To Live) for cache keys. This prevents stale data and automatically cleans up old cache entries.
💡 Invalidate Cache on Updates
When data changes (create, update, delete), invalidate related cache keys to prevent serving stale data.
💡 Handle Cache Misses Gracefully
Always handle cache misses by falling back to database queries. Redis should enhance performance, not break functionality.
Important Notes
-
Installation: Don't forget to choose Redis during
gemvc initCLI command! This installs the Redis PHP extension and configures your project. -
API Level: Best practice is to use Redis at the API level (
/app/api/folder). This provides the best performance optimization. -
Auto-Connection: RedisManager auto-connects when you call any method. No need to manually call
connect(). - Safe Defaults: All methods return safe defaults (null, false, empty array) if Redis is unavailable, so your application won't break.
-
Key Prefix: All keys are automatically prefixed with
REDIS_PREFIX(default:gemvc:) to avoid conflicts.
⚡ Redis Integration Complete!
Excellent! You've learned how to use GEMVC's integrated Redis support. Remember: use Redis at the API level for best performance, and don't forget to choose Redis during gemvc init!