【问题标题】:symfony 4.3 , api-platform with vich bundle - how to multiple file uploadsymfony 4.3,带有 vich 包的 api 平台 - 如何上传多个文件
【发布时间】:2019-11-27 12:48:03
【问题描述】:

我创建了一个具有一对多关系图像实体的 demo1 实体,并使用 vich 捆绑包进行上传

Demo1 实体

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

use App\Controller\UploadImageAction;

/**
 * @ORM\Entity(repositoryClass="App\Repository\Demo1Repository")
 * @ApiResource(
 *     collectionOperations={
 *             "get",
 *              "post" ={
 *
 *                    "controller"=UploadImageAction::class,
 *                    "defaults"={"_api_receive"=false},
 *                    "denormalization_context"={"groups"={"image"}}
 *              }
 *     }
 * )
 */
class Demo1
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Image", mappedBy="myfiles")
     * @ORM\JoinColumn(nullable=false);
     */
    private $files;

    public function __construct()
    {
        $this->files = new ArrayCollection();
    }

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

    /**
     * @return Collection|Image[]
     */
    public function getFiles(): Collection
    {
        return $this->files;
    }

    public function addFile(Image $file): self
    {
        if (!$this->files->contains($file)) {
            $this->files[] = $file;
            $file->setMyfiles($this);
        }

        return $this;
    }

    public function removeFile(Image $file): self
    {
        if ($this->files->contains($file)) {
            $this->files->removeElement($file);
            // set the owning side to null (unless already changed)
            if ($file->getMyfiles() === $this) {
                $file->setMyfiles(null);
            }
        }

        return $this;
    }
}

图像实体

<?php

namespace App\Entity;

use Symfony\Component\Validator\Constraints as Assert;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Symfony\Component\Serializer\Annotation\Groups;
use App\Controller\UploadImageAction;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Api\Data\TagInterface;
use App\Api\File\ImageInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(name="data_files_images")
 * @ORM\Entity(repositoryClass="App\Repository\ImageRepository")
 * @Vich\Uploadable()

 */
