sajad torkamani

In a nutshell

VichUploaderBundle is a Symfony bundle that provides an easy way to link file uploads with ORM entities or MongoDB ODM documents.

Its features include:

  • Set the file in the entity as an instance of Symfony\Component\HttpFoundation\File\File when the entity is loaded from the datastore.
  • Delete the file from the file system when the entity/document is removed from the datastore.
  • Templating helpers to generate public URLs to the file.

Usage

1. Install and register bundle

Install package:

composer require vich/uploader-bundle

Register (if not using Symfony Flex):

// app/AppKernel.php (your kernel class may be defined in a different class/path)
class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = [
            // ...
            new Vich\UploaderBundle\VichUploaderBundle(),
            // ...
        ];
    }
}

2. Configure persistence engine

# config/packages/vich_uploader.yaml or app/config/config.yml
vich_uploader:
    db_driver: orm # or mongodb or phpcr

3. Configure an upload mapping

# config/packages/vich_uploader.yaml or app/config/config.yml
vich_uploader:
    db_driver: orm

    metadata:
        type: attribute

    mappings:
        products:
            uri_prefix: /images/products
            upload_destination: '%kernel.project_dir%/public/images/products'
            namer: Vich\UploaderBundle\Naming\SmartUniqueNamer

You need to define three things as a minimum:

  1. <mapping-name>: products in the above example.
  2. uri_prefix: The public web path to the upload destination – the URL that users will be able to access files from.
  3. upload_destination: The location on the server the files should be uploaded.

4. Link the upload mapping to an entity

Create a link between the filesystem and an entity by adding an Uploadable annotation to an entity. This is like a flag that tells the bundle that a given entity contains uploadable fields.

Next, add two fields:

  1. Create a persistent field (e.g., imageName) that will be stored in the database as a string. This will contain the filename of the uploaded file.
  2. Create a non-persistent (e.g., imageFile) that will store the UploadedFile object after the form is submitted. This shouldn’t be persisted in the database, but you must annotate it.

Here’s an example entity that contains all the above:

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;

#[ORM\Entity]
#[Vich\Uploadable]
class Product
{
    #[ORM\Id]
    #[ORM\Column(type: 'integer')]
    #[ORM\GeneratedValue(strategy: 'AUTO')]
    private ?int $id = null;

   // ... other fields

    // Path to file stored in "<mapping>.storage"
    #[ORM\Column(nullable: true)]
    private ?string $imageFilePath = null;
   

    // NOTE: This is not a mapped field of entity metadata, just a simple property.
    #[Vich\UploadableField(mapping: 'products', fileNameProperty: 'imageName', size: 'imageSize')]
    private ?File $imageFile = null;

    // Auxiliary property to handle base64 encoded uploads on JSON requests
    private ?string $imageFileBase64 = null;

    #[ORM\Column(type: 'string')]
    private ?string $imageName = null;

    #[ORM\Column(type: 'integer')]
    private ?int $imageSize = null;

    #[ORM\Column(type: 'datetime')]
    private ?\DateTimeInterface $updatedAt = null;

    /**
     * If manually uploading a file (i.e. not using Symfony Form) ensure an instance
     * of 'UploadedFile' is injected into this setter to trigger the update. If this
     * bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
     * must be able to accept an instance of 'File' as the bundle will inject one here
     * during Doctrine hydration.
     *
     * @param File|\Symfony\Component\HttpFoundation\File\UploadedFile|null $imageFile
     */
    public function setImageFile(?File $imageFile = null): void
    {
        $this->imageFile = $imageFile;

        if (null !== $imageFile) {
            // It is required that at least one field changes if you are using doctrine
            // otherwise the event listeners won't be called and the file is lost
            $this->updatedAt = new \DateTimeImmutable();
        }
    }

    public function getImageFile(): ?File
    {
        return $this->imageFile;
    }

    public function setImageName(?string $imageName): void
    {
        $this->imageName = $imageName;
    }

    public function getImageName(): ?string
    {
        return $this->imageName;
    }

    public function setImageSize(?int $imageSize): void
    {
        $this->imageSize = $imageSize;
    }

    public function getImageSize(): ?int
    {
        return $this->imageSize;
    }
}

5. Configure the lifecycle events (optional)

You can configure when files should be removed using the below configuration options:

# config/packages/vich_uploader.yaml or app/config/config.yml
vich_uploader:
    db_driver: orm
    mappings:
        products:
            uri_prefix: /images/products
            upload_destination: '%kernel.project_dir%/public/images/products'
            namer: Vich\UploaderBundle\Naming\SmartUniqueNamer

            inject_on_load: false
            delete_on_update: true
            delete_on_remove: true
  • delete_on_remove: default true, should the file be deleted when the entity is removed ;
  • delete_on_update: default true, should the file be deleted when a new file is uploaded ;
  • inject_on_load: default false, should the file be injected into the uploadable entity when it is loaded from the data store. The object will be an instance of Symfony\Component\HttpFoundation\File\File.

Other notes

Sources

Tagged: Symfony