Installation:
composer require vich/uploader-bundle
Enable the bundle in config/bundles.php:
return [
// ...
Vich\UploaderBundle\VichUploaderBundle::class => ['all' => true],
];
Configure Storage:
Add to config/packages/vich_uploader.yaml:
vich_uploader:
db_driver: orm # or 'mongodb', 'phpcr'
storage: vich_uploader.storage.local_directory
mappings:
products:
uri_prefix: /uploads/products
upload_destination: '%kernel.project_dir%/public/uploads/products'
namer: Vich\UploaderBundle\Naming\SmartUniqueNamer
First Use Case: Create an entity with uploadable fields:
use Vich\UploaderBundle\Mapping\Annotation as Vich;
#[ORM\Entity]
class Product
{
#[Vich\UploadableField(mapping: 'products', fileNameProperty: 'imageName')]
private ?File $imageFile = null;
#[ORM\Column(length: 255)]
private ?string $imageName = null;
// Getters/setters...
}
Form Integration:
{{ form_start(form) }}
{{ form_widget(form.imageFile) }}
{{ form_widget(form.submit) }}
{{ form_end(form) }}
Access Uploaded File:
$product->getImagePath(); // Returns public URL
#[Vich\UploadableField] on entity properties.upload_destination and uri_prefix in vich_uploader.yaml.#[ORM\PreRemove]
public function preRemove(): void
{
if ($this->imageFile) {
$this->imageFile->delete();
}
}
getUploadDir() in your entity:
public function getUploadDir(): string
{
return 'uploads/products/' . $this->category->id;
}
Vich\UploaderBundle\Naming\NamerInterface:
class CustomNamer implements NamerInterface
{
public function name(File $file): string
{
return 'custom_' . uniqid() . '.' . $file->guessExtension();
}
}
services.yaml:
services:
App\Naming\CustomNamer:
tags: ['vich_uploader.namer']
Vich\UploaderBundle\Form\Type\VichFileType:
$builder->add('imageFile', VichFileType::class, [
'required' => false,
'allow_delete' => true,
'download_uri' => true,
]);
use Vich\UploaderBundle\Validator\Constraints as VichAssert;
#[VichAssert\FileMaxSize(maxSize: '1M')]
#[VichAssert\FileMimeType(type: 'image/jpeg')]
private ?File $imageFile = null;
#[Vich\UploadableField(mapping: 'products', fileNameProperty: 'images')] with a Collection or ArrayCollection:
#[ORM\Column(length: 255, nullable: true)]
private ?string $images = null;
#[Assert\All({
new Assert\FileMaxSize(maxSize: '5M'),
new Assert\FileMimeType(type: 'image/*')
})]
private array $imagesFiles = [];
use Vich\UploaderBundle\Message\UploadHandler;
$message = new UploadHandler($entity, $propertyName);
$this->messageBus->dispatch($message);
vich_uploader.storage to use vich_uploader.storage.flysystem:
vich_uploader:
storage: vich_uploader.storage.flysystem
db_driver: orm
mappings:
products:
uri_prefix: /uploads/products
services.yaml:
services:
vich_uploader.storage.flysystem:
class: Vich\UploaderBundle\Storage\FlysystemStorage
arguments:
- '@oneup_flysystem.aws_s3.vich_storage'
VichFileType for file inputs:
{{ form_widget(form.imageFile, {
'attr': {
'class': 'custom-upload-class',
'data-upload-url': path('app_upload')
}
}) }}
#[Route('/upload', name: 'app_upload', methods: ['POST'])]
public function upload(Request $request, UploadHandler $handler): JsonResponse
{
$data = json_decode($request->getContent(), true);
$entity = new Product();
$entity->setImageFile($request->files->get('imageFile'));
$handler->handle($entity, 'imageFile');
$em->persist($entity);
$em->flush();
return new JsonResponse(['success' => true]);
}
vich_uploader:
db_driver: orm
mappings:
products:
uri_prefix: /uploads/products
namer: Vich\UploaderBundle\Naming\SmartUniqueNamer
injections:
image_file: liip_imagine_filter
#[Vich\UploadableField(mapping: 'products', fileNameProperty: 'imageName')]
#[Assert\Image]
private ?File $imageFile = null;
use Vich\UploaderBundle\Event\Event;
use Vich\UploaderBundle\Event\Events;
$dispatcher->addListener(Events::PRE_UPLOAD, function (Event $event) {
$file = $event->getFileObject();
// Custom logic before upload
});
Vich\UploaderBundle\Test\IntegrationTestTrait for tests:
use Vich\UploaderBundle\Test\IntegrationTestTrait;
class ProductTest extends WebTestCase
{
use IntegrationTestTrait;
public function testUpload(): void
{
$client = static::createClient();
$crawler = $client->request('GET', '/product/new');
$form = $crawler->selectButton('Save')->form([
'product[imageFile]' => __DIR__ . '/fixtures/test.jpg',
]);
$client->submit($form);
$this->assertResponseIsSuccessful();
}
}
fileNameProperty in #[Vich\UploadableField] or incorrect upload_destination.#[Vich\UploadableField(mapping: 'products', fileNameProperty: 'imageName')]
private ?File $imageFile = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $imageName = null;
upload_destination.chmod -R 775 %kernel.project_dir%/public/uploads
#[ORM\PreRemove].#[ORM\PreRemove]
public function preRemove(): void
{
if ($this->imageFile) {
$this->imageFile->delete();
}
}
#[Assert\Valid] on entity.$builder->addEvent
How can I help you explore Laravel packages today?