lunzai/laravel-cache-dependency
最新稳定版本:0.9.0
Composer 安装命令:
composer require lunzai/laravel-cache-dependency
包简介
Dependency-based caching for Laravel with tag and database dependencies inspired by Yii2
README 文档
README
A dependency-based caching system for Laravel inspired by Yii2. Features tag dependencies with O(1) invalidation and database dependencies for automatic cache freshness.
Why This Package?
Laravel's built-in cache tags have fundamental limitations:
- Retrieval requires exact tag match — You must provide the exact same tags used when caching
- Limited driver support — Only works with Redis and Memcached
- No database dependencies — No automatic invalidation when data changes
This package solves all three problems.
Features
- Tag Dependencies: Tags stored as metadata, retrieval without tags, O(1) invalidation via version counters
- Database Dependencies: Automatic cache invalidation when query results change
- Universal Driver Support: Works with all Laravel cache drivers (file, array, database, Redis, Memcached)
- Cache Interoperability: Works seamlessly with Laravel's Cache facade
- Configurable Behavior: Fail-open or fail-closed when database queries fail
Installation
composer require lunzai/laravel-cache-dependency
Optionally publish the config:
php artisan vendor:publish --tag="cache-dependency-config"
Requirements
- PHP 8.2+
- Laravel 11+
Quick Start
use Lunzai\CacheDependency\Facades\CacheDependency; // Cache with tags CacheDependency::tags(['users', 'permissions']) ->put('user.1.permissions', $permissions, 3600); // Retrieve WITHOUT tags $permissions = CacheDependency::get('user.1.permissions'); // Invalidate — O(1) operation CacheDependency::invalidateTags('users');
Tag Dependencies
How It Works
Tags are stored as metadata with the cached entry. A version counter is maintained for each tag. When you invalidate a tag, the counter increments. On retrieval, cached entries check if their stored tag versions match current versions. If any tag version has increased, the cache is stale.
This is an O(1) operation — no iteration over cached items needed.
Usage
// Cache with tags CacheDependency::tags(['user.123', 'rbac']) ->put('user.123.permissions', $permissions, 3600); // Cache with multiple tags CacheDependency::tags(['user.123', 'role.5', 'rbac']) ->remember('user.123.permissions', 3600, function () { return $this->calculatePermissions(123); }); // Retrieve WITHOUT specifying tags $permissions = CacheDependency::get('user.123.permissions'); // Also works with standard Cache facade $permissions = Cache::get('user.123.permissions'); // Invalidate all caches with 'rbac' tag (O(1) operation) CacheDependency::invalidateTags('rbac'); // Invalidate multiple tags at once CacheDependency::invalidateTags(['user.123', 'role.5']); // Store indefinitely with tags CacheDependency::tags('config')->forever('app.settings', $settings);
Database Dependencies
How It Works
When caching, you provide a SQL query. The query result is stored as a "baseline". On retrieval, the query is re-executed and compared to the baseline. If they differ, the cache is stale.
Usage
// Simple DB dependency CacheDependency::db('SELECT MAX(updated_at) FROM roles') ->remember('all.roles', 3600, fn() => Role::all()); // DB dependency with parameters CacheDependency::db( 'SELECT MAX(updated_at) FROM role_user WHERE user_id = ?', [$userId] )->remember("user.{$userId}.roles", 3600, fn() => $user->roles); // Using named connection CacheDependency::db('SELECT COUNT(*) FROM audit_logs') ->connection('audit') ->put('audit.count', $count, 3600);
Failure Handling
When a database query fails during cache retrieval:
- Fail Closed (default): Treat as cache miss, fetch fresh data
- Fail Open: Return cached value (prioritize availability)
Configure in config/cache-dependency.php:
'db' => [ 'fail_open' => false, // Default: fail closed ],
Combined Dependencies
You can combine tags and database dependencies:
// Cache is invalidated if: // - Any tag is invalidated, OR // - DB query result changes CacheDependency::tags(['rbac', 'permissions']) ->db('SELECT MAX(updated_at) FROM permissions') ->remember('all.permissions', 3600, fn() => Permission::all());
Tag Design Patterns
Since the package uses explicit tagging (no wildcards), proper tag design is essential:
RBAC / Permission System
// Caching user permissions CacheDependency::tags([ "user.{$userId}.permissions", // Specific cache "user.{$userId}", // All caches for this user 'user.permissions', // All user permission caches 'rbac', // All RBAC-related caches ])->remember("user.{$userId}.permissions", 3600, fn() => $this->calculatePermissions($userId)); // Invalidation scenarios: CacheDependency::invalidateTags("user.{$userId}"); // User's roles changed CacheDependency::invalidateTags('user.permissions'); // Permission logic changed CacheDependency::invalidateTags('rbac'); // Clear all RBAC caches
E-commerce / Product Catalog
// Product cache CacheDependency::tags([ "product.{$productId}", "category.{$categoryId}.products", "vendor.{$vendorId}.products", 'products', ])->remember("product.{$productId}", 3600, fn() => Product::find($productId)); // Invalidation: CacheDependency::invalidateTags("product.{$productId}"); // Product updated CacheDependency::invalidateTags("category.{$categoryId}.products"); // Category products changed
Multi-tenant Application
// Tenant-scoped cache CacheDependency::tags([ "tenant.{$tenantId}", "tenant.{$tenantId}.settings", ])->remember("tenant.{$tenantId}.config", 3600, fn() => $tenant->settings); // Invalidation: CacheDependency::invalidateTags("tenant.{$tenantId}"); // Clear all tenant caches
Tag Naming Conventions
| Pattern | Use Case | Example |
|---|---|---|
entity.{id} |
All caches for a specific entity | user.123, product.456 |
entity.{id}.aspect |
Specific aspect of an entity | user.123.permissions |
entity.aspect |
All entities' aspect caches | user.permissions |
domain |
Domain-wide caches | rbac, products, settings |
parent.{id}.children |
Parent-child relationships | category.5.products |
Configuration
Publish the configuration file:
php artisan vendor:publish --tag="cache-dependency-config"
Available options:
return [ // Cache store to use (null = default) 'store' => env('CACHE_DEPENDENCY_STORE'), // Prefix for internal cache keys (tag versions) 'prefix' => env('CACHE_DEPENDENCY_PREFIX', 'cdep'), // Tag version TTL (should be longer than longest cache TTL) 'tag_version_ttl' => env('CACHE_DEPENDENCY_TAG_TTL', 86400 * 30), // 30 days 'db' => [ // Default database connection (null = default) 'connection' => env('CACHE_DEPENDENCY_DB_CONNECTION'), // Query timeout in seconds 'timeout' => env('CACHE_DEPENDENCY_DB_TIMEOUT', 5), // Behavior when DB query fails: // - false: Return null (cache miss) - fail closed // - true: Return cached value (fail open) 'fail_open' => env('CACHE_DEPENDENCY_FAIL_OPEN', false), ], ];
API Reference
CacheDependency Facade
// Create pending dependency with tags CacheDependency::tags(array|string $tags): PendingDependency // Create pending dependency with DB query CacheDependency::db(string $sql, array $params = []): PendingDependency // Retrieve from cache CacheDependency::get(string $key, mixed $default = null): mixed // Store in cache (without dependencies) CacheDependency::put(string $key, mixed $value, ?int $ttl = null): bool // Remember pattern CacheDependency::remember(string $key, ?int $ttl, Closure $callback): mixed // Invalidate tags (O(1)) CacheDependency::invalidateTags(array|string $tags): void // Get tag version CacheDependency::getTagVersion(string $tag): int // Check existence (checks staleness) CacheDependency::has(string $key): bool // Remove from cache CacheDependency::forget(string $key): bool // Retrieve and delete CacheDependency::pull(string $key, mixed $default = null): mixed // Get multiple CacheDependency::many(array $keys): array // Clear all CacheDependency::flush(): bool // Use different store CacheDependency::store(?string $name = null): CacheDependencyManager
PendingDependency Methods
// Add tags (chainable) ->tags(array|string $tags): self // Set DB dependency (chainable) ->db(string $sql, array $params = []): self // Set DB connection (chainable) ->connection(string $connection): self // Store with dependencies ->put(string $key, mixed $value, ?int $ttl = null): bool // Remember with dependencies ->remember(string $key, ?int $ttl, Closure $callback): mixed // Store forever with dependencies ->forever(string $key, mixed $value): bool // Store multiple with dependencies ->putMany(array $values, ?int $ttl = null): bool
Testing
composer test
Credits
- HL (Lunzai)
- Inspired by Yii2's Cache Dependencies
License
The MIT License (MIT). Please see License File for more information.
统计信息
- 总下载量: 1
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 0
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-11-26