Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Vich uploader with easyAdmin 3 on Symfony 5

I've been trying to use VichUploader to upload files on a Symfony project, already using EasyAdmin 3.

I've configured everything correctly, but I'm getting this error:

The "pieceJointeFile" image field must define the directory where the images are uploaded using the setUploadDir() method.

<?php

namespace App\Entity;

use App\Repository\InventaireRepository;
use DateTime;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;

My entity

/**
 * @ORM\Entity(repositoryClass=InventaireRepository::class)
 * @Vich\Uploadable
 */
class Inventaire
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity=Conducteur::class, inversedBy="inventaires")
     */
    private $conducteur;

    /**
     * @ORM\Column(type="date")
     */
    private $dateInventaire;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $pieceJointe;

    /**
     * @Vich\UploadableField(mapping="pieceJointe", fileNameProperty="pieceJointe")
     */
    private $pieceJointeFile;

    /**
     * @ORM\Column(type="datetime")
     */
    private $updatedAt;

    public function __construct()
    {
        $this->updatedAt = new DateTime();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getConducteur(): ?Conducteur
    {
        return $this->conducteur;
    }

    public function setConducteur(?Conducteur $conducteur): self
    {
        $this->conducteur = $conducteur;

        return $this;
    }

    public function getDateInventaire(): ?\DateTimeInterface
    {
        return $this->dateInventaire;
    }

    public function setDateInventaire(\DateTimeInterface $dateInventaire): self
    {
        $this->dateInventaire = $dateInventaire;

        return $this;
    }

    public function getPieceJointeFile() {
        return $this->pieceJointeFile;
    }

    public function setPieceJointeFile($pieceJointeFile): void
    {
        $this->pieceJointeFile = $pieceJointeFile;

        if($pieceJointeFile) {
            $this->updatedAt = new DateTime();
        }
    }

    public function getPieceJointe() {
        return $this->pieceJointe;
    }


    public function setPieceJointe($pieceJointe):self
    {
        $this->pieceJointe = $pieceJointe;
        return $this;
    }

    public function getUpdatedAt()
    {
        return $this->updatedAt;
    }
}

vich uploader configuration

vich_uploader:
    db_driver: orm

    mappings:
        pieceJointe:
            uri_prefix: /files/pieceJointe
            upload_destination: '%kernel.project_dir%/public/files/pieceJointe'

and finally My crud controller

<?php

namespace App\Controller\Admin;

use App\Entity\Inventaire;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateField;
use EasyCorp\Bundle\EasyAdminBundle\Field\ImageField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use Vich\UploaderBundle\Form\Type\VichFileType;
use Vich\UploaderBundle\Form\Type\VichImageType;

class InventaireCrudController extends AbstractCrudController
{
    public static function getEntityFqcn(): string
    {
        return Inventaire::class;
    }


    public function configureFields(string $pageName): iterable
    {
        return [
            DateField::new('dateInventaire'),
            AssociationField::new('conducteur'),
            TextField::new('pieceJointeFile')->setFormType(VichFileType::class, [
                'delete_label' => 'supprimer?'
            ])->onlyOnForms(),
            ImageField::new('pieceJointe')->setBasePath('/files/pieceJointe')->onlyOnDetail(),
            ImageField::new('pieceJointeFile')->setFormType(VichImageType::class)
        ];
    }



    public function configureActions(Actions $actions): Actions
    {
        return $actions
            ->add(Crud::PAGE_INDEX, Action::DETAIL);
    }
}

Finally, I want to clarify that when using TextField it works correctly.

like image 796
Chedi Athmni Avatar asked Dec 08 '20 16:12

Chedi Athmni


People also ask

How do I upload files to easyadmin?

Although EasyAdmin doesn't provide any built-in feature to upload files, it integrates seamlessly with VichUploaderBundle, the most popular file uploader Symfony bundle. Add the minimal configuration that makes the bundle work: First you'll learn how to upload and preview images in the backend.

Do I need to use the fqcn of the vichfiletype in easyadmin?

Even if your application uses Symfony 3 there is no need to use the FQCN of the VichFileType ( type: 'Vich \UploaderBundle \Form \Type \VichFileType' ) because EasyAdmin supports the short types for some popular third-party bundles. EasyAdmin renders the VichUploaderBundle form fields using a custom form theme that improves their default styling.

