Installation et l'utilisation du composant Vich Uploader pour l'upload de fichiers

Objectifs

  • Apprendre à installer et configurer le composant Vich Uploader

  • Apprendre à utiliser le composant Vich Uploader pour téléverser un fichier

Rappel

Nous venons de voir comment mettre en place un téléversement de fichier avec les formulaires de Symfony. L'exemple était de donner la possibilité de rattacher une photo à un produit.

Maintenant, nous allons voir comment intégrer un composant de téléchargement de fichier qui va nous permettre de :

  • Simplifier et uniformiser le processus de téléchargement de fichier,

  • Ne pas coder tout le processus de sauvegarde.

Contexte

Dans le contexte d'une pratique professionnelle, vous utiliserez la notion d'upload de fichier dans le cas où vous aurez besoin de donner la possibilité de présenter une description autre que du texte (image, pdf, etc.), de stocker les fichiers sur le serveur et en base de données.

Dans cette partie, nous allons associer une image à une fiche produit grâce au composant VichUploader, afin de donner un visuel plus attractif du produit. Le fichier sera stocké sur le serveur et son nom sera mis en base de données en tant que propriété du produit.

Commençons par installer et configurer le composant de VichUploader.

Méthode

Pour installer le composant VichUploader, nous allons utiliser Composer, le gestionnaire de composants PHP.

Le nom du composant : vich/uploader-bundle

À la racine du projet où se trouve le fichier « composer.json », exécuter la commande « require » et répondre par « yes » à la fin de l'installation, pour que le composant puisse créer les fichiers nécessaires au bon fonctionnement de VichUploader.

1
> composer require vich/uploader-bundle

Nous devons mettre en place la configuration minimale pour que le composant puisse fonctionner.

Méthode

Ajoutons dans le fichier ./config/packages/vich_uploader.yaml, la configuration du driver de la base de données avec l'ORM.

1
# config/packages/vich_uploader.yaml
2
vich_uploader:
3
    db_driver: orm

Avant de télécharger des fichiers, nous devons configurer les mappings pour le VichUploaderBundle.

Ces mappings indiquent au composant où les fichiers doivent être téléchargés et quels chemins doivent être utilisés pour les afficher dans l'application.

Dans le fichier config/services.yaml, on doit spécifier le chemin du répertoire des fichiers téléversés.

1
# config/services.yaml
2
parameters:
3
    app.path.produit_images: /uploads/images/produits
4

Dans le fichier config/packages/vich_uploader.yaml, on spécifie la configuration du mapping.

1
# config/packages/vich_uploader.yaml
2
vich_uploader:
3
    # ...
4
    mappings:
5
        produit_images:
6
            uri_prefix: '%app.path.produit_images%'
7
            upload_destination: '%kernel.project_dir%/public%app.path.produit_images%'

La valeur mapping produit_images est un nom librement choisi qui contient la configuration pour un mapping spécifique.

Cette valeur sera utilisée ultérieurement dans la configuration de l'entité.

Les images téléchargées sont stockées dans le répertoire défini dans upload_destination.

Complément

L'option uri_prefix définit l'url permettant d'accéder aux fichiers depuis le site.

Conseil

