Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Activeredis Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require directorytree/activeredis
    

    Ensure your config/database.php has a dedicated Redis connection for ActiveRedis (recommended).

  2. Define a Model:

    namespace App\Redis;
    use DirectoryTree\ActiveRedis\Model;
    
    class Visit extends Model {}
    
  3. Create a Record:

    $visit = Visit::create([
        'ip' => '192.168.1.1',
        'url' => 'https://example.com',
    ]);
    
  4. Query a Record:

    $visit = Visit::find('f195637b-7d48-43ab-abab-86e93dfc9410');
    

First Use Case

Track User Visits:

// Create a visit record
$visit = Visit::create([
    'ip' => request()->ip(),
    'url' => request()->url(),
    'user_agent' => request()->userAgent(),
]);

// Later, retrieve all visits
$visits = Visit::query()->get();

Where to Look First

  • Model Definition: app/Redis/Visit.php (or your custom model file).
  • Configuration: config/database.php (Redis connection).
  • Searchable Attributes: Define in your model ($searchable).
  • Events: Hook into lifecycle events in the booted() method.

Implementation Patterns

Core Workflows

1. CRUD Operations

  • Create:
    $model = ModelName::create(['key' => 'value']);
    
  • Read:
    $model = ModelName::find('id');
    // Or query all
    $models = ModelName::all();
    
  • Update:
    $model->update(['key' => 'new_value']);
    // Or
    $model->key = 'new_value';
    $model->save();
    
  • Delete:
    $model->delete();
    // Or bulk delete
    ModelName::destroy(['id1', 'id2']);
    

2. Expiring Models

  • Set expiry on creation or later:
    $model = ModelName::create(['key' => 'value']);
    $model->setExpiry(now()->addHours(1));
    
  • Check expiry:
    if ($model->getExpiry()) {
        // Model will expire at $model->getExpiry()
    }
    

3. Searching

  • Define searchable attributes in your model:
    class Visit extends Model {
        protected array $searchable = ['ip', 'url'];
    }
    
  • Search dynamically:
    $results = ModelName::search('ip', '192.168.1.1')->get();
    

4. Chunking for Large Datasets

  • Process records in batches to avoid memory issues:
    ModelName::chunk(100, function ($models) {
        foreach ($models as $model) {
            // Process each model
        }
    });
    

5. Custom Key Generation

  • Override getNewKey() for non-UUID keys:
    protected function getNewKey(): string {
        return Str::random(20);
    }
    

Integration Tips

1. Separate Redis Connection

  • Configure a dedicated Redis connection in config/database.php for ActiveRedis to avoid scanning unrelated keys (e.g., cache, sessions).
  • Example:
    'activeredis' => [
        'url' => env('REDIS_URL'),
        'database' => 10, // Isolated database
    ],
    

2. Events and Observers

  • Use observers for cross-cutting concerns (e.g., logging, analytics):
    // app/Observers/VisitObserver.php
    class VisitObserver {
        public function created(Visit $visit) {
            Log::info("New visit recorded: {$visit->ip}");
        }
    }
    
  • Register in AppServiceProvider:
    Visit::observe(VisitObserver::class);
    

3. Casts for Type Safety

  • Define casts to avoid manual type conversion:
    class Visit extends Model {
        protected array $casts = [
            'user_id' => 'integer',
            'is_bot' => 'boolean',
            'metadata' => 'json',
        ];
    }
    

4. Dynamic Query Building

  • Leverage Eloquent-like query methods:
    $recentVisits = Visit::where('created_at', '>', now()->subHours(1))->get();
    

5. Testing

  • Use ActiveRedis facade to mock Redis in tests:
    use DirectoryTree\ActiveRedis\Facades\ActiveRedis;
    
    public function test_model_creation() {
        ActiveRedis::shouldReceive('hSet')->once();
        $model = ModelName::create(['key' => 'value']);
        $this->assertEquals('value', $model->key);
    }
    

Gotchas and Tips

Pitfalls

1. Case Sensitivity in Keys

  • Redis keys are case-sensitive. Ensure consistency when defining keys (e.g., id vs ID).
  • Example:
    // Fails to find the model if case doesn't match
    $model = ModelName::find('CUSTOM-ID'); // Returns null if stored as 'custom-id'
    

2. Searchable Attributes Are Immutable

  • Changing $searchable after records exist will break searches. Plan schema early.
  • Workaround: Use a separate Redis hash for searchable fields if flexibility is needed.

3. Chunking Limitations

  • Redis SCAN does not guarantee exact batch sizes. Use each() with a callback to handle variability:
    ModelName::each(function ($model) {
        // Process model
    }, 100); // Batch size hint
    

4. Force Overwrite Risks

  • Using force: true in create() or save() deletes existing records silently. Document this behavior in your code.
  • Example:
    // Deletes existing record if it exists
    ModelName::create(['id' => '123'], force: true);
    

5. Expiry and Deletion Race Conditions

  • If a model expires while being accessed, it may return null unexpectedly. Handle gracefully:
    $model = ModelName::find('id');
    if (!$model) {
        // Handle expired/deleted model
    }
    

6. Reserved Characters in Keys

  • Avoid colons (:) and asterisks (*) in custom keys or searchable values. Redis uses these for patterns.

Debugging Tips

1. Check Redis Keys Manually

  • Use redis-cli to inspect keys:
    redis-cli KEYS "visits:id:*"
    
  • Verify expiry with:
    redis-cli TTL "visits:id:f195637b-7d48-43ab-abab-86e93dfc9410"
    

2. Enable Query Logging

  • Temporarily log queries in AppServiceProvider:
    use DirectoryTree\ActiveRedis\Facades\ActiveRedis;
    
    public function boot() {
        ActiveRedis::setLogger(function ($query) {
            Log::debug('Redis Query:', ['query' => $query]);
        });
    }
    

3. Handle Missing Models

  • Use findOrFail() for API responses to return 404:
    $model = ModelName::findOrFail($id);
    return response()->json($model);
    

4. Test Key Generation

  • Override getNewKey() for testing to avoid UUID collisions:
    protected function getNewKey(): string {
        return 'test-key-' . time();
    }
    

5. Monitor Memory Usage

  • Large datasets may cause memory issues. Use chunking and avoid eager loading unrelated data.

Extension Points

1. Custom Query Scopes

  • Add reusable query logic:
    class Visit extends Model {
        public function scopeRecent($query, $hours = 24) {
            return $query->where('created_at', '>', now()->subHours($hours));
        }
    }
    
  • Usage:
    $recent = Visit::recent()->get();
    

2. Override Redis Connection Logic

  • Extend the DirectoryTree\ActiveRedis\Connection class to add custom commands:
    namespace App\Redis;
    
    use DirectoryTree\ActiveRedis\Connection;
    
    class CustomConnection extends Connection {
        public function
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport