【问题标题】:How to handle a file upload with a many to one relationship in Symfony2?如何在 Symfony2 中处理具有多对一关系的文件上传?
【发布时间】:2013-07-16 12:27:52
【问题描述】:

我正在创建一个用于练习目的的票务系统。

现在我在上传文件时遇到问题。

这个想法是一个工单可以有多个附件,所以我在工单和上传表之间创建了一个多对一的关系。

class Ticket {

// snip

/**
 * @ORM\OneToMany(targetEntity="Ticket", mappedBy="ticket")
 */
protected $uploads;

// snip
}

上传实体类包含上传功能,我取自this教程:

<?php

namespace Sytzeandreae\TicketsBundle\Entity;

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

/**
 * @ORM\Entity(repositoryClass="Sytzeandreae\TicketsBundle\Repository\UploadRepository")
 * @ORM\Table(name="upload")
 * @ORM\HasLifecycleCallbacks
 */
class Upload
{
    /**
     * @Assert\File(maxSize="6000000")
     */
    private $file;

    private $temp;

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\ManyToOne(targetEntity="Ticket", inversedBy="upload")
     * @ORM\JoinColumn(name="ticket_id", referencedColumnName="id")
     */
    protected $ticket;

    /**
     * @ORM\Column(type="string")
     */
    protected $title;

    /**
     * @ORM\Column(type="string")
     */
    protected $src; 

    public function getAbsolutePath()
    {
        return null === $this->src
            ? null
            : $this->getUploadRootDir().'/'.$this->src;
    }

    public function getWebPath()
    {
        return null === $this->src
            ? null
            : $this->getUploadDir().'/'.$this->src;
    }

    public function getUploadRootDir()
    {
        // The absolute directory path where uplaoded documents should be saved
        return __DIR__.'/../../../../web/'.$this->getUploadDir();
    }

    public function getUploadDir()
    {
        // Get rid of the __DIR__ so it doesn/t screw up when displaying uploaded doc/img in the view
        return 'uploads/documents';
    }

    /**
     * Sets file
     * 
     * @param UploadedFile $file
     */
    public function setFile(UploadedFile $file = null)
    {
        $this->file = $file;

        if (isset($this->path)) {
            // store the old name to delete after the update
            $this->temp = $this->path;
            $this->path = null;
        } else {
            $this->path = 'initial';
        }
    }

    /**
     * Get file
     *
     * @return UploadedFile
     */
    public function getFile()
    {
        return $this->file;
    }

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

    /**
     * Set title
     *
     * @param string $title
     */
    public function setTitle($title)
    {
        $this->title = $title;
    }

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

    /**
     * Set src
     *
     * @param string $src
     */
    public function setSrc($src)
    {
        $this->src = $src;
    }

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

    /**
     * Set ticket
     *
     * @param Sytzeandreae\TicketsBundle\Entity\Ticket $ticket
     */
    public function setTicket(\Sytzeandreae\TicketsBundle\Entity\Ticket $ticket)
    {
        $this->ticket = $ticket;
    }

    /**
     * Get ticket
     *
     * @return Sytzeandreae\TicketsBundle\Entity\Ticket 
     */
    public function getTicket()
    {
        return $this->ticket;
    }

    /**
     * @ORM\PrePersist()
     * @ORM\PreUpdate()
     */
    public function preUpload()
    {
        if (null !== $this->getFile()) {
            // do whatever you want to generate a unique name
            $filename = sha1(uniqid(mt_rand(), true));
            $this->src = $filename.'.'.$this->getFile()->guessExtension();
        }
    }

    public function upload()
    {
        // the file property can be empty if the field is not required
        if (null === $this->getFile()) {
            return;
        }

        // move takes the target directory and then the target filename to move to
        $this->getFile()->move(
            $this->getUploadRootDir(),
            $this->src
        );

        // check if we have an old image
        if (isset($this->temp)) {
            // delete the old image
            unlink($this->getUploadRootDir().'/'.$this->temp);
            // clear the temp image path
            $this->temp = null;
        }

        // clean up the file property as you won't need it anymore
        $this->file = null;
    }

    /**
     * @ORM\PostRemove
     */
    public function removeUpload()
    {
        if ($file = $this->getAbsolutePath()) {
            unlink($file);
        }   
    }
}

表单构建如下:

class TicketType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
            ->add('title')
            ->add('description')
            ->add('priority')
            ->add('uploads', new UploadType())
    }

UploadType 如下所示:

class UploadType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options) {
        $builder->add('file', 'file', array(
            'label' => 'Attachments',
            'required' => FALSE,
            'attr' => array (
                'accept' => 'image/*',
                'multiple' => 'multiple'
            )
        ));
    }

这部分似乎工作正常,我确实收到了一个包含文件上传器的表单。

一旦我将此行放入 Ticket 实体的构造函数中: $this->uploads = new \Doctrine\Common\Collections\ArrayCollection(); 它向我抛出以下错误:

属性“file”、方法“getFile()”和方法“isFile()”都不是 存在于“Doctrine\Common\Collections\ArrayCollection”类中

如果我忽略此行并上传文件,则会引发以下错误:

“Sytzeandreae\TicketsBundle\Entity\Ticket”。也许你应该创造 方法“setUploads()”?

所以我接下来要做的是创建这个方法,再次尝试上传,现在它抛出了我:

类 Symfony\Component\HttpFoundation\File\UploadedFile 不是 有效的实体或映射的超类。

这是我真正陷入困境的地方。我看不到我在哪个阶段做错了什么,希望得到一些帮助:)

谢谢!

【问题讨论】:

  • 你试过this solution吗?
  • 是的,我做到了,尽管我不确定我这样做是否正确。它仍然向我抛出 UploadedFile is not a valid entity 错误...
  • 你的setUpload 方法是什么样的?
  • /** * 设置上传 * * @param Sytzeandreae\TicketsBundle\Enitity\Upload $uploads */ public function setUploads($uploads) { $this->uploads = $uploads; }
  • 请问这个问题的解决方法是什么?

标签: php symfony file-upload doctrine-orm many-to-one


【解决方案1】:

您可以在表单中添加collection field-typeUploadType()。请注意,您不能对当前的 Upload 实体使用 multiple 选项......但这是最快的解决方案。

或者调整您的 Ticket 实体,使其能够处理 ArrayCollection 中的多个文件并循环它们。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-09
    • 2011-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-01
    相关资源
    最近更新 更多