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
- Ensure that your entity is using the necessary classes
- Annotate the entity class
- Add two properties to the entity - an unmapped "file" field, and a mapped "string" to store the filename
- Add the required VichUploader configuration to config.yml
- 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.
- create a namer
- 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