3

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

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

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

class Ticket {

// snip

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

// snip
}

上传实体类包含我从教程中获取的上传功能:

<?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(); 它向我抛出以下错误:

类“Doctrine\Common\Collections\ArrayCollection”中既不存在属性“file”,也不存在方法“getFile()”或方法“isFile()”

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

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

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

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

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

谢谢!

4

1 回答 1

0

您可以将集合字段类型添加到UploadType()表单中。请注意,您不能对当前Upload实体使用多个选项......但这是最快的解决方案。

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

于 2013-07-16T14:18:35.610 回答