N'hésitez pas à créer autant de mapping que de cas d'utilisation (Ex : photo d'utilisateur).

Maintenant que le composant VichUploader est configuré, préparons notre entité produit pour conserver les images.

Méthode

Récupérons notre entité Produit :

La première modification que nous devons apporter consiste à ajouter l'annotation téléchargeable à la classe d'entité grâce à cette annotation : @Vich\Uploadable.

ExempleCode

1
**
2
 * @ORM\Entity(repositoryClass=ProduitRepository::class)
3
 * @Vich\Uploadable
4
 */
5
class Produit
6
{
7
    // ...
8
}

Méthode

Ensuite, nous avons besoin de 2 nouvelles propriétés “image” et “fichierImage" et nous rajoutons aussi une propriété date de dernière mise à jour qui permettra à vichupdater de gérer l'enregistrement des fichiers.

ExempleCode

1
namespace App\Entity;
2
// ...
3
use Symfony\Component\HttpFoundation\File\File;
4
use Vich\UploaderBundle\Mapping\Annotation as Vich;
5
6
/**
7
 * @ORM\Entity(repositoryClass=ProduitRepository::class)
8
 * @Vich\Uploadable
9
 */
10
class Produit
11
{
12
    // ...
13
    /**
14
     * @ORM\Column(type="string", length=255, nullable=true)
15
     * @var string
16
     */
17
    private $image;
18
19
    /**
20
     * @Vich\UploadableField(mapping="produit_images", fileNameProperty="image")
21
     * @var File
22
     */
23
    private $fichierImage;
24
25
    // Default car nous avons déjà des produits
26
    /**
27
     * @ORM\Column(type="datetime",  options={"default": "CURRENT_TIMESTAMP"})
28
     * @var \DateTime
29
     */
30
    private $mis_a_jour_le;
31
32
    /**
33
     * @return null|string
34
     */
35
    public function getImage(): ?string
36
    {
37
        return $this->image;
38
    }
39
40
    /**
41
     * @param null|string $image
42
     */
43
    public function setImage(?string $image = null): void
44
    {
45
        $this->image = $image;
46
    }
47
48
    /**
49
     * @return null|File
50
     */
51
    public function getFichierImage(): ?File
52
    {
53
        return $this->fichierImage;
54
    }
55
56
    /**
57
     * @param File|null $fichierImage
58
     */
59
    public function setFichierImage(?File $fichierImage = null): void
60
    {
61
        $this->fichierImage = $fichierImage;
62
   
63
        if ($fichierImage) {
64
65
            $this->mis_a_jour_le = new \DateTime('now');
66
        }
67
    }
68
    // ...
69
}

Attention

Il est nécessaire qu'au moins un champ change si nous utilisons Doctrine. Sinon, les écouteurs d'événements ne seront pas appelés et le fichier sera perdu. C'est pourquoi nous avons ajouté le champ « mis_a_jour ».

Définition

La propriété image stocke uniquement le nom de l'image importée et elle est conservée dans la base de données.

La propriété fichierImage stocke le contenu binaire du fichier image et elle n'est pas conservée dans la base de données (c'est pourquoi elle ne définit pas d'annotation @ORM). Elle doit définir une annotation @Vich\UploadableField qui va permettre de :

  • Configurer la gestion du téléversement du contenu binaire dans un fichier. Ce fichier sera stocké dans un répertoire spécifié dans le mapping configuré dans le fichier config/packages/vich_uploader.yaml.

  • Enregistrer le nom du fichier dans une propriété de l'entité.

Cette annotation prend en paramètre la clé de mapping à utiliser (dans ce cas : « produit_images ») et le nom de la propriété de l'entité qui stockera le nom de l'image en base de données (dans ce cas : « image »).

Nous devons mettre à jour le schéma de la base de données avec les nouvelles propriétés de produit.

Méthode

Exécutons la commande de doctrine.

1
> php bin/console doctrine:schema:update  --force

Utilisons enfin notre composant VichUploader, en ajoutant dans la construction du formulaire de création de Produit de Symfony la form de type Vich\UploaderBundle\Form\Type\VichFileType.

ExempleCode

1
<?php
2
namespace App\Form\Type;
3
// ...
4
use Symfony\Component\Form\AbstractType;
5
use Symfony\Component\Form\FormBuilderInterface;
6
use Vich\UploaderBundle\Form\Type\VichFileType;
7
8
class ProduitType extends AbstractType
9
{
10
    public function buildForm(FormBuilderInterface $builder, array $options): void
11
    {
12
        $builder
13
           // ..............
14
            ->add('fichierImage', VichFileType::class)
15
        ;
16
    }
17
}

Remarque

Maintenant que nous venons de mettre en place l'upload avec le composant VichUploader, nous devrions retrouver la même interface de création de produit de la première partie du cours.

Après avoir enregistré les images des produits, nous allons terminer par afficher l'image dans la liste des produits.

Méthode

Pour afficher l'url du produit depuis Twig, nous pouvons utiliser la fonction « vich_uploader_asset », qui prend en paramètre l'objet concerné et le nom de la propriété qui stocke les données binaires des fichiers.

ExempleCode

Dans notre exemple, nous aurons « produit » comme objet entité produit et « fichierImage » comme propriété qui stocke les données binaires.

1
{% for produit in produits %}{% if produit.getImage() %} <img src="{{ vich_uploader_asset(produit, 'fichierImage') }}"> {% endif %}

Complément