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 AppEntity; use AppRepositoryInventaireRepository; use DateTime; use DoctrineORMMapping as ORM; use SymfonyComponentHttpFoundationFileFile; use VichUploaderBundleMappingAnnotation as Vich; My entity /** * @ORMEntity(repositoryClass=InventaireRepository::class) * @VichUploadable */ class Inventaire { /** * @ORMId * @ORMGeneratedValue * @ORMColumn(type="integer") */ private $id; /** * @ORMManyToOne(targetEntity=Conducteur::class, inversedBy="inventaires") */ private $conducteur; /** * @ORMColumn(type="date") */ private $dateInventaire; /** * @ORMColumn(type="string", length=255) */ private $pieceJointe; /** * @VichUploadableField(mapping="pieceJointe", fileNameProperty="pieceJointe") */ private $pieceJointeFile; /** * @ORMColumn(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 AppControllerAdmin; use AppEntityInventaire; use EasyCorpBundleEasyAdminBundleConfigAction; use EasyCorpBundleEasyAdminBundleConfigActions; use EasyCorpBundleEasyAdminBundleConfigCrud; use EasyCorpBundleEasyAdminBundleControllerAbstractCrudController; use EasyCorpBundleEasyAdminBundleFieldAssociationField; use EasyCorpBundleEasyAdminBundleFieldDateField; use EasyCorpBundleEasyAdminBundleFieldImageField; use EasyCorpBundleEasyAdminBundleFieldTextField; use VichUploaderBundleFormTypeVichFileType; use VichUploaderBundleFormTypeVichImageType; 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.
Advertisement
Answer
You can solve this problem by creating a simple field class
<?PHP namespace AppField; use AppFormMetaDataType; use EasyCorpBundleEasyAdminBundleContractsFieldFieldInterface; use EasyCorpBundleEasyAdminBundleFieldFieldTrait; use VichUploaderBundleFormTypeVichImageType; 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 AppFieldVichImageField; ... 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 %}