How do I use vichuploaderbundle's form styles with easyadmin?

If you prefer to use the original VichUploaderBundle styles, add its form theme in the form_theme configuration option (put it at the end to override EasyAdmin's default form theme): Apply the same technique in case you want to use your own form theme instead of the one provided by VichUploaderBundle.

How to upload multiple attachments to the same file in vichuploader?

VichUploader only supports to upload single files, so the only solution is to have a bridge entity with a OneToMany relation with the entity that contains the file, like you can see in this answer A viable alternative would be to create many different Image entities instead of trying to put multiple attachments to the same Image.


4 Answers

$imageFile = TextareaField::new('imageFile')->setFormType(VichImageType::class);

Put TextareaField to remplace the ImageField and it's works for me!!!!!

$imageFile = TextareaField

$image = ImageField

like image 108
sheerif Avatar answered Oct 19 '22 10:10

sheerif


You can solve this problem by creating a simple field class

<?PHP

namespace App\Field;

use App\Form\MetaDataType;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait;
use Vich\UploaderBundle\Form\Type\VichImageType;

final class VichImageField implements FieldInterface
{
    use FieldTrait;

    public static function new(string $propertyName, ?string $label = 'Image'): self
    {
        return (new self())
            ->setProperty($propertyName)
            ->setLabel($label)
            // this template is used in 'index' and 'detail' pages
            ->setTemplatePath('admin/field/vich_image.html.twig')
            // this is used in 'edit' and 'new' pages to edit the field contents
            // you can use your own form types too
            ->setFormType(VichImageType::class)
            ->addCssClass('field-vich-image')
        ;
    }
}

And then use it in your crud controllers

use App\Field\VichImageField;

...
yield VichImageField::new('image')->hideOnForm();
yield VichImageField::new('imageFile')->onlyOnForms();

Two times here because you need image field to render and imageFile on forms

{# admin/field/vich_image.html.twig #}
{% if field.value %}
  {% if field.value|match('/\.svg$/') %}
    <div class="thumbnail">
      {{ vich_uploader_asset(entity.instance, field.property ~ 'File', entity.fqcn) }}
    </div>
  {% else %}
    {% set html_id = 'ea-lightbox-' ~ field.uniqueId %}
    <a href="#" class="ea-lightbox-thumbnail" data-featherlight="#{{ html_id }}" data-featherlight-close-on-click="anywhere">
        <img src="{{ vich_uploader_asset(entity.instance, field.property ~ 'File', entity.fqcn)|imagine_filter('admin_thumbnail') }}" alt="{{ entity.name }}" class="img-fluid">
    </a>

    <div id="{{ html_id }}" class="ea-lightbox">
        <img src="{{ vich_uploader_asset(entity.instance, field.property ~ 'File', entity.fqcn)|imagine_filter('admin_full') }}" alt="{{ entity.name }}">
    </div>
  {% endif %}
{% else %}
    <span class="badge badge-secondary">
        Empty
    </span>
{% endif %}
like image 8
Flash Avatar answered Oct 19 '22 10:10

Flash


I found that documentation for EasyAdmin and VichUploaderBundle contains a mistake which follow to next exception: The "imageFile" image field must define the directory where the images are uploaded using the setUploadDir() method.

solution is simple:

//Entity
/**
  *
  * @Vich\UploadableField(mapping="video_image", fileNameProperty="imageName")
  *
  * @var File|null
*/
    private $imageFile;
//......

/**
  * @param File|null $imageFile
  * @return $this
*/
public function setImageFile(File $imageFile = null): self
{
    $this->imageFile = $imageFile;
    if (null !== $imageFile) {
        $this->updatedAt = new DateTime();
    }
  return $this;
}
//Admin Crud controller
// any type of field isnt correct except one
$coverImage = ImageField::new('imageFile')->setFormType(VichImageType::class); 

//this is a proper way of how to
$coverImage = Field::new('imageFile')->setFormType(VichImageType::class);

not required to create any custom field type or anything else except proper configuration in vich_uploader.yaml

like image 3
Moris Finkel Avatar answered Oct 19 '22 11:10

Moris Finkel


I have the same issue. I solved it by reverting to the version "easycorp/easyadmin-bundle": "3.1.6"

Good luck!

like image 2
Amibel Avatar answered Oct 19 '22 10:10

Amibel