php - Symfony 5. EasyAdmin 3. VichUploader。同时上传多个文件
问题描述
我有一个完美的多文件上传。使用一个“浏览”按钮一次上传一个文件。它基本上是一个可以包含许多图像的 Places 实体。
我正在尝试修改它以仅通过一个“浏览”窗口一次上传所有文件。使用 Ctrl / shift 选择多个文件。
所以我得到的第一个内部是 VichUploader ( VichFileType::class
) 不支持多次上传,所以到目前为止我发现只有一个选项是在我的和添加选项中更改VichFileType::class
,所以现在我在我的管理面板字段中可以选择一次有很多文件。这正是我所需要的。但是在我选择了所有需要的文件并单击创建一个新位置后,我得到了错误:. 似乎 VichUploader 只等待一个文件而不是数组,所以我修改了我的图像实体。FileType::class
AttachmentType.php
['multiple' => true]
Create
Return value of Vich\UploaderBundle\Mapping\PropertyMapping::getFile() must be an instance of Symfony\Component\HttpFoundation\File\File or null, array returned
前:
/**
* @param mixed $imageFile
*/
public function setImageFile($imageFile): void {
$this->imageFile = $imageFile;
if ($imageFile) {
$this->updatedAt = new \DateTime();
}
}
后:
/**
* @param mixed $imageFile
*/
public function setImageFile($imageFile): void {
foreach ($imageFile as $file) {
$this->imageFile = $file;
if ($imageFile) {
$this->updatedAt = new \DateTime();
}
}
}
之后,错误消失了,但问题是如果我添加多张图片,则只添加数组中的最后一张。
完整代码:
Places.php
/**
* @ORM\OneToMany(targetEntity=Images::class, mappedBy="place", cascade={"persist", "remove"})
*/
private $images;
public function __construct()
{
$this->images = new ArrayCollection();
}
/**
* @return Collection|Images[]
*/
public function getImages(): Collection
{
return $this->images;
}
public function addImage(Images $image): self
{
if (!$this->images->contains($image)) {
$this->images[] = $image;
$image->setPlace($this);
}
return $this;
}
public function removeImage(Images $image): self
{
if ($this->images->removeElement($image)) {
// set the owning side to null (unless already changed)
if ($image->getPlace() === $this) {
$image->setPlace(null);
}
}
return $this;
}
Images.php
/**
* @ORM\Entity(repositoryClass=ImagesRepository::class)
* @Vich\Uploadable()
*/
class Images
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $title;
/**
* @Vich\UploadableField(mapping="attachments", fileNameProperty="title")
*/
private $imageFile;
/**
* @ORM\Column(type="datetime")
*/
private $updatedAt;
/**
* @ORM\ManyToOne(targetEntity=Places::class, inversedBy="images")
*/
private $place;
/**
* @ORM\ManyToOne(targetEntity=Regions::class, inversedBy="image")
*/
private $region;
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(?string $title): self
{
$this->title = $title;
return $this;
}
public function setUpdatedAt(\DateTimeInterface $updatedAt): self
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* @return mixed
*/
public function getUpdatedAt() {
return $this->updatedAt;
}
/**
* @param mixed $imageFile
*/
public function setImageFile($imageFile): void {
foreach ($imageFile as $file) {
$this->imageFile = $file;
if ($imageFile) {
$this->updatedAt = new \DateTime();
}
}
}
/**
* @return mixed
*/
public function getImageFile() {
return $this->imageFile;
}
public function getPlace(): ?Places
{
return $this->place;
}
public function setPlace(?Places $place): self
{
$this->place = $place;
return $this;
}
public function getRegion(): ?Regions
{
return $this->region;
}
public function setRegion(?Regions $region): self
{
$this->region = $region;
return $this;
}
}
AttachmentType.php
class AttachmentType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('imageFile', FileType::class, [
'multiple' => true
])
->add('updatedAt')
->add('place')
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Images::class,
]);
}
}
解决方案
通过创建我自己的 Field 类,我可以使用 EasyAdmin3 为画廊上传多张图片。
这是我如何实现这一目标的一个例子......
<?php
namespace App\Controller\Admin\Fields;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait;
use Symfony\Component\Form\Extension\Core\Type\FileType;
class MultipleImageField implements FieldInterface
{
use FieldTrait;
public static function new(string $propertyName, ?string $label = null): self
{
return (new self())
->setProperty($propertyName)
->setFormType(FileType::class)
->setFormTypeOptions([
'multiple' => true,
'data_class' => null,
]);
}
}
在我的 Gallery 实体中,我有 2 个字段来处理 imageFile 和 image(它只存储文件名)和一个upload()
处理上传本身的函数。
const UPLOAD_IMAGE_DIRECTORY = 'uploads/images';
/**
* @ORM\Column(type="string", length=255)
* @Assert\Regex(pattern="/[\/.](gif|jpg|jpeg|tiff|png)$/i", message="Please upload a valid image")
*/
private string $image;
/**
* Unmapped property to handle file uploads
*/
private $imageFile;
public function getImage(): ?string
{
return $this->image;
}
public function setImage(string $image): self
{
$this->image = $image;
return $this;
}
/**
* @return mixed
*/
public function getImageFile()
{
return $this->imageFile;
}
/**
* @param mixed $imageFile
*/
public function setImageFile($imageFile): void
{
$this->imageFile = $imageFile;
}
public function upload($file)
{
if(null === $file){
return;
}
$file->move(
self::UPLOAD_IMAGE_DIRECTORY,
$file->getClientOriginalName()
);
$this->setImage($file->getClientOriginalName());
$this->setImageFile(null);
}
您可能可以在此处断言文件类型做得更好..
然后我将这两个字段添加到我的 EasyAdmin CRUDController 中,一个用于在索引/详细信息上显示实际图像,另一个用于表单以及updateEntity
功能persistEntity
。
<?php
namespace App\Controller\Admin;
use App\Controller\Admin\Fields\MultipleImageField;
use App\Entity\Gallery;
use Doctrine\ORM\EntityManagerInterface;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Config\Filters;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\ImageField;
class GalleryCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Gallery::class;
}
public function configureFilters(Filters $filters): Filters
{
return $filters
->add('category')
;
}
public function configureActions(Actions $actions): Actions
{
return $actions
->add(Crud::PAGE_INDEX, Action::DETAIL)
->add(Crud::PAGE_EDIT, Action::SAVE_AND_ADD_ANOTHER)
;
}
public function configureFields(string $pageName): iterable
{
return [
AssociationField::new('category'),
ImageField::new('image')
->setUploadDir('public/uploads/images')
->setBasePath('uploads/images')
->setRequired(false)
->hideOnForm(),
MultipleImageField::new('imageFile')
->setRequired(false)
->onlyOnForms(),
];
}
/**
* @param EntityManagerInterface $entityManager
* @param Gallery $entityInstance
*/
public function persistEntity(EntityManagerInterface $entityManager, $entityInstance): void
{
foreach($entityInstance->getImageFile() as $file)
{
$gallery = (new Gallery())
->setCategory($entityInstance->getCategory())
->setImage($file->getClientOriginalName())
;
$entityInstance->upload($file);
$entityManager->persist($gallery);
}
$entityManager->flush();
}
/**
* @param EntityManagerInterface $entityManager
* @param Gallery $entityInstance
*/
public function updateEntity(EntityManagerInterface $entityManager, $entityInstance): void
{
foreach($entityInstance->getImageFile() as $file)
{
$gallery = (new Gallery())
->setCategory($entityInstance->getCategory())
->setImage($file->getClientOriginalName())
;
$entityInstance->upload($file);
$entityManager->persist($gallery);
}
$entityManager->flush();
}
}
我希望这可以帮助任何尝试使用 EasyAdmin3 做类似事情的人
推荐阅读
- r - 如果在 R data.table 中满足条件,则获取唯一条目
- android - 如何在没有 root [su] 访问权限的情况下读取保存的 wifi 密码
- android - 如何在android上更改语言环境
- c# - 将灰度软拷贝呈现状态与 fo-dicom 结合使用
- m2doc - M2DOC如何定义一个变量并使用它
- python - 根据 Python 中的参考交换表中的值
- firebase - 没有帐户访问权限
- python - numba.errors.TypingError:在 nopython 模式管道中失败(步骤:nopython 前端)无法确定变量“argmax”的类型
- php - SQL 错误:- 语句已终止
- c# - 在函数中将字符串转换为枚举