Installation:
composer require bengor-file/file-bundle
Register the bundle in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony <4):
return [
// ...
BenGor\FileBundle\BenGorFileBundle::class => ['all' => true],
];
Configuration: Publish the default config:
php bin/console ben-gor-file:install
Edit config/packages/ben_gor_file.yaml to define storage paths, allowed extensions, and file limits.
First Use Case: Upload a file via a form and process it in a controller:
use BenGor\FileBundle\Service\FileManager;
public function upload(Request $request, FileManager $fileManager)
{
$file = $request->files->get('file');
$savedFile = $fileManager->save($file, 'uploads');
return new JsonResponse(['path' => $savedFile->getPath()]);
}
FileManager: Core service for file operations (save, delete, move, etc.).FileValidator: Validate files against rules (size, type, etc.).StorageAdapter: Interface for custom storage backends (e.g., S3, local filesystem).use BenGor\FileBundle\Service\FileValidator;
public function uploadWithValidation(Request $request, FileValidator $validator, FileManager $fileManager)
{
$file = $request->files->get('file');
// Validate against rules defined in config (e.g., maxSize: 5MB, allowedExtensions: ['jpg', 'png'])
if (!$validator->validate($file)) {
throw new \RuntimeException('Invalid file');
}
$savedFile = $fileManager->save($file, 'uploads');
return new JsonResponse(['success' => true, 'path' => $savedFile->getUrl()]);
}
Extend StorageAdapter to support cloud storage (e.g., AWS S3):
use BenGor\FileBundle\Storage\StorageAdapter;
class S3StorageAdapter implements StorageAdapter
{
public function save(File $file, string $directory): File
{
// Implement S3 upload logic
return $file;
}
// Implement other required methods (delete, move, etc.)
}
Register the adapter in services.yaml:
services:
BenGor\FileBundle\Service\FileManager:
arguments:
$storageAdapter: '@app.s3_storage_adapter'
Chain operations using the FileManager:
$file = $fileManager->save($request->file, 'uploads')
->resize(800, 600) // If using Image extension
->optimize()
->getFile();
Listen for file deletion events to clean up related data:
// config/services.yaml
services:
App\EventListener\FileDeleteListener:
tags:
- { name: kernel.event_listener, event: ben_gor_file.delete, method: onFileDelete }
FileType with custom constraints:
use BenGor\FileBundle\Form\Type\FileType;
$builder->add('file', FileType::class, [
'constraints' => [
new \BenGor\FileBundle\Validator\Constraints\File([
'maxSize' => '5M',
'allowedExtensions' => ['jpg', 'png'],
]),
],
]);
use BenGor\FileBundle\Service\FileUrlGenerator;
$urlGenerator = new FileUrlGenerator($fileManager, $request);
$signedUrl = $urlGenerator->generateSignedUrl($savedFile);
FileManager mock in PHPUnit:
$mockFileManager = $this->createMock(FileManager::class);
$mockFileManager->method('save')->willReturn(new File('path/to/file.jpg'));
Deprecated Symfony Version:
services.yaml vs. config.yml).kernel.event_listener tags).Missing Laravel-Specific Features:
class FileManagerFacade extends \Illuminate\Support\Facades\Facade
{
protected static function getFacadeAccessor() { return 'ben_gor_file.manager'; }
}
Configuration Overrides:
ben_gor_file.yaml. If missing, it uses defaults, which may not suit Laravel’s filesystem structure.storage_path in config:
ben_gor_file:
storage:
local:
path: '%kernel.project_dir%/storage/app/files'
File Permissions:
storage/ directory may require:
chmod -R 775 storage/
Storage facade to generate absolute paths if needed:
$path = storage_path('app/files/' . $file->getFilename());
Event Dispatching:
ben_gor_file.upload or ben_gor_file.delete may not fire as expected in Laravel due to differing event systems.$event = new FileUploadEvent($file);
$this->get('event_dispatcher')->dispatch($event, 'ben_gor_file.upload');
Log File Operations:
Enable debug mode in ben_gor_file.yaml:
ben_gor_file:
debug: true
Logs will appear in var/log/dev.log (Symfony) or Laravel’s storage/logs.
Validate File Rules: If validation fails silently, check the validator’s rules in config:
ben_gor_file:
validation:
max_size: 10M
allowed_extensions: [jpg, png, pdf]
disallowed_extensions: []
Tip: Use the FileValidator directly to debug:
$errors = $validator->validate($file);
dd($errors); // Inspect validation errors
Storage Adapter Issues:
StorageAdapter is properly injected and configured.save method:
public function save(File $file, string $directory): File
{
\Log::debug('Saving file to: ' . $directory, ['file' => $file->getFilename()]);
// ...
}
Custom File Metadata:
Extend the File class to add Laravel-specific metadata (e.g., user_id, created_at):
class LaravelFile extends \BenGor\FileBundle\Model\File
{
protected $userId;
protected $createdAt;
// Add getters/setters and hydration logic
}
Register the custom class in services.yaml:
BenGor\FileBundle\Model\File: '@app.laravel_file'
Dynamic Storage Paths: Override the storage path dynamically (e.g., per user):
$fileManager->setStoragePath('uploads/' . auth()->id());
$fileManager->save($file);
Presigned URLs:
For cloud storage (e.g., S3), create a custom FileUrlGenerator:
use Aws\S3\S3Client;
class S3UrlGenerator implements FileUrlGeneratorInterface
{
public function generateSignedUrl(File $file): string
{
$s3 = new S3Client([/* config */]);
return $s3->getObjectUrl('bucket', $file->getPath());
}
}
**
How can I help you explore Laravel packages today?