phillarmonic / allegro-redis-odm-bundle
Redis ODM (Object Document Mapper) for Symfony - store and retrieve PHP objects using Redis
Installs: 12
Dependents: 0
Suggesters: 0
Security: 0
Stars: 2
Watchers: 1
Forks: 0
Open Issues: 0
Type:symfony-bundle
Requires
- php: >=8.2
- doctrine/doctrine-bundle: ^2.10
- doctrine/orm: ^2.0|^3.0
- symfony/config: ^6.0|^7.0
- symfony/dependency-injection: ^6.0|^7.0
- symfony/framework-bundle: ^6.0|^7.0
Requires (Dev)
- phpunit/phpunit: ^9.5|^10.0
- roave/security-advisories: dev-latest
- symfony/phpunit-bridge: ^6.0|^7.0
Suggests
- ext-redis: Required for using the phpredis adapter
- predis/predis: Required for using the predis adapter
This package is auto-updated.
Last update: 2025-04-27 17:05:22 UTC
README
A Symfony bundle providing an Object Document Mapper (ODM) for Redis. This bundle simplifies storing, retrieving, and managing PHP objects in Redis with support for various Redis storage formats, indexing, and automated object hydration.
Features
- Simple object persistence - Store PHP objects directly in Redis
- Multiple storage formats - Store documents as Redis Hashes or JSON
- Automatic indexing - Create and maintain secondary indices for fast lookups
- Repository pattern - Clean data access through document repositories
- Attribute-based mapping - Define document structure using PHP 8 attributes
- TTL support - Set expiration times for documents and indices
- Multiple client support - Works with both PhpRedis and Predis clients
- Symfony integration - Seamlessly integrates with Symfony framework
Requirements
- PHP 8.2 or higher
- Symfony 6.0+ or 7.0+
- Redis server
- Either the PHP Redis extension (
ext-redis
) orpredis/predis
package
Installation
Step 1: Install the bundle
composer require phillarmonic/allegro-redis-odm-bundle
Step 2: Enable the bundle in your kernel
// config/bundles.php return [ // ... Phillarmonic\AllegroRedisOdmBundle\AllegroRedisOdmBundle::class => ['all' => true], ];
Step 3: Configure the bundle
Create a configuration file at config/packages/allegro_redis_odm.yaml
:
allegro_redis_odm: client_type: phpredis # Options: phpredis, predis connection: scheme: redis # Options: redis, rediss (for TLS) host: 127.0.0.1 port: 6379 database: 0 # auth: null # Password if required # read_timeout: 0 # persistent: false # Default storage settings default_storage: type: hash # Options: hash, json ttl: 0 # Default TTL in seconds (0 = no expiration) # Document mappings mappings: app: dir: '%kernel.project_dir%/src/Document' namespace: 'App\Document' prefix: 'app' # Optional prefix for all Redis keys
Usage
Defining Documents
Create document classes in your project:
<?php // src/Document/Article.php namespace App\Document; use Phillarmonic\AllegroRedisOdmBundle\Mapping\Document; use Phillarmonic\AllegroRedisOdmBundle\Mapping\Field; use Phillarmonic\AllegroRedisOdmBundle\Mapping\Id; use Phillarmonic\AllegroRedisOdmBundle\Mapping\Index; use Phillarmonic\AllegroRedisOdmBundle\Mapping\RedisHash; use Phillarmonic\AllegroRedisOdmBundle\Mapping\Expiration; #[Document(collection: 'articles', prefix:'blog')] // You can add a custom prefix to the entity key #[RedisHash] #[Expiration(ttl: 3600)] // Optional: 1-hour expiration class Article { #[Id] private ?string $id = null; #[Field] #[Index] private string $slug; #[Field(name: 'title', nullable: false)] private string $title; #[Field(type: 'string', nullable: true)] private ?string $content = null; #[Field] #[Index] private string $category; #[Field(type: 'boolean')] private bool $isPublished = false; #[Field(type: 'integer')] private int $viewCount = 0; #[Field(type: 'datetime')] private ?\DateTime $publishedAt = null; // Getters and setters... public function getId(): ?string { return $this->id; } public function getSlug(): string { return $this->slug; } public function setSlug(string $slug): self { $this->slug = $slug; return $this; } public function getTitle(): string { return $this->title; } public function setTitle(string $title): self { $this->title = $title; return $this; } // Add other getters and setters... }
Using the Document Manager
Inject the DocumentManager
into your services:
<?php namespace App\Service; use App\Document\Article; use Phillarmonic\AllegroRedisOdmBundle\DocumentManager; class ArticleService { public function __construct( private DocumentManager $documentManager ) { } public function createArticle(string $title, string $slug, string $category): Article { $article = new Article(); $article->setTitle($title); $article->setSlug($slug); $article->setCategory($category); $article->setPublishedAt(new \DateTime()); $this->documentManager->persist($article); $this->documentManager->flush(); return $article; } public function findArticleById(string $id): ?Article { return $this->documentManager->find(Article::class, $id); } public function findArticleBySlug(string $slug): ?Article { $repository = $this->documentManager->getRepository(Article::class); return $repository->findOneBy(['slug' => $slug]); } }
Mapping Attributes
Attribute | Target | Description |
---|---|---|
#[Document] |
Class | Marks a class as a Redis document |
#[RedisHash] |
Class | Stores document as a Redis hash (default) |
#[RedisJson] |
Class | Stores document as JSON in Redis |
#[Expiration] |
Class | Sets TTL for document |
#[Id] |
Property | Marks a property as the document ID |
#[Field] |
Property | Maps a property to a Redis field |
#[Index] |
Property | Creates a secondary index for a field |
Field Types
The Field
attribute supports the following types:
string
(default)integer
float
boolean
datetime
(stored as UNIX timestamp)json
(serialized as JSON string)
Command Line Tools
The bundle provides several console commands to help with management:
# Debug document mappings to troubleshoot mapping issues php bin/console allegro:debug-mappings # Rebuild all indexes (useful after schema changes) php bin/console allegro:rebuild-indexes # Remove stale/orphaned indexes php bin/console allegro:purge-indexes
Working with Repositories
The bundle provides a DocumentRepository
class with several finder methods similar to Doctrine:
<?php // Example controller or service using repositories namespace App\Controller; use App\Document\Article; use App\Document\Product; use Phillarmonic\AllegroRedisOdmBundle\DocumentManager; use Symfony\Component\HttpFoundation\Response; class ArticleController extends AbstractController { public function __construct( private DocumentManager $documentManager ) { } public function listArticles(): Response { $articleRepository = $this->documentManager->getRepository(Article::class); // Find a single document by ID $article = $articleRepository->find('article123'); // Find all documents $allArticles = $articleRepository->findAll(); // Find by criteria - uses indexed fields when available $publishedTechArticles = $articleRepository->findBy([ 'isPublished' => true, 'category' => 'technology' ]); // Find with ordering, limit and offset $recentArticles = $articleRepository->findBy( ['isPublished' => true], ['publishedAt' => 'DESC'], // Order by publishedAt descending 10, // Limit to 10 results 0 // Start from offset 0 ); // Find a single document by criteria $article = $articleRepository->findOneBy(['slug' => 'introduction-to-redis']); // Count documents $totalCount = $articleRepository->count(); // ... controller logic } }
Custom Repositories
You can create custom repository classes for more specific queries:
<?php // src/Document/Repository/ArticleRepository.php namespace App\Document\Repository; use App\Document\Article; use Phillarmonic\AllegroRedisOdmBundle\Repository\DocumentRepository; class ArticleRepository extends DocumentRepository { public function findRecentArticles(int $days = 30): array { $allArticles = $this->findAll(); $recentArticles = []; foreach ($allArticles as $article) { if ($article->getPublishedAt() && $article->getPublishedAt() > new \DateTime('-' . $days . ' days')) { $recentArticles[] = $article; } } return $recentArticles; } public function findByTitlePattern(string $pattern): array { // Using lower-level Redis client via document manager $redisClient = $this->documentManager->getRedisClient(); // Get all document keys for this collection $keyPattern = $this->metadata->getCollectionKeyPattern(); $keys = $redisClient->keys($keyPattern); $result = []; foreach ($keys as $key) { // Extract ID from key $parts = explode(':', $key); $id = end($parts); // Find the document $article = $this->find($id); // Apply custom filtering if ($article && str_contains(strtolower($article->getTitle()), strtolower($pattern))) { $result[] = $article; } } return $result; } }
Then reference it in your document:
#[Document(collection: 'articles', repository: ArticleRepository::class)] class Article { // ... }
Configuration Reference
Full Configuration
allegro_redis_odm: # Redis client implementation (required) client_type: phpredis # Options: phpredis, predis # Redis connection settings (required) connection: scheme: redis # Options: redis, rediss (for TLS/SSL) host: 127.0.0.1 port: 6379 database: 0 auth: null # Optional password read_timeout: 0 # Read timeout in seconds persistent: false # Use persistent connections options: [] # Additional client-specific options # Default storage settings (optional) default_storage: type: hash # Options: hash, json ttl: 0 # Default TTL in seconds (0 = no expiration) # Document mappings (required - at least one mapping) mappings: app: # Mapping name (arbitrary) type: attribute # Currently only attribute mapping is supported dir: '%kernel.project_dir%/src/Document' # Directory containing document classes namespace: 'App\Document' # Namespace for document classes prefix: '' # Optional prefix for Redis keys
Advanced Usage
Transactions and Batch Processing
Use the document manager to persist multiple objects in a single transaction:
// Persist multiple entities at once $article1 = new Article(); $article1->setTitle('Introduction to Redis'); $article1->setContent('Redis is an in-memory data structure store...'); $article1->setCategory('databases'); $article1->setPublishedAt(new \DateTime()); $article1->setIsPublished(true); $article1->setSlug('introduction-to-redis'); $article2 = new Article(); $article2->setTitle('Redis vs. MongoDB'); $article2->setContent('When comparing Redis and MongoDB...'); $article2->setCategory('databases'); $article2->setPublishedAt(new \DateTime()); $article2->setIsPublished(true); $article2->setSlug('redis-vs-mongodb'); // Both will be persisted in a single Redis transaction $documentManager->persist($article1); $documentManager->persist($article2); $documentManager->flush();
Indexing and Querying
The ODM uses Redis Sets for indexing. When you mark a property with #[Index]
, a Redis Set is created that maps each unique value of the property to all document IDs that have that value.
// In your document class #[Field] #[Index] private string $category; // Then, when querying: $articles = $repository->findBy(['category' => 'technology']);
This query will be highly efficient because it uses Redis sets to directly find the relevant document IDs without scanning all documents.
Using With TLS/SSL
For secure Redis connections:
allegro_redis_odm: client_type: phpredis connection: scheme: rediss # Note the double 's' for SSL host: my-redis-server.com port: 6380 auth: 'my-password'
Working with Redis JSON
To use the JSON storage format:
#[Document(collection: 'articles')] #[RedisJson] class Article { // Document properties... }
Remember that Redis must have the RedisJSON module installed for this to work.
Custom ID generation
By default, IDs are auto-generated using uniqid()
. You can customize the ID strategy:
#[Id(strategy: 'manual')] // Options: 'auto', 'manual', 'none' private string $id;
Using Time-To-Live (TTL) on indexes
You can set TTL on specific indexes to auto-expire them:
#[Field] #[Index(name: 'featured', ttl: 86400)] // 24-hour TTL on this index private bool $isFeatured;
Best Practices
- Use indexes wisely - Only create indexes on fields you frequently search by
- Set appropriate TTLs - Use TTL for temporary data to avoid Redis memory growth
- Batch operations - Use bulk persistence when working with multiple documents
- Keep documents small - Redis works best with relatively compact documents
- Use the debug command -
allegro:debug-mappings
helps diagnose mapping issues
License
This bundle is released under the MIT License. See the bundled LICENSE file for details.
Credits
Developed by the Phillarmonic Team.
For questions, issues, or contributions, please visit the GitHub repository.