Installation:
composer require vich/uploader-bundle
Add to config/bundles.php:
return [
// ...
Vich\UploaderBundle\VichUploaderBundle::class => ['all' => true],
];
Configure Storage:
Define upload paths in config/packages/vich_uploader.yaml:
vich_uploader:
db_driver: orm # or 'mongodb', 'phpcr'
storage: '%kernel.project_dir%/public/uploads'
First Use Case:
Product) with a file field:
use Vich\UploaderBundle\Mapping\Annotation as Vich;
class Product {
/**
* @Vich\UploadableField(mapping="product_images", fileDir="products/")
*/
private $imageFile;
}
php bin/console make:migration).$builder->add('imageFile', FileType::class);
Entity Mapping:
@Vich\UploadableField) or YAML/XML for configuration./**
* @Vich\UploadableField(mapping="documents", fileDir="documents/")
*/
private $documentFile;
Handling Uploads:
$product->setImageFile($request->files->get('imageFile'));
$em->persist($product);
$em->flush();
Public URLs:
{{ vich_uploader_asset(product.imageFile) }}
$this->get('vich_uploader.templating.helper')->getUrl($product->getImageFile());
Batch Processing:
Vich\UploaderBundle\Handler\UploadHandler for custom logic:
$handler = $this->get('vich_uploader.upload_handler');
$handler->upload($product, 'imageFile');
MongoDB/PHPCR:
db_driver in config and adjust mappings (e.g., @Vich\UploadableField for documents).Symfony Forms:
FileType for single files, CollectionType for multiple files.$builder->add('documents', CollectionType::class, [
'entry_type' => FileType::class,
'allow_add' => true,
'allow_delete' => true,
]);
Validation:
use Symfony\Component\Validator\Constraints as Assert;
/**
* @Assert\File(maxSize="1024k")
* @Vich\UploadableField(mapping="images", fileDir="images/")
*/
private $imageFile;
Custom Storage:
Vich\UploaderBundle\Storage\StorageInterface for cloud storage (e.g., S3):
vich_uploader:
storage: vich_uploader.storage.s3
Register service in services.yaml:
services:
Vich\UploaderBundle\Storage\StorageInterface vich_uploader.storage.s3:
class: App\Storage\S3Storage
arguments: ['@aws_s3.client']
Events:
vich_uploader.pre_upload or vich_uploader.post_upload:
$eventDispatcher->addListener('vich_uploader.pre_upload', function (UploadEvent $event) {
// Custom logic before upload
});
File Deletion:
preRemove lifecycle callback is bypassed.preRemove is called or manually trigger deletion:
$handler->remove($entity, 'fieldName');
Circular Dependencies:
@Vich\UploadableField.Case Sensitivity:
fileDir consistently.Large Files:
upload_max_filesize, post_max_size) may block large uploads.php.ini or use chunked uploads (e.g., Symfony Uploader).Doctrine Proxy Classes:
getRealPath() or ensure entities are initialized before upload.Logs:
monolog:
handlers:
main:
level: debug
var/log/dev.log for VichUploaderBundle entries.Common Errors:
fileDir paths are correct and writable.chmod -R 775 public/uploads
Database Mismatch:
vich_uploader.db_driver consistently (e.g., orm for Doctrine).Dynamic FileDirs:
%kernel.project_dir%) or services for dynamic paths:
vich_uploader:
storage: '%app.upload_dir%'
Define in parameters.yaml:
app.upload_dir: '%kernel.project_dir%/public/custom_uploads'
Naming Strategies:
namer:
vich_uploader:
db_driver: orm
storage: public/uploads
namers:
product_images: Vich\UploaderBundle\Naming\SmartUniqueNamer
class CustomNamer implements NamerInterface {
public function name($object, $field, $originalName) {
return 'custom_' . uniqid() . '.' . pathinfo($originalName, PATHINFO_EXTENSION);
}
}
Asset Helper:
vich_uploader_asset fails if the file is not uploaded yet.null or use a fallback:
{% if product.imageFile %}
{{ vich_uploader_asset(product.imageFile) }}
{% else %}
{{ asset('images/default.png') }}
{% endif %}
Custom Storage:
Vich\UploaderBundle\Storage\StorageInterface for cloud storage (e.g., S3, GCS):
class S3Storage implements StorageInterface {
public function store($object, $field, $file) { /* ... */ }
public function delete($object, $field) { /* ... */ }
public function update($object, $field, $newFile, $oldFile) { /* ... */ }
}
Event Subscribers:
class CustomUploadSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents() {
return [
UploadEvent::PRE_UPLOAD => 'onPreUpload',
UploadEvent::POST_UPLOAD => 'onPostUpload',
];
}
public function onPreUpload(UploadEvent $event) {
// Modify file before upload
}
}
Doctrine Lifecycle Callbacks:
Vich\UploaderBundle\Event\EventDispatcherInterface:
$dispatcher->addListener('vich_uploader.pre_remove', function (UploadEvent $event) {
// Custom logic before file deletion
});
Twig Extensions:
class CustomTwigExtension extends \Twig_Extension {
public function getFunctions() {
return [
new \Twig_SimpleFunction('custom_asset', [$this
How can I help you explore Laravel packages today?