如何在 Symfony 5 上通过 easyAdmin 3 使用 Vich 上传器
How to use Vich uploader with easyAdmin 3 on Symfony 5
我一直在尝试使用 VichUploader 在 Symfony 项目上上传文件,已经在使用 EasyAdmin 3。
我已正确配置所有内容,但出现此错误:
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 上传器配置
vich_uploader:
db_driver: orm
mappings:
pieceJointe:
uri_prefix: /files/pieceJointe
upload_destination: '%kernel.project_dir%/public/files/pieceJointe'
最后是我的 crud 控制器
<?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);
}
}
最后,我想澄清一下,当使用 TextField
时它可以正常工作。
我有同样的问题。
我通过恢复到版本 "easycorp/easyadmin-bundle": "3.1.6"
解决了这个问题
祝你好运!
您可以通过创建一个简单的字段来解决这个问题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')
;
}
}
然后在你的 crud 控制器中使用它
use App\Field\VichImageField;
...
yield VichImageField::new('image')->hideOnForm();
yield VichImageField::new('imageFile')->onlyOnForms();
此处两次,因为您需要 image
字段来呈现并且 imageFile
在表单上
{# 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 %}
$imageFile = TextareaField::new('imageFile')->setFormType(VichImageType::class);
用 TextareaField 替换 ImageField 对我有用!!!
$imageFile = TextareaField
$image = 图片字段
我发现 EasyAdmin 和 VichUploaderBundle 的文档包含错误
遵循下一个例外:
“imageFile”图像字段必须定义使用 setUploadDir() 方法上传图像的目录。
解决方法很简单:
//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);
除了 vich_uploader.yaml
中的正确配置外,不需要创建任何自定义字段类型或任何其他内容
我也有同样的问题。我通过在 Controller 中更改这个来解决它:
use App\Field\VichImageField;
...
yield VichImageField::new('image')->hideOnForm();
yield VichImageField::new('imageFile')->onlyOnForms();
在你的 CrudController 中
public function configureFields(string $pageName): iterable
{
$name = TextField::new('name');
$description = TextField::new('description');
$image = ImageField::new('image')
->setTemplatePath('admin/fields/vich_image.html.twig')
;
$imageFile = Field::new('imageFile')
->setFormType(VichImageType::class)
;
if (Crud::PAGE_INDEX === $pageName) {
return [$name, $description, $image];
} elseif (Crud::PAGE_DETAIL === $pageName) {
return [$image];
} elseif (Crud::PAGE_NEW === $pageName) {
return [$name, $description, $imageFile];
} elseif (Crud::PAGE_EDIT === $pageName) {
return [$name, $description, $imageFile];
}
}
这里稍微更新了 admin/fields/vich_image.html.twig
版本,小屏幕全屏显示:
{% if field.value %}
<a href="#" data-bs-toggle="modal" data-bs-target="#imageModal{{ field.uniqueId }}">
<img src="{{ vich_uploader_asset(entity.instance, 'imageFile')|imagine_filter('thumb') }}">
</a>
<div class="modal fade" id="imageModal{{ field.uniqueId }}" tabindex="-1" aria-labelledby="modal for {{ entity.instance.name }}" aria-hidden="true">
<div class="modal-dialog modal-lg modal-fullscreen-lg-down">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{ entity.instance.name }}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<img src="{{ vich_uploader_asset(entity.instance, 'imageFile')|imagine_filter('creative_dim_down') }}">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
{% endif %}
供参考,这里是用于缩略图和图像暗淡缩放的 liip 过滤器
liip_imagine:
# [...]
filter_sets:
cache: ~
thumb:
quality: 75
filters:
thumbnail: { size: [120, 90], mode: outbound }
background: { size: [124, 94], position: center, color: '#000000' }
creative_dim_down:
quality: 90
filters:
scale:
dim: [ 800, 1000 ]
我一直在尝试使用 VichUploader 在 Symfony 项目上上传文件,已经在使用 EasyAdmin 3。
我已正确配置所有内容,但出现此错误:
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 上传器配置
vich_uploader:
db_driver: orm
mappings:
pieceJointe:
uri_prefix: /files/pieceJointe
upload_destination: '%kernel.project_dir%/public/files/pieceJointe'
最后是我的 crud 控制器
<?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);
}
}
最后,我想澄清一下,当使用 TextField
时它可以正常工作。
我有同样的问题。 我通过恢复到版本 "easycorp/easyadmin-bundle": "3.1.6"
解决了这个问题祝你好运!
您可以通过创建一个简单的字段来解决这个问题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')
;
}
}
然后在你的 crud 控制器中使用它
use App\Field\VichImageField;
...
yield VichImageField::new('image')->hideOnForm();
yield VichImageField::new('imageFile')->onlyOnForms();
此处两次,因为您需要 image
字段来呈现并且 imageFile
在表单上
{# 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 %}
$imageFile = TextareaField::new('imageFile')->setFormType(VichImageType::class);
用 TextareaField 替换 ImageField 对我有用!!!
$imageFile = TextareaField
$image = 图片字段
我发现 EasyAdmin 和 VichUploaderBundle 的文档包含错误 遵循下一个例外: “imageFile”图像字段必须定义使用 setUploadDir() 方法上传图像的目录。
解决方法很简单:
//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);
除了 vich_uploader.yaml
我也有同样的问题。我通过在 Controller 中更改这个来解决它:
use App\Field\VichImageField;
...
yield VichImageField::new('image')->hideOnForm();
yield VichImageField::new('imageFile')->onlyOnForms();
在你的 CrudController 中
public function configureFields(string $pageName): iterable
{
$name = TextField::new('name');
$description = TextField::new('description');
$image = ImageField::new('image')
->setTemplatePath('admin/fields/vich_image.html.twig')
;
$imageFile = Field::new('imageFile')
->setFormType(VichImageType::class)
;
if (Crud::PAGE_INDEX === $pageName) {
return [$name, $description, $image];
} elseif (Crud::PAGE_DETAIL === $pageName) {
return [$image];
} elseif (Crud::PAGE_NEW === $pageName) {
return [$name, $description, $imageFile];
} elseif (Crud::PAGE_EDIT === $pageName) {
return [$name, $description, $imageFile];
}
}
这里稍微更新了 admin/fields/vich_image.html.twig
版本,小屏幕全屏显示:
{% if field.value %}
<a href="#" data-bs-toggle="modal" data-bs-target="#imageModal{{ field.uniqueId }}">
<img src="{{ vich_uploader_asset(entity.instance, 'imageFile')|imagine_filter('thumb') }}">
</a>
<div class="modal fade" id="imageModal{{ field.uniqueId }}" tabindex="-1" aria-labelledby="modal for {{ entity.instance.name }}" aria-hidden="true">
<div class="modal-dialog modal-lg modal-fullscreen-lg-down">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{ entity.instance.name }}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<img src="{{ vich_uploader_asset(entity.instance, 'imageFile')|imagine_filter('creative_dim_down') }}">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
{% endif %}
供参考,这里是用于缩略图和图像暗淡缩放的 liip 过滤器
liip_imagine:
# [...]
filter_sets:
cache: ~
thumb:
quality: 75
filters:
thumbnail: { size: [120, 90], mode: outbound }
background: { size: [124, 94], position: center, color: '#000000' }
creative_dim_down:
quality: 90
filters:
scale:
dim: [ 800, 1000 ]