class Image extends AbstractEntity implements ImageInterface
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     * @Groups({"get","patch","post"})
     */
    private $id;

    /**
     * @ORM\Column(name="mimetype", type="string", length=20, nullable=true)
     */
    private $mimeType;

    /**
     * @Vich\UploadableField(mapping="images", fileNameProperty="url")
     * @Assert\NotNull()
     * @Groups({"image"})
     */
    private $files;


    /**
     * @ORM\Column(name="url", type="string", length=255, nullable=true)
     * @Groups({"get","patch","post"})
     */
    private $url;

    /**
     * @ORM\Column(name="width", type="integer", nullable=true)
     */
    private $width;

    /**
     * @ORM\Column(name="length", type="integer", nullable=true)
     */
    private $length;

    /**
     * @ORM\Column(name="filesize", type="integer", nullable=true)
     */
    private $filesize;

    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Tag", inversedBy="images", cascade={"persist"})
     * @ORM\JoinTable(
     *  name="rel_tags_images",
     *  joinColumns={ @ORM\JoinColumn(name="image_id", referencedColumnName="id", onDelete="CASCADE") },
     *  inverseJoinColumns={ @ORM\JoinColumn(name="tag_id", referencedColumnName="id", onDelete="CASCADE") }
     * )
     */
    private $tags;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\SingleProduct", inversedBy="images")
     * @ORM\JoinColumn(name="product_id", nullable=true, onDelete="CASCADE")
     */
    private $singleProduct;

    /**

     * @ORM\ManyToOne(targetEntity="App\Entity\Demo1", inversedBy="files")
     * ORM\@ORM\JoinColumn(nullable=false)
     */
    public $myfiles;

    /**
     * Image constructor.
     */
    public function __construct()
    {
        $this->tags = new ArrayCollection();
    }

    /**
     * @return int|null
     */
    public function getId(): ?int
    {
        return $this->id;
    }

    /**
     * @return string|null
     */
    public function getMimeType(): ?string
    {
        return $this->mimeType;
    }

    /**
     * @param string $mimeType
     */
    public function setMimeType(string $mimeType): void
    {
        $this->mimeType = $mimeType;
    }

    /**
     * @return string|null
     */
    public function getUrl(): ?string
    {
        return $this->url;
    }

    /**
     * @param string $url
     */
    public function setUrl(string $url): void
    {
        $this->url = $url;
    }

    /**
     * @return int|null
     */
    public function getWidth(): ?int
    {
        return $this->width;
    }

    /**
     * @param int $width
     */
    public function setWidth(int $width): void
    {
        $this->width = $width;
    }

    /**
     * @return int|null
     */
    public function getLength(): ?int
    {
        return $this->length;
    }

    /**
     * @param int $length
     */
    public function setLength(int $length): void
    {
        $this->length = $length;
    }

    /**
     * @return int|null
     */
    public function getFilesize(): ?int
    {
        return $this->filesize;
    }

    /**
     * @param int $filesize
     */
    public function setFilesize(int $filesize): void
    {
        $this->filesize = $filesize;
    }

    /**
     * @return Collection|Tag[]
     */
    public function getTags(): Collection
    {
        return $this->tags;
    }

    /**
     * @param \App\Entity\Tag $tag
     */
    public function addTag(Tag $tag): void
    {
        if (!$this->tags->contains($tag)) {
            $this->tags[] = $tag;
        }
    }

    /**
     * @param \App\Entity\Tag $tag
     */
    public function removeTag(Tag $tag): void
    {
        if ($this->tags->contains($tag)) {
            $this->tags->removeElement($tag);
        }
    }

    /**
     * @return string
     */
    public function toString(): string
    {
        return (string)$this->getUrl();
    }

    /**
     * @return array
     */
    public function toArray(): array
    {
        return [
            'mimetype' => $this->getMimeType(),
            'url' => $this->getUrl(),
            'width' => $this->getWidth(),
            'length' => $this->getLength(),
            'filesize' => $this->getFilesize(),
            'tags' => array_map(
                function (TagInterface $tag) {
                    return $tag->toString();
                },
                $this->getTags()->toArray()
            ),
        ];
    }

    /**
     * @return \App\Entity\SingleProduct|null
     */
    public function getSingleProduct(): ?SingleProduct
    {
        return $this->singleProduct;
    }

    /**
     * @param \App\Entity\SingleProduct|null $singleProduct
     */
    public function setSingleProduct(?SingleProduct $singleProduct): void
    {
        $this->singleProduct = $singleProduct;
    }

    /**
     * @return mixed
     */
    public function getFiles()
    {
        return $this->files;
    }

    /**
     * @param mixed $files
     */
    public function setFiles($files): void
    {
        $this->files = $files;
    }

    public function getMyfiles(): ?Demo1
    {
        return $this->myfiles;
    }

    public function setMyfiles(?Demo1 $myfiles): self
    {
        $this->myfiles = $myfiles;

        return $this;
    }
}

ImageType(形式)

<?php
namespace App\Form;
use App\Entity\Demo1;
use App\Entity\Image;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;


class ImageType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('files', FileType::class, [
            'multiple'=>true,
            'attr'     => [
                'accept' => 'image/*',
            ]

        ]);
    }
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Demo1::class,
            'csrf_protection' => false
        ]);
    }
    public function getBlockPrefix()
    {
        return '';
    }
}

上传动作

<?php


namespace App\Controller;


use ApiPlatform\Core\Validator\Exception\ValidationException;
use ApiPlatform\Core\Validator\ValidatorInterface;
use App\Entity\Demo1;
use App\Entity\Image;
use App\Form\ImageType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Request;

class UploadImageAction
{

    /**
     * @var FormFactoryInterface
     */
    private $formFactory;
    /**
     * @var EntityManagerInterface
     */
    private $entityManager;
    /**
     * @var ValidatorInterface
     */
    private $validator;

