cache/namespaced-cache
PSR-6 cache pool decorator that adds namespaces on top of a hierarchical cache (e.g., Redis). Wrap an existing cache pool and automatically prefix keys per namespace, helping isolate apps/modules while reusing the same backend.
Installation
composer require php-cache/namespaced-cache
Add to config/cache.php under stores (if not using default):
'namespaced' => [
'driver' => 'namespaced',
'store' => 'file', // or 'redis', 'database', etc.
],
First Use Case
use PhpCache\NamespacedCache\NamespacedCache;
$cache = new NamespacedCache(app('cache.store'), 'my_namespace');
$cache->set('key', 'value', 60); // Stores as `my_namespace:key`
$value = $cache->get('key'); // Retrieves `my_namespace:key`
Where to Look First
src/NamespacedCache.php for core logic (e.g., how keys are prefixed).tests/ for edge cases (e.g., nested namespaces, invalid keys).Namespace Hierarchy
Use dot notation for hierarchical namespaces (e.g., user:123:settings):
$cache = new NamespacedCache(app('cache.store'), 'user.123.settings');
Dynamic Namespaces Generate namespaces dynamically (e.g., per user or tenant):
$userCache = new NamespacedCache(app('cache.store'), "user:{$userId}");
Fallback to Global Cache
For shared keys across namespaces, prefix with global::
$cache->set('global:config', $config); // Accessible in all namespaces
Laravel Service Provider Bind the decorator to a custom cache key for reusability:
$this->app->bind('cache.namespace', function ($app, $params) {
return new NamespacedCache($app['cache.store'], $params[0]);
});
Usage:
$cache = app('cache.namespace', ['user.123']);
Cache Tags Combine with Laravel’s cache tags for namespace-aware invalidation:
$cache->tags(['user:123'])->put('settings', $data);
Middleware Attach namespaces to requests (e.g., for tenant isolation):
$request->cacheNamespace = "tenant:{$request->tenantId}";
$cache = new NamespacedCache(app('cache.store'), $request->cacheNamespace);
Key Collisions
Avoid using : in keys if the underlying store (e.g., Redis) treats it as a separator. Use underscores or URL-encode:
$cache->set('user:profile', $data); // May fail in Redis
$cache->set('user_profile', $data); // Safer
Namespace Depth Limits Some stores (e.g., Memcached) may fail with excessively long prefixed keys. Keep namespaces concise:
// Bad: "user.123.orders.2023"
// Good: "user_123_orders"
Tag Invalidation Quirks Cache tags are not automatically namespaced. Manually prefix tags:
$cache->tags(["{$namespace}:settings"])->flush();
Verify Prefixed Keys Check the raw cache store to confirm keys are prefixed correctly:
$store = app('cache.store');
$store->get('my_namespace:key'); // Debug output
Disable Namespacing Temporarily For testing, bypass the decorator:
$cache = new NamespacedCache($store, '');
Custom Key Formatter
Override the default : separator by extending NamespacedCache:
class CustomNamespacedCache extends NamespacedCache {
protected function getPrefix() {
return '__'; // Custom separator
}
}
Multi-Store Support Chain multiple namespaces for fallback logic:
$primary = new NamespacedCache($store, 'primary');
$fallback = new NamespacedCache($store, 'fallback');
$value = $primary->get('key') ?? $fallback->get('key');
Event Listeners
Hook into cache events (e.g., CacheStore::itemStored) to log namespaced operations:
Cache::store('namespaced')->extend(function ($store) {
$store->listen(function ($event) {
Log::debug("Namespaced cache event: {$event->key}");
});
});
$cache = new NamespacedCache($store, config('cache.default_namespace'));
How can I help you explore Laravel packages today?