Installation
composer require daemon/filestorage-bundle
Add to config/bundles.php:
return [
Daemon\FilestorageBundle\FilestorageBundle::class => ['all' => true],
];
Configuration Publish the default config:
php bin/console daemon:filestorage:install
Edit config/packages/daemon_filestorage.yaml to define storage paths (e.g., storage_path: '%kernel.project_dir%/storage/files').
First Upload
Use the FilestorageManager service in a controller:
use Daemon\FilestorageBundle\Manager\FilestorageManager;
public function upload(Request $request, FilestorageManager $manager)
{
$file = $request->file('file');
$path = $manager->store($file, 'user_uploads'); // 'user_uploads' is a configured storage key
return response()->json(['path' => $path]);
}
config/packages/daemon_filestorage.yaml: Storage configurations (keys, paths, permissions).src/Manager/FilestorageManager.php: Core logic for file operations.src/EventListener/FilestorageListener.php: Event hooks (e.g., post-upload).File Uploads
FilestorageManager::store() for saving files to a specific storage key:
$path = $manager->store($request->file('document'), 'documents');
FilestorageManager::getPath()/getUrl().File Deletion
$manager->delete('documents', 'report.pdf');
// or
$manager->deleteByPath($fullPath);
Custom Storage Keys
daemon_filestorage:
storages:
user_avatars: '%kernel.project_dir%/storage/avatars/%user_id%'
user_id context to resolve paths:
$path = $manager->store($file, 'user_avatars', ['user_id' => 123]);
Events
filestorage.pre_store/filestorage.post_store:
// config/services.yaml
Daemon\FilestorageBundle\EventListener\FilestorageListener:
tags:
- { name: kernel.event_listener, event: filestorage.pre_store, method: onPreStore }
Symfony Uploader Integration
Pair with VichUploaderBundle for entity-based file handling:
use Daemon\FilestorageBundle\Annotation as Filestorage;
class User {
#[Filestorage\Uploadable('user_avatars', context: ['user_id' => 'id'])]
private $avatar;
}
Validation Validate file types/sizes before upload:
$file = $request->validate()->file('file')->assertMimes(['image/jpeg']);
Symlinks for Web Access
Create a symlink from public/uploads to your storage path for direct web access:
ln -s %kernel.project_dir%/storage/files %kernel.project_dir%/public/uploads
Permissions
chmod -R 775 %kernel.project_dir%/storage/files
FilestorageManager::checkPermissions().Path Resolution
user_id) will break path resolution.
Fix: Validate context keys in config or use defaults:
storages:
user_files: '%kernel.project_dir%/storage/files/%user_id%/%default%'
Overwriting Files
FilestorageManager::storeUnique() to append hashes:
$path = $manager->storeUnique($file, 'documents');
Event Order
pre_store events can modify the file (e.g., resize) but must not call store() recursively to avoid infinite loops.Symlink Caveats
Log Storage Events
Enable debug mode in config/packages/daemon_filestorage.yaml:
debug: true
Logs will appear in var/log/dev.log.
Check Paths
Use FilestorageManager::getStoragePath() to verify resolved paths:
$path = $manager->getStoragePath('documents', ['user_id' => 123]);
Custom Storage Handlers
Implement Daemon\FilestorageBundle\Storage\StorageInterface for S3, FTP, etc.:
class S3Storage implements StorageInterface {
public function store(File $file, string $path): string { /* ... */ }
}
Register in config/services.yaml:
Daemon\FilestorageBundle\Storage\S3Storage:
arguments:
- '@aws.s3.client'
tags: { name: daemon_filestorage.storage, alias: 's3' }
File Processing
Extend the FilestorageListener to add pre/post-processing:
public function onPreStore(PreStoreEvent $event) {
$file = $event->getFile();
// Resize image, etc.
$event->setFile($processedFile);
}
Dynamic Config
Override storage paths at runtime using FilestorageManager::setStoragePath():
$manager->setStoragePath('temp_uploads', '/tmp/uploads');
How can I help you explore Laravel packages today?