在单个表Symfony中处理filesUpload

时间:2017-12-28 23:36:16

标签: forms symfony validation doctrine

感谢您的关注,

SHORT

我想在一个实体中管理我的所有上传内容(图片,PDF,视频等...),因此我使用实体继承来获取各种"类型"和OneToOne关系将父实体与正确的上传链接起来。我没有找到任何捆绑来做这件事并面临问题:

  • 限制使用
  • 设置上传文件而非上传实体
  • 获取上传文件而非上传实体(版本)

LONG

我没有在每个表中使用1个文件管理(安静详细),而是只使用一个表Uploads来处理每个上传。然后我只需要执行OneToOne关系来获取我的文件,再加上使用继承我可以根据ImagePDF应用各种处理。

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

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

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

有人这样做过吗?我无法找到如何正确实现这一目标。

看看我试图解决的断言问题:

  • Image上定义断言(这不会像$file WithImage的{​​{1}}表格一样正常工作
    • 使用注释@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,但这似乎并不适用于我的情况)

CODE

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

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;
}

1 个答案:

答案 0 :(得分:0)

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

首先,你必须在一个表单中上传文件,并且约束应该在一个实体的属性中(除非你想要在每个表单中编写约束的痛苦,这是不可能的)。因此,对于将要拥有文件的每个实体,定义文件属性(不是ORM anotated)并在那里编写约束。还要添加相应的getter和setter。

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

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

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

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

这样做的好处: 1.您可以在实体中定义约束。 2.您可以拥有所需的上传实体。

唯一的主要问题是您必须通过侦听器检索,存储和更新Uploads实体。但是我唯一能想到的就是帮助你。