Installation Add the package via Composer (direct Git URL due to lack of Packagist listing):
composer require 2lenet/file-bundle
Register the bundle in config/bundles.php:
return [
// ...
FileBundle\FileBundle::class => ['all' => true],
];
First Use Case
Inject FileManager into a controller/service and generate a filename for an entity’s file:
use FileBundle\Manager\FileManagerInterface;
class MyController extends AbstractController
{
public function __construct(private FileManagerInterface $fileManager) {}
public function uploadFile(MyEntity $entity)
{
$fileSpec = $this->fileManager->getLocalFilename(
MyEntity::PDF_STORAGE_NAME, // Constant in entity
$entity,
'pdf' // File extension
);
// Use $fileSpec['path'] (absolute) and $fileSpec['filename'] (DB-safe)
}
}
Entity Integration
PDF_STORAGE_NAME = 'user_pdf').getId() method (required by FileManager).File Storage
getLocalFilename() for direct filesystem storage.
$fileSpec = $this->fileManager->getLocalFilename('store_name', $entity, 'ext');
// $fileSpec = ['path' => '/absolute/path', 'filename' => 'hash.ext']
getDatabaseFilename() for storing paths in DB (e.g., for cloud storage):
$dbPath = $this->fileManager->getDatabaseFilename('store_name', $entity, 'ext');
Validation & Sanitization
config/packages/file_bundle.yaml).Custom Storage Engines
FileBundle\Storage\StorageInterface to support S3, Dropbox, etc.:
class S3Storage implements StorageInterface {
public function getPath(string $storeName): string { ... }
public function getFilename(string $storeName, string $id, string $extension): string { ... }
}
services.yaml:
FileBundle\Manager\FileManager:
arguments:
$storage: '@app.s3_storage' # Your custom service
No Packagist Listing
"2lenet/file-bundle": "dev-main#123abc"
Storage Naming Collisions
store_name across entities? Files will share the same directory. Use unique prefixes (e.g., user_avatar, product_manual).Missing getId()
FileManager expects entities to implement getId(). Use traits or abstract classes to enforce this:
abstract class BaseEntity {
abstract public function getId(): ?int;
}
Extension Whitelist
['jpg', 'png', 'pdf', 'txt']. Override in config:
file_bundle:
allowed_extensions: ['jpg', 'png', 'pdf', 'docx', 'xlsx']
$fileSpec to verify paths/filenames:
$this->logger->debug('Generated file spec', ['spec' => $fileSpec]);
config/packages/file_bundle.yaml for storage_path (defaults to public/uploads).Custom Filename Hashing
Override the hashing logic in a custom StorageInterface implementation:
public function getFilename(string $storeName, string $id, string $extension): string {
return md5($id . $extension) . '.' . $extension; // Custom hash
}
Event Listeners
Hook into file operations via Symfony events (e.g., file.pre_upload):
# config/services.yaml
FileBundle\EventListener\FileUploadListener:
tags:
- { name: kernel.event_listener, event: file.pre_upload, method: onPreUpload }
Symfony Uploader Integration
Pair with VichUploaderBundle for seamless file handling:
use Vich\UploaderBundle\Mapping\Annotation as Vich;
class MyEntity {
#[Vich\UploadableField(mapping: 'user_pdf', fileNameProperty: 'pdfPath')]
private ?File $pdfFile = null;
}
How can I help you explore Laravel packages today?