directorytree/activeredis
Active Record-style Redis hash models for Laravel. Create, update, delete, expire, and query Redis-backed records with an Eloquent-like API, including model identifiers, timestamps, casts, events, connections, chunking, searching, and testing support.
## Getting Started
### Minimal Steps
1. **Installation**:
```bash
composer require directorytree/activeredis
Ensure your config/database.php has a dedicated Redis connection for ActiveRedis (recommended).
Define a Model:
namespace App\Redis;
use DirectoryTree\ActiveRedis\Model;
class Visit extends Model {}
Create a Record:
$visit = Visit::create([
'ip' => '192.168.1.1',
'url' => 'https://example.com',
]);
Query a Record:
$visit = Visit::find('f195637b-7d48-43ab-abab-86e93dfc9410');
Track User Visits with Optimized Performance:
// Create a visit record (now with optimized Redis pipelining under the hood)
$visit = Visit::create([
'ip' => request()->ip(),
'url' => request()->url(),
'user_agent' => request()->userAgent(),
]);
// Later, retrieve all visits (attribute fetching is now pipelined)
$visits = Visit::query()->get();
app/Redis/Visit.php (or your custom model file).config/database.php (Redis connection).$searchable).booted() method.$model = ModelName::create(['key' => 'value']);
$model = ModelName::find('id');
// Or query all (attributes fetched in bulk)
$models = ModelName::all();
$model->update(['key' => 'new_value']);
// Or
$model->key = 'new_value';
$model->save();
$model->delete();
// Or bulk delete
ModelName::destroy(['id1', 'id2']);
$model = ModelName::create(['key' => 'value']);
$model->setExpiry(now()->addHours(1));
if ($model->getExpiry()) {
// Model will expire at $model->getExpiry()
}
class Visit extends Model {
protected array $searchable = ['ip', 'url'];
}
$results = ModelName::search('ip', '192.168.1.1')->get();
ModelName::chunk(100, function ($models) {
foreach ($models as $model) {
// Process each model (attributes fetched efficiently)
}
});
getNewKey() for non-UUID keys:
protected function getNewKey(): string {
return Str::random(20);
}
find(), all(), and query operations.$models = ModelName::limit(100)->get(); // Attributes fetched in bulk
config/database.php for ActiveRedis to avoid scanning unrelated keys (e.g., cache, sessions).'activeredis' => [
'url' => env('REDIS_URL'),
'database' => 10, // Isolated database
],
// app/Observers/VisitObserver.php
class VisitObserver {
public function created(Visit $visit) {
Log::info("New visit recorded: {$visit->ip}");
}
}
AppServiceProvider:
Visit::observe(VisitObserver::class);
class Visit extends Model {
protected array $casts = [
'user_id' => 'integer',
'is_bot' => 'boolean',
'metadata' => 'json',
];
}
$recentVisits = Visit::where('created_at', '>', now()->subHours(1))->get();
use DirectoryTree\ActiveRedis\Facades\ActiveRedis;
public function test_pipelined_attribute_fetching() {
ActiveRedis::shouldReceive('pipeline')
->once()
->andReturnSelf()
->shouldReceive('hGetAll')
->with('visits:id:test-key')
->once()
->andReturn(['ip' => '192.168.1.1']);
$model = ModelName::find('test-key');
$this->assertEquals('192.168.1.1', $model->ip);
}
id vs ID).// Fails to find the model if case doesn't match
$model = ModelName::find('CUSTOM-ID'); // Returns null if stored as 'custom-id'
$searchable after records exist will break searches. Plan schema early.SCAN does not guarantee exact batch sizes. Use each() with a callback to handle variability:
ModelName::each(function ($model) {
// Process model (attributes fetched per batch)
}, 100); // Batch size hint
force: true in create() or save() deletes existing records silently. Document this behavior in your code.// Deletes existing record if it exists
ModelName::create(['id' => '123'], force: true);
null unexpectedly. Handle gracefully:
$model = ModelName::find('id');
if (!$model) {
// Handle expired/deleted model
}
:) and asterisks (*) in custom keys or searchable values. Redis uses these for patterns.redis-cli to inspect keys:
redis-cli KEYS "visits:id:*"
redis-cli TTL "visits:id:f195637b-7d48-43ab-abab-86e93dfc9410"
AppServiceProvider to see pipeline usage:
use DirectoryTree\ActiveRedis\Facades\ActiveRedis;
public function boot() {
ActiveRedis::setLogger(function
How can I help you explore Laravel packages today?