lunzai/laravel-cache-dependency 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

lunzai/laravel-cache-dependency

Composer 安装命令:

composer require lunzai/laravel-cache-dependency

包简介

Dependency-based caching for Laravel with tag and database dependencies inspired by Yii2

README 文档

README

Latest Version on Packagist Tests Total Downloads License

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

License

The MIT License (MIT). Please see License File for more information.

lunzai/laravel-cache-dependency 适用场景与选型建议

lunzai/laravel-cache-dependency 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 2 次下载、GitHub Stars 达 0, 最近一次更新时间为 2025 年 11 月 26 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「dependency」 「cache」 「tags」 「laravel」 「invalidation」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 lunzai/laravel-cache-dependency 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 lunzai/laravel-cache-dependency 我们能提供哪些服务?
定制开发 / 二次开发

基于 lunzai/laravel-cache-dependency 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 2
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 18
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-11-26