nao-pon/flysystem-cached-extra
Installation:
composer require nao-pon/flysystem-cached-extra
Basic Setup:
Extend Laravel’s CachedAdapter with the provided traits in a service provider:
use NaoPon\FlysystemCachedExtra\Traits\{TemporaryFileTrait, FileLockingTrait};
use League\Flysystem\Cached\CachedAdapter;
// In a service provider's boot method
$this->app->extend('filesystem', function ($filesystem) {
$adapter = $filesystem->getAdapter();
if ($adapter instanceof CachedAdapter) {
$adapter->useTrait(TemporaryFileTrait::class);
$adapter->useTrait(FileLockingTrait::class);
}
return $filesystem;
});
First Use Case:
Use the TemporaryFileTrait for job payloads or the FileLockingTrait for concurrent writes:
// Create a temporary file (auto-expires after 1 hour)
Storage::disk('cached_temp')->put('temp/job-123.json', $data);
// Lock a file for exclusive access
Storage::disk('cached_temp')->lock('critical-file.txt', function () {
// Critical section
});
Temporary File Handling:
// Set TTL (e.g., 1 hour)
Storage::disk('cached_temp')->put('temp/file.txt', 'content', [
'cache_ttl' => 3600,
]);
// Manually expire early
Storage::disk('cached_temp')->expire('temp/file.txt');
File Locking:
// Lock with timeout (5 seconds)
Storage::disk('cached_temp')->lock('file.txt', 5, function () {
// Exclusive access block
});
// Check if locked
if (Storage::disk('cached_temp')->isLocked('file.txt')) {
// Handle contention
}
Streaming Support:
// Stream a large file with caching
$stream = Storage::disk('cached_temp')->readStream('large-file.zip');
// Process stream...
Integration with Queues:
// In a job
public function handle()
{
$tempPath = 'temp/' . $this->jobId . '.json';
Storage::disk('cached_temp')->put($tempPath, $this->payload, [
'cache_ttl' => 3600,
]);
// Process...
Storage::disk('cached_temp')->delete($tempPath);
}
Dynamic Disks:
Storage::extend('cached_temp', function ($app) {
$adapter = new CachedAdapter(
Storage::disk('s3')->getAdapter(),
new TemporaryFileTrait(),
new FileLockingTrait()
);
return new Filesystem($adapter);
});
Event Listeners:
// Invalidate cache on file deletion
Storage::disk('cached_temp')->addListener('deleted', function ($path) {
Cache::forget("flysystem_{$path}");
});
Lock Contention:
FileLockingTrait uses flock (process-local). Distributed locks require Redis or database.RedisLock or DatabaseLock.Memory Leaks:
cache_ttl or use file cache driver.Cache Stampedes:
has() calls may flood the cache layer.hasWithCacheValidation() with a short TTL (e.g., 5 minutes).Trait Conflicts:
generateCacheKey).Cache Inspection:
// Dump cache stats
dd(Storage::disk('cached_temp')->getAdapter()->getCache()->stats());
Lock Debugging:
// Check active locks
$locks = Storage::disk('cached_temp')->getAdapter()->getLocks();
TTL Validation:
// Verify TTL for a file
$metadata = Storage::disk('cached_temp')->getMetadata('temp/file.txt');
$expiresAt = $metadata['cache_ttl'] ? now()->addSeconds($metadata['cache_ttl']) : null;
Custom Cache Drivers:
$adapter->setCache(new \League\Flysystem\Cached\Storage\Psr6CacheStorage(
new \Illuminate\Cache\RedisStore()
));
Override Traits:
class CustomTemporaryFileTrait extends TemporaryFileTrait
{
protected function getDefaultTtl(): int
{
return 7200; // 2 hours
}
}
Event Hooks:
// Listen for cache misses
Storage::disk('cached_temp')->getAdapter()->addListener('cache_miss', function ($path) {
Log::debug("Cache miss for {$path}");
});
filesystems.php:
'disks' => [
'cached_temp' => [
'driver' => 'custom',
'adapter' => NaoPon\FlysystemCachedExtra\CachedAdapter::class,
'cache' => env('FILESYSTEM_CACHE', 'file'), // 'redis', 'array', or 'file'
'traits' => [
NaoPon\FlysystemCachedExtra\Traits\TemporaryFileTrait::class,
NaoPon\FlysystemCachedExtra\Traits\FileLockingTrait::class,
],
],
],
Environment Variables:
FILESYSTEM_CACHE=redis
FILESYSTEM_CACHE_TTL=3600
How can I help you explore Laravel packages today?