cursedcoder/dark-redis-list-bundle
Installation:
composer require cursedcoder/dark-redis-list-bundle
Add to bundles.php:
return [
// ...
CursedCoder\DarkRedisListBundle\CursedCoderDarkRedisListBundle::class => ['all' => true],
];
Configure Redis:
Add to config/packages/cursed_coder_dark_redis_list.yaml:
cursed_coder_dark_redis_list:
redis:
host: '127.0.0.1'
port: 6379
db: 0
First Use Case:
Define a list in a Doctrine entity (e.g., Post):
use CursedCoder\DarkRedisListBundle\Model\RedisListInterface;
class Post implements RedisListInterface
{
// ...
public function getRedisListName(): string
{
return 'viewed_posts'; // List name in Redis
}
}
Add Items to Redis:
Use the RedisListManager service:
$redisListManager = $container->get('cursed_coder_dark_redis_list.manager');
$redisListManager->addToList($post, 'viewed_posts'); // Format: "Bundle:Entity;id"
Hybrid Storage:
created_at, title) in Doctrine.Real-Time Updates:
$redisListManager->publishUpdate('viewed_posts', $post);
$redis->subscribe(['viewed_posts'], function ($message) {
// Rebuild list logic here
});
Multi-Entity Lists:
Post, Article) into one Redis list:
$redisListManager->addToList($post, 'global_feed');
$redisListManager->addToList($article, 'global_feed');
$items = $redisListManager->getList('global_feed', 0, 10); // Paginated
Permanent Caching:
# config/packages/cursed_coder_dark_redis_list.yaml
cursed_coder_dark_redis_list:
ttl: 86400 # 24 hours
$redisListManager->touchList('viewed_posts'); // Reset TTL
Doctrine Events:
Listen to postPersist/postUpdate to auto-populate Redis lists:
$entityManager->getEventManager()->addEventListener(
Doctrine\ORM\Events::postPersist,
function ($event) {
$entity = $event->getObject();
if ($entity instanceof RedisListInterface) {
$this->redisListManager->addToList($entity, $entity->getRedisListName());
}
}
);
Symfony Cache: Use Symfony’s cache system to store serialized Redis lists locally for read-heavy apps:
$cache = $container->get('cache.app');
$cache->set('viewed_posts', $redisListManager->getList('viewed_posts'), 3600);
API Layer: Expose Redis lists via API with pagination:
// src/Controller/FeedController.php
public function getFeed(Request $request, RedisListManager $manager)
{
$page = $request->query->getInt('page', 1);
$items = $manager->getList('global_feed', ($page - 1) * 10, 10);
return $this->json($items);
}
ID Collisions:
getList() with offset/limit to skip gaps, or manually compact lists with:
$redisListManager->compactList('viewed_posts');
Data Corruption:
RDB/AOF) and monitor with redis-cli --stat.Memory Bloat:
Bundle:Entity;id) and fetch full entities from Doctrine.Race Conditions:
$redis->transaction(function ($tx) use ($listName, $entity) {
$tx->lPush($listName, $entity->getRedisKey());
$tx->expire($listName, 86400);
});
Symfony Cache Invalidation:
$cache->delete('viewed_posts');
Check Redis Data: Inspect lists directly with:
redis-cli HGETALL viewed_posts
Or use a GUI like RedisInsight.
Log Redis Operations: Enable debug mode in config:
cursed_coder_dark_redis_list:
debug: true
Logs will appear in var/log/dev.log.
Test Locally: Use Docker for Redis:
docker run --name redis -p 6379:6379 -d redis
Custom List Formats:
Extend the RedisListInterface to support nested data:
class Post implements RedisListInterface
{
public function getRedisListValue(): array
{
return [
'id' => $this->id,
'title' => $this->title,
'score' => $this->getEngagementScore(),
];
}
}
Add Indexes:
Use Redis sorted sets (ZSET) for indexed lists (e.g., by created_at):
$redis->zAdd('viewed_posts:sorted', $post->getCreatedAt()->getTimestamp(), $post->getRedisKey());
Event Dispatching: Trigger Symfony events when lists are updated:
$dispatcher->dispatch(new ListUpdatedEvent($listName, $entity));
Fallback to Doctrine: Implement a fallback to Doctrine queries if Redis fails:
try {
$items = $redisListManager->getList($listName, $offset, $limit);
} catch (\Exception $e) {
$items = $doctrine->getRepository(Post::class)->findBy([], [], $limit, $offset);
}
How can I help you explore Laravel packages today?