【问题标题】:Handle filesUpload in a single table Symfony在单个表中处理文件上传 Symfony
【发布时间】:2017-12-28 23:36:15
【问题描述】:

感谢您的关注,

简短

我想在一个实体中管理我所有的上传(图像、PDF、视频等),所以我使用实体继承来获取各种“类型”和 OneToOne 关系,以将父实体与正确的上传链接起来。我没有找到任何捆绑包来执行此操作并遇到问题:

  • 约束使用
  • 设置上传文件而不是上传实体
  • 获取上传的文件而不是上传实体(版)

我宁愿在每个表中只使用一个表 Uploads 来处理每个上传,而不是在每个表中进行 1 个文件管理(这很冗长)。然后我只需要做 OneToOne 关系来获取我的文件,再加上使用继承,我可以根据 ImagePDF 应用各种处理。

我至少有 4 个实体需要图像,所以我认为 1to1 关系是一个不错的选择。

但我在做这样的事情时遇到了问题:

  • Constraints 没有考虑到
  • $file 的版本应设置为$file->file(它不会从Uploads/Image 发送实体,而是用于创建此实体的文件
  • 上传的文件未在实体版本上加载,每次编辑实体时都应重新上传

有人这样做吗?我不知道如何正确实现这一点。

查看我尝试的断言问题:

  • Image 上定义断言(这不能按预期工作,因为表单的目标是$fileWithImage
    • 使用注解@Assert\Image()
    • 使用loadValidatorMetadata
    • 使用注解@Assert\Callback()
  • 在表单字段'constraints' => array(new Assert\Image()) 上定义断言,这可行,但需要在我使用它的任何地方定义...

看着 setter 被误用,我找到了一种解决方法,但这很丑:

public function setFile($file = null)
{
    if ($file instanceof \Symfony\Component\HttpFoundation\File\UploadedFile) {
        $tmpfile = new Image();
        $tmpfile->setFile($file);
        $file = $tmpfile;
    }
    $this->file = $file;

    return $this;
}

(PS:我阅读了有关避免复制/粘贴代码的特征,我已经检查了 SonataMediaBundle 但这似乎不适用于我的情况)

代码

所以我将我的课程设计如下:

Entity\Uploads.php 处理文件从上传到删除的整个生命周期(以及访问、移动、编辑,可能还有缩略图等...)

<?php

namespace Acme\CoreBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;

use Acme\CoreBundle\Utils\UUID;

/**
 * Uploads
 *
 * @ORM\Table(name="uploads")
 * @ORM\Entity(repositoryClass="Acme\CoreBundle\Repository\UploadsRepository")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="class", type="string")
 * @ORM\DiscriminatorMap({"image" = "Image"})
 * @ORM\HasLifecycleCallbacks
 */
abstract class Uploads
{
    protected $file;

    private $tempFileName;

    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="date", type="datetime")
     */
    private $date;

    /**
     * @var string
     *
     * @ORM\Column(name="fileName", type="string", length=36, unique=true)
     */
    private $fileName; // UUID

    /**
     * @var string
     *
     * @ORM\Column(name="extension", type="string", length=4)
     */
    private $extension;


    /**
     * Get id.
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set date.
     *
     * @param \DateTime $date
     *
     * @return uploads
     */
    public function setDate($date)
    {
        $this->date = $date;

        return $this;
    }

    /**
     * Get date.
     *
     * @return \DateTime
     */
    public function getDate()
    {
        return $this->date;
    }

    /**
     * Set fileName.
     *
     * @param string $fileName
     *
     * @return uploads
     */
    public function setFileName($fileName)
    {
        $this->fileName = $fileName;

        return $this;
    }

    /**
     * Get fileName.
     *
     * @return string
     */
    public function getFileName()
    {
        return $this->fileName;
    }

    /**
     * Set extension
     *
     * @param string $extension
     *
     * @return string
     */
    public function setExtension($extension)
    {
        $this->extension = $extension;

        return $this;
    }

    /**
     * Get extension
     *
     * @return string
     */
    public function getExtension()
    {
        return $this->extension;
    }

    public function getFileNameExt()
    {
        return $this->getFileName().'.'.$this->getExtension();
    }

    public function setFile(UploadedFile $file)
    {
        $this->file = $file;
        if (null !== $this->getId()) {
            $this->tempFileName = $this->getFileNameExt();
            $this->fileName = null;
            $this->extension = null;
        }
    }

    public function getFile()
    {
        return $this->file;
    }

    /**
    * @ORM\PrePersist()
    * @ORM\PreUpdate()
    */
    public function preUpload()
    {
        if (null === $this->file) {
            return;
        }
        $this->extension = $this->file->guessExtension();
        $this->fileName = UUID::v4();
        $this->preUpdateFile();
    }

    protected function preUpdateFile(){} // To define if specific treatment

    /**
     * @ORM\PrePersist()
     */
    public function prePersistDate()
    {
        $this->date = new \DateTime();
        return $this;
    }

    /**
    * @ORM\PostPersist()
    * @ORM\PostUpdate()
    */
    public function upload()
    {
        if (null === $this->file) {
            return;
        }

        if (null !== $this->tempFileName) {
            $oldFile = $this->getUploadRootDir().$this->tempFileName;
            if (file_exists($oldFile)) {
                unlink($oldFile);
            }
        }

        $this->file = $this->file->move(
            $this->getUploadRootDir(),
            $this->getFileNameExt()
        );

        $this->postUpdateFile();
    }

    protected function postUpdateFile(){} // To define if specific treatment

    /**
    * @ORM\PreRemove()
    */
    public function preRemoveUpload()
    {
        // On sauvegarde temporairement le nom du fichier
        $this->tempFileName = $this->getFileNameExt();
        $this->preRemoveFile();
    }

    protected function preRemoveFile(){} // To define if specific treatment

    /**
    * @ORM\PostRemove()
    */
    public function removeUpload()
    {
        $oldFile = $this->getUploadRootDir().$this->tempFileName;
        if (file_exists($oldFile)) {
            unlink($oldFile);
        }
        $this->postRemoveFile();
    }

    protected function postRemoveFile(){} // To define if specific treatment

    public function getFileUri()
    {
        return $this->getUploadDir().$this->getFileNameExt();
    }

    public function getUploadDir()
    {
        return 'uploads/';
    }

    protected function getUploadRootDir()
    {
        return __DIR__.'/../../../../web/'.$this->getUploadDir();
    }

    public function __toString() {
        return $this->getFileNameExt();
    }
}

Entity\Image.php特定类型的上传,有自己的约束和文件管理

<?php

namespace Acme\CoreBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Image
 *
 * @ORM\Entity(repositoryClass="Acme\CoreBundle\Repository\ImageRepository")
 */
class Image extends Uploads
{
}

Entity\WithImage.php 需要Image的实体

<?php

namespace Acme\CoreBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * WithImage
 *
 * @ORM\Table(name="with_image")
 * @ORM\Entity(repositoryClass="Acme\CoreBundle\Repository\WithImageRepository")
 */
class WithImage
{

    /**
     * @ORM\OneToOne(targetEntity="Acme\CoreBundle\Entity\Image", cascade={"persist", "remove"})
     */
    protected $file;
}

【问题讨论】:

    标签: forms symfony validation doctrine


    【解决方案1】:

    我想到了一些想法来帮助你实现你想要的。

    首先,您必须以表单的形式上传文件,并且约束应该在实体的属性中(除非您想在每个表单中都编写约束,这不是很容易维护)。因此,对于每个将有文件的实体,定义一个文件属性(不是 ORM 注释的)并在那里写下你的约束。同时添加相应的 getter 和 setter。

    /**                                                                         
     * @var UploadedFile                                                        
     * @Assert\NotBlank(groups={"New"})                                         
     * @Assert\File(mimeTypes={"text/html", "text/markdown", "text/plain"})     
     */                                                                         
    private $file;
    

    其次,您可能会问 ¿ 但是我如何将它们保存到不同的实体?这是我建议您使用 Doctrine Event Subscriber 的时候。基本上,是一个使用doctrine.event_subscriber 标签定义的服务,该类实现Doctrine\Common\EventSubscriber 接口。您可以订阅preUpdatepostLoad 等事件,以及您感兴趣的:prePersist

    我对此的看法是您订阅了prePersist 事件。该事件会将实体传递给您(使用我们创建的文件非 orm 属性,它具有保存您的文件信息的 UploadedFile 实例)。

    然后,使用该文件的信息,创建一个新的 Upload 实体,传递您想要的所有信息,然后将其设置在保存您与所需实体的文件关系的真实文件 orm 映射属性中。如果我没记错的话,你必须启用持久级联。

    这样做的好处: 1. 您可以在实体中定义约束。 2. 你可以拥有你想要的Uploads Entity。

    唯一的主要问题是您必须通过侦听器完成所有上传实体的检索、存储和更新。但这是我能想到的唯一能帮助你的事情。

    【讨论】:

    • 从未听说过学说事件订阅者,将尝试这个谢谢:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-07
    • 1970-01-01
    • 2016-04-18
    • 2015-07-02
    • 1970-01-01
    • 2020-11-14
    相关资源
    最近更新 更多