Installation
composer require betamfd/file-handler-bundle
Add to config/bundles.php (Symfony):
return [
// ...
BetaMFD\FileHandlerBundle\BetaMFDFileHandlerBundle::class => ['all' => true],
];
First Use Case Upload a file via a Symfony form:
// src/Form/FileUploadType.php
use BetaMFD\FileHandlerBundle\Form\FileType;
class FileUploadType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('file', FileType::class, [
'label' => 'Upload File',
'mime_types' => ['image/jpeg', 'image/png'],
'max_size' => '10M',
]);
}
}
Handling Uploads
// src/Controller/FileUploadController.php
use BetaMFD\FileHandlerBundle\Service\FileHandler;
class FileUploadController extends AbstractController {
public function upload(Request $request, FileHandler $fileHandler) {
$form = $this->createForm(FileUploadType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$file = $form->get('file')->getData();
$path = $fileHandler->store($file, 'uploads');
// $path now contains the stored file location
}
}
}
File Validation & Processing
// Validate and process with custom rules
$fileHandler->validate($file, [
'mime_types' => ['application/pdf'],
'max_size' => '5M',
'extensions' => ['pdf'],
'custom' => function ($file) {
return $file->getClientOriginalExtension() === 'pdf';
}
]);
Storage Integration
$path = $fileHandler->store($file, 'custom_directory');
config/packages/betamfd_file_handler.yaml:
betamfd_file_handler:
storage:
default: 'local'
disks:
s3:
driver: 's3'
key: '%env(AWS_ACCESS_KEY_ID)%'
secret: '%env(AWS_SECRET_ACCESS_KEY)%'
bucket: 'my-bucket'
Use in code:
$path = $fileHandler->store($file, 'uploads', 's3');
File Metadata & Manipulation
// Get metadata
$metadata = $fileHandler->getMetadata($file);
// Resize images (if ImageMagick is installed)
$resizedPath = $fileHandler->resize($file, 800, 600);
Batch Processing
$files = $request->files->all();
foreach ($files['documents'] as $file) {
$fileHandler->store($file, 'documents');
}
Symfony Events Listen for file upload events:
// src/EventListener/FileUploadListener.php
use BetaMFD\FileHandlerBundle\Event\FileUploadEvent;
class FileUploadListener {
public function onFileUpload(FileUploadEvent $event) {
if ($event->getFile()->getClientOriginalExtension() === 'pdf') {
$event->setPath('pdfs/' . $event->getPath());
}
}
}
Register in services.yaml:
services:
App\EventListener\FileUploadListener:
tags:
- { name: kernel.event_listener, event: betamfd.file_upload, method: onFileUpload }
Custom Storage Adapters
Extend BetaMFD\FileHandlerBundle\Storage\StorageInterface:
class CustomStorage implements StorageInterface {
public function store(File $file, string $directory): string {
// Custom logic
}
// Implement other methods...
}
Register in config:
betamfd_file_handler:
storage:
disks:
custom:
driver: 'custom'
adapter: App\Storage\CustomStorage
API File Handling
// For API responses
$filePath = $fileHandler->store($file, 'exports');
return $this->file($filePath, 'report.pdf', [
'Content-Type' => 'application/pdf',
]);
File Size Limits
post_max_size and upload_max_filesize in php.ini exceed your max_size config.config/packages/framework.yaml:
framework:
http_method_override: true
form: true
csrf_protection: true
# Ensure these are not stricter than your bundle config
Mime Type Validation
image/jpeg vs jpeg). Use extensions fallback:
betamfd_file_handler:
validation:
mime_types: ['image/jpeg']
extensions: ['jpg', 'jpeg'] # Fallback
Race Conditions in Storage
$path = $fileHandler->store($file, 'uploads', null, true); // $unique = true
Cloud Storage Timeouts
set_time_limit(300); // 5 minutes
$fileHandler->store($file, 'large_files');
Enable Verbose Logging
betamfd_file_handler:
debug: true
Check logs at var/log/dev.log for detailed storage operations.
Validate File Paths
file_exists() to verify stored files:
if (!file_exists($path)) {
throw new \RuntimeException('File not stored correctly.');
}
Check Storage Permissions
chmod -R 775 var/storage
Custom File Naming Override default naming strategy:
$fileHandler->setNamingStrategy(function (File $file) {
return 'custom_' . time() . '_' . $file->getClientOriginalName();
});
Post-Processing Hooks Use events to add logic after storage:
// src/EventSubscriber/FileUploadSubscriber.php
class FileUploadSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents() {
return [
'betamfd.file_upload.post_store' => 'onPostStore',
];
}
public function onPostStore(FileUploadEvent $event) {
// Example: Generate a thumbnail
$fileHandler = $event->getFileHandler();
$fileHandler->resize($event->getFile(), 200, 200);
}
}
Fallback Storage
Configure fallback disks in betamfd_file_handler.yaml:
betamfd_file_handler:
storage:
disks:
primary:
driver: 's3'
fallback: 'local' // Falls back to local if S3 fails
Symfony Messenger Integration Dispatch file processing as async jobs:
use BetaMFD\FileHandlerBundle\Message\ProcessFileMessage;
$this->messageBus->dispatch(new ProcessFileMessage($file, 'uploads'));
Configure in config/packages/messenger.yaml:
framework:
messenger:
transports:
async: '%env(MESSENGER_TRANSPORT_DSN)%'
routing:
'BetaMFD\FileHandlerBundle\Message\ProcessFileMessage': async
How can I help you explore Laravel packages today?