2013-07-16 31 views
3

我正在爲實踐目的創建一個票務系統。如何在Symfony2中處理與多對一關係的文件上傳?

現在我在上傳文件時遇到問題。

這個想法是一張票可以有多個附件,所以我創建了票和上傳表之間的多對一關係。

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(); 它拋出我下面的錯誤:

Neither property "file" nor method "getFile()" nor method "isFile()" exists in class "Doctrine\Common\Collections\ArrayCollection"

如果我離開這一行了,並上傳文件時,它拋出我下面的錯誤:

"Sytzeandreae\TicketsBundle\Entity\Ticket". Maybe you should create the method "setUploads()"?

我這樣做,接下來的事情是創造這種方法,嘗試再次上傳,現在它拋出我:

Class Symfony\Component\HttpFoundation\File\UploadedFile is not a valid entity or mapped super class.

這是我真的被卡住了。我沒有看到什麼,在什麼階段,我做錯了,並希望得到一些幫助:)

謝謝!

+0

您是否試過[此解決方案](http://stackoverflow.com/a/6930001/1847340)? – ferdynator

+0

是的,我做了,儘管不確定我是否以正確的方式做了。它仍然扔我UploadedFile不是一個有效的實體錯誤... – Njerpie

+0

你的'setUpload'方法是什麼樣子? – ferdynator

回答

0

您可以將UploadType()collection field-type添加到您的表單中。請注意,您不能對當前的Upload實體使用多個選項......但這是最快的解決方案。

或修改您的Ticket實體,以便能夠處理ArrayCollection中的多個文件並循環播放它們。