Integrating VichUploaderBundle to Upload Files and Images
=========================================================
In this article you'll learn how to allow uploading files in your backends, both
images and regular files, such as PDF files.
Although EasyAdmin doesn't provide any built-in feature to upload files, it
integrates seamlessly with `VichUploaderBundle`_, the most popular file uploader
Symfony bundle.
Installing the File Uploader Bundle
-----------------------------------
1) Install the bundle:
.. code-block:: terminal
$ composer require vich/uploader-bundle
2) Enable the bundle:
.. code-block:: php
// app/AppKernel.php
class AppKernel extends Kernel
{
public function registerBundles()
{
return array(
// ...
new Vich\UploaderBundle\VichUploaderBundle(),
);
}
}
3) Add the minimal configuration that makes the bundle work:
.. code-block:: yaml
vich_uploader:
db_driver: orm
Uploading Image Files
---------------------
First you'll learn how to upload and preview images in the backend. Then, in the
next section, you'll see how to upload other types of files (such as PDFs).
Configuring the Uploading of Image Files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Before uploading files, you must configure the "mappings" for the
VichUploaderBundle. These "mappings" tell the bundle where should the files be
uploaded and which paths should be used to display them in the application.
This is the configuration needed for this example:
.. code-block:: yaml
# app/config/config.yml
parameters:
app.path.product_images: /uploads/images/products
# ...
vich_uploader:
# ...
mappings:
product_images:
uri_prefix: '%app.path.product_images%'
upload_destination: '%kernel.root_dir%/../web%app.path.product_images%'
The ``product_images`` value is a freely chosen name which holds the configuration
for a specific mapping. This value will be used later in the entity configuration.
The uploaded images are stored in the directory defined in ``upload_destination``.
The ``uri_prefix`` option defines the base path prepended to file paths so they
can be displayed in the application. In this example, the ``uri_prefix`` value is
defined as a container parameter, because we'll reuse this value in the EasyAdmin
configuration later.
Preparing your Entities to Persist Images
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Considering that the ``Product`` entity is already created, the first change you
need to make is adding the ``Uploadable`` annotation to the entity class:
.. code-block:: php
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* @ORM\Entity
* @Vich\Uploadable
*/
class Product
{
// ...
}
Then, you need to add two new properties (``image`` and ``imageFile``):
.. code-block:: php
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* @ORM\Entity
* @Vich\Uploadable
*/
class Product
{
/**
* @ORM\Column(type="string", length=255)
* @var string
*/
private $image;
/**
* @Vich\UploadableField(mapping="product_images", fileNameProperty="image")
* @var File
*/
private $imageFile;
/**
* @ORM\Column(type="datetime")
* @var \DateTime
*/
private $updatedAt;
// ...
public function setImageFile(File $image = null)
{
$this->imageFile = $image;
// VERY IMPORTANT:
// 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
if ($image) {
// if 'updatedAt' is not defined in your entity, use another property
$this->updatedAt = new \DateTime('now');
}
}
public function getImageFile()
{
return $this->imageFile;
}
public function setImage($image)
{
$this->image = $image;
}
public function getImage()
{
return $this->image;
}
}
The ``image`` property stores just the name of the uploaded image and it's
persisted in the database. The ``imageFile`` property stores the binary contents
of the image file and it's not persisted in the database (that's why it doesn't
define a ``@ORM`` annotation).
The ``imageFile`` property must define a ``@Vich\UploadableField`` annotation that
configures both the "mapping" to use (``product_images`` in this case) and the
entity property that stores the image name (``image`` in this case).
Displaying the Images in the ``list`` and ``show`` Views
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use the special ``image`` type in the ``list`` and ``show`` views to display the
contents of a property as an image:
.. code-block:: yaml
easy_admin:
entities:
Product:
# ...
list:
fields:
- { property: 'image', type: 'image', base_path: '%app.path.product_images%' }
# ...
show:
fields:
- { property: 'image', type: 'image', base_path: '%app.path.product_images%' }
The property used to display the image must be the one that stores the image path
(``image`` in this case) and not the one that stores the binary contents of the
image (``imageFile``). Since this property only stores the image name, you must also
define the ``base_path`` option to prepend the path to make the image accessible.
Instead of hardcoding the ``base_path`` value, this example uses the
``app.path.product_images`` container parameter which also was used in the
VichUploaderBundle configuration.
.. tip::
If you define `custom namers`_ in VichUploaderBundle, images won't be
displayed correctly because their paths will be wrong. The simplest solution
is to define a custom template fragment to display the image and use in it
the ``vich_uploader_asset()`` Twig function:
.. code-block:: yaml
easy_admin:
entities:
Product:
# ...
list:
fields:
- { property: 'image', template: 'vich_uploader_image.html.twig' }
.. code-block:: twig
{# app/Resources/views/easy_admin/vich_uploader_image.html.twig #}
{# the second parameter is the name of the property with the UploadableField annotation #}