    public function __construct(
        FormFactoryInterface $formFactory,
        EntityManagerInterface $entityManager,
        ValidatorInterface $validator
    )
    {

        $this->formFactory = $formFactory;
        $this->entityManager = $entityManager;
        $this->validator = $validator;
    }

    public function __invoke(Request $request)
    {
        // Create a new Image instance
        $image = new Demo1();
        // Validate the form
        $form = $this->formFactory->create(ImageType::class, $image);
        $form->handleRequest($request);
       // dump($request);
        if ($form->isSubmitted() && $form->isValid()){
            // Persist the new Image entity

            $this->entityManager->persist($image);
            $this->entityManager->flush();

           // $image->setFiles(null);

            return $image;


        }


        // Uploading done for us in background by VichUploader

        // Throw an validation exception, that means something went wrong during
        // form validation
        throw new ValidationException(
            $this->validator->validate($image)
        );


    }
}

如果使用平台 API 上传多个文件的任何替代解决方案建议也 当前代码没有上传文件,也没有更新图像表

【问题讨论】:

    标签: php symfony doctrine-orm doctrine api-platform.com


    【解决方案1】:

    请在下面找到将多个附件上传到消息的示例。

    /应用程序/实体/附件

    namespace App\Entity;
    
    use Doctrine\ORM\Mapping as ORM;
    use Symfony\Component\Validator\Constraints as Assert;
    use ApiPlatform\Core\Annotation\ApiResource;
    use Symfony\Component\Serializer\Annotation\Groups;
    use Vich\UploaderBundle\Mapping\Annotation as Vich;
    use Symfony\Component\HttpFoundation\File\File;
    use Symfony\Component\HttpFoundation\File\UploadedFile;
    use App\Controller\AttachmentMessageAction;
    
    /**
     * @ApiResource(
     *   attributes={"pagination_enabled"=false},
     *      itemOperations={
     *          "get"={
     *              "access_control"="is_granted('ROLE_USER')",
     *              "normalization_context"={
     *                  "groups"={"get"}
     *              }
     *          }
     *      },
     *      collectionOperations={
     *          "get",
     *          "post"={
     *             "method"="POST",
     *             "path"="/attachments",
     *             "controller"=AttachmentMessageAction::class,
     *             "defaults"={"_api_receive"=false}
     *         }
     *      }
     * )
     * @ORM\Entity(repositoryClass="App\Repository\AttachmentRepository")
     * @Vich\Uploadable()
     */
    class Attachment
    {
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     * @Groups({"get"})
     */
    private $id;
    
    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Message", inversedBy="attachments")
     * @ORM\JoinColumn(nullable=true)
     * @Groups({"post", "get"})
     */
    private $message;
    
    /**
     * @Assert\File(
     *     maxSize = "2048k",
     *     maxSizeMessage = "File exceeds allowed size",
     *     mimeTypes = {"image/png","image/jpeg", "application/pdf", "application/x-pdf"},
     *     mimeTypesMessage = "Please upload a valid file"
     * )
     * @Assert\NotNull()
     * @Vich\UploadableField(mapping="message_attachment", fileNameProperty="filename")
     * @Groups({"post"})
     * @var File
     */
    private $file;
    
    /**
     * @ORM\Column(type="string", length=180)
     * @Groups({"post","get-owner"})
     * @var string
     */
    private $filename;
    
    /**
     * @ORM\Column(type="datetime")
     * @var \DateTime
     */
    private $updatedAt;
    
    /**
     * Constructor
     *
     * @param Message $message
     */
    public function __construct(Message $message = null)
    {
        $this->message = $message;
    }
    
    public function getId()
    {
        return $this->id;
    }
    
    
    public function getMessage(): ?Message
    {
        return $this->message;
    }
    
    public function setMessage(?Message $message): self
    {
        $this->message = $message;
    
        return $this;
    }
    
    /**
     * @param File|\Symfony\Component\HttpFoundation\File\UploadedFile $attachment
     */
    public function setFile(?File $file = null): void
    {
        $this->file = $file;
    
        if (null !== $file) {
            // It is required that at least one field changes if you are using doctrine
            // otherwise the event listeners won't be called and the file is lost
            $this->updatedAt = new \DateTimeImmutable();
        }
    }
    
    public function getFile(): ?File
    {
        return $this->file;
    }
    
    public function getFilename(): ?string
    {
        return $this->filename;
    }
    
    public function setFilename(?string $filename): void
    {
        $this->filename = $filename;
    }
    
    public function getUpdatedAt(): ?\DateTimeInterface
    {
        return $this->updatedAt;
    }
    
    public function setUpdatedAt(\DateTimeInterface $updatedAt): self
    {
        $this->updatedAt = $updatedAt;
    
        return $this;
    }
    
    public function __toString()
    {
        return $this->id . ':' . $this->filename;
    }
    }
    

    还有 App/Controller/AttachmentMessageAction

    namespace App\Controller;
    
    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
    use ApiPlatform\Core\Validator\ValidatorInterface;
    use ApiPlatform\Core\Validator\Exception\ValidationException;
    use App\Entity\Attachment;
    use App\Entity\Message;
    use Doctrine\ORM\EntityManagerInterface;
    use Symfony\Component\Form\Extension\Core\Type\FileType;
    use Symfony\Component\HttpFoundation\Request;
    
    class AttachmentMessageAction extends AbstractController
    {
    /**
     * @var ValidatorInterface
     */
    private $validator;
    /**
     * @var EntityManagerInterface
     */
    private $entityManager;
    
    public function __construct(
        ValidatorInterface $validator,
        EntityManagerInterface $entityManager
    )
    {
        $this->validator = $validator;
        $this->entityManager = $entityManager;
    }
    
    public function __invoke(Request $request)
    { 
        $files = $request->files->get('file');
        $attachments = [];
        foreach ($files as $file) {
            $attachment = new Attachment();
            $attachment->setFile($file);
            $this->validator->validate($attachment);
            $this->entityManager->persist($attachment);
    
            $attachment->setFile(null);
            $attachments[] = $attachment;
        }
        $this->entityManager->flush();
    
        return $attachments;
    }
    }
    

    编辑:应要求的 App/Entity/Message 的相关摘录:

     /**
     * @ORM\OneToMany(targetEntity="App\Entity\Attachment", mappedBy="message",cascade={"persist"}, orphanRemoval=true)
     * @Groups({"post", "get"})
     */
    private $attachments;
    
    ....
    
    public function __construct()
    {
        $this->attachments = new ArrayCollection();
        $this->children = new ArrayCollection();
        $this->isDeletedBySender = false;
        $this->isDeletedByReceiver = false;
        $this->sentAt = new \DateTimeImmutable();
    }
    
    ....
    
    /**
     * @return Collection|Attachment[]
     */
    public function getAttachments(): Collection
    {
        return $this->attachments;
    }
    
    public function addAttachment(Attachment $attachment): self
    {
        if (!$this->attachments->contains($attachment)) {
            $this->attachments[] = $attachment;
            $attachment->setMessage($this);
        }
    
        return $this;
    }
    
    public function removeAttachment(Attachment $attachment): self
    {
        if ($this->attachments->contains($attachment)) {
            $this->attachments->removeElement($attachment);
            // set the owning side to null (unless already changed)
            if ($attachment->getMessage() === $this) {
                $attachment->setMessage(null);
            }
        }
    
        return $this;
    }
    

    【讨论】:

    • 请同时提供消息实体
    • 我按要求编辑了我的答案。请检查一下。
    • 我试过你的例子,但它对我不起作用,我得到:“无法对类 \"App\\Entity\\Contact\" 的属性 \"attachments\" 值进行非规范化:预期类型为 \"App\\Entity\\Attachment\", \"instance of App\\Entity\\Image\" 的参数在属性路径 \"attachments\"." 处给出,
    猜你喜欢
    • 1970-01-01
    • 2021-07-19
    • 1970-01-01
    • 2020-08-19
    • 1970-01-01
    • 2017-09-08
    • 2020-11-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多