Skip to main content

Add an image field to an entity, using vichuploader

Symfony

The process of adding file uploads to an entity is documented in the Symfony cookbook. As one quickly notices, the default technique requires you to hard-code a file path within the entity, and copy-paste some dull code. The VichUploader Bundle (get it at github) moves required paths to the config.yml file and abstracts some of that code away. But you'll still need to mess about when you add an image or other uploadable item to your entity.

The Checklist

  1. Ensure that your entity is using the necessary classes
  2. Annotate the entity class
  3. Add two properties to the entity - an unmapped "file" field, and a mapped "string" to store the filename
  4. Add the required VichUploader configuration to config.yml
  5. If your entity doesn't already have an "Updated" property, add one

You may also want to add a custom "namer" to specify rules for naming the uploaded file.

  1. create a namer
  2. register the namer as a service

Assumptions: these steps presuppose that you already have a site bundle in place - src/Acme/Bundle - and that you have already followed the general configuration guidelines for VichUploader.

Step 1

Open the file containing your entity - likely in the acme/somebundle/entity folder. Let's call our class Player.php. At the top of the file, add these lines:



/* filename src/Acme/SomeBundle/Entity/Player.php */
namespace Acme\SomeBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Validator\Constraints as Assert;
use Vich\UploaderBundle\Mapping\Annotation as Vich;

Step 2

Add these annotations to the class declaration: @Vich\Uploadable @ORM\HasLifecycleCallbacks When you're done, it will look like this:


/* filename src/Acme/SomeBundle/Entity/Player.php */

/**
 * // ..other declarations
 * @Vich\Uploadable 
 * @ORM\HasLifecycleCallbacks
 */
class Player
{
    //etc..
}

Step 3

The key to uploading files in Symfony2, whether using VichUploader or not, is to add two new properties to your entity. One of these is of the type 'file', and will be used to generate an upload widget in the entity form. This field is not mapped - meaning that its content is not saved in the entity's database table. That job goes to the second new property we are adding, which will be of the type "string" and will store the actual filename of our upload. In this example let's name the file field "File" and the other property "Image". You will need to add the following batch of code to your entity:


/* filename src/Acme/SomeBundle/Entity/Player.php */

class Player
{

// ... 

    /**
     * @ORM\Column(name="image", type="string", length=255, nullable=true)
     */
    private $image;

    /**
     * @return string
     */
    public function getImage()
    {
        return $this->image;
    }

    /**
     * @return Player
     */
    public function setImage($image)
    {
        $this->image = $image;

        return $this;
    }

    /**
     * @Assert\Image(
     *     maxSize="100000"
     *     // other validation criteria as required
     * )
     * @Vich\UploadableField(mapping="player_image", fileNameProperty="image", nullable=true)
     *
     * @var File $file
     */
    protected $file;

    /**
     * @param UploadedFile $file
     */
    public function setFile(File $file = null)
    {
        $this->file = $file;
        $this->updated = new \DateTime();
    }

    /**
     * @return UploadedFile
     */
    public function getFile()
    {
        return $this->file;
    }
}

Take note of the highlighted code: these two elements must agree. That is, if you changed the Image property to something like audio, you would change fileNameProperty="image" to fileNameProperty="audio".

Step 4

Now you have to add mapping details to the VichUploader block of your config.yml file. In the entity class, you'll notice this annotation in the $file definition: @Vich\UploadableField(mapping="player_image", fileNameProperty="image", nullable=true)



vich_uploader:
    db_driver: orm
    twig: true
    gaufrette: false
    storage: vich_uploader.storage.file_system


    mappings:
        player_image:
            uri_prefix: /%uploads_dir%/player # folder to store these images
            upload_destination: %data_root_path%/%uploads_dir%/artist # %kernel.root_dir%/../web/releases
            namer: ~ # specify a file namer
            directory_namer: ~ # specify a directory namer 
            delete_on_remove: true # whether to delete file upon removal of entity
            inject_on_load: true # whether to inject a File upon load

Step 5

Step 5 - add an "updated" field and its associated setter/getters - is required to ensure that Symfony saves new versions of your file if you change the file you originally uploaded. (more to come...) 6) create a namer 7) register the namer as a service