2013-10-24 66 views
4

我有工作實體References.php包括Image,但我不知道如何在Symfony2中刪除保存在此引用中的舊映像(如果存在)並創建新。因爲現在,它並沒有刪除當前圖像,所以只創建了一個新的並將image_path設置到此實體中。這是我嘗試刪除它preUpload方法,但它目前的文件設置爲NULL再沒有什麼(所以我有錯誤 - 你必須選擇一個文件Symfony2,文件上傳 - 刪除舊的和創建新的編輯

<?php 

namespace Acme\ReferenceBundle\Entity; 

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

/** 
* @ORM\Entity(repositoryClass="Acme\ReferenceBundle\Entity\ReferenceRepository") 
* @ORM\Table(name="`references`") 
* @ORM\HasLifecycleCallbacks 
*/ 
class Reference 
{ 
    /** 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id;    

    /** 
    * @ORM\Column(type="string", length=200)  
    * @Assert\NotBlank(
    *  message = "Name cannot be blank"  
    *)  
    * @Assert\Length(
    *  min = "3", 
    *  minMessage = "Name is too short"   
    *)  
    */  
    private $name; 

    /** 
    * @ORM\Column(type="string", length=200)  
    * @Assert\NotBlank(
    *  message = "Description cannot be blank"  
    *)  
    * @Assert\Length(
    *  min = "3", 
    *  minMessage = "Description is too short"   
    *)  
    */  
    private $description; 

    /** 
    * @ORM\Column(type="string", length=200) 
    * @Assert\Url(
    *  message = "URL is not valid" 
    *)   
    */  
    private $url; 

    /** 
    * @ORM\ManyToMany(targetEntity="Material", inversedBy="references") 
    * @Assert\Count(min = 1, minMessage = "Choose any material") 
    */ 
    private $materials; 

    /** 
    * @ORM\Column(type="text", length=255, nullable=false) 
    * @Assert\NotNull(
    *  message = "You have to choose a file" 
    *)  
    */ 
    private $image_path; 

    /** 
    * @Assert\File(
    *  maxSize = "5M", 
    *  mimeTypes = {"image/jpeg", "image/gif", "image/png", "image/tiff"}, 
    *  maxSizeMessage = "Max size of file is 5MB.", 
    *  mimeTypesMessage = "There are only allowed jpeg, gif, png and tiff images" 
    *) 
    */ 
    private $file;     

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

    /** 
    * Set name 
    * 
    * @param string $name 
    * @return Reference 
    */ 
    public function setName($name) 
    { 
     $this->name = $name; 

     return $this; 
    } 

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

    /** 
    * Set description 
    * 
    * @param string $description 
    * @return Reference 
    */ 
    public function setDescription($description) 
    { 
     $this->description = $description; 

     return $this; 
    } 

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

    /** 
    * Set url 
    * 
    * @param string $url 
    * @return Reference 
    */ 
    public function setUrl($url) 
    { 
     $this->url = $url; 

     return $this; 
    } 

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

    /** 
    * Set materials 
    * 
    * @param string $materials 
    * @return Reference 
    */ 
    public function setMaterials($materials) 
    { 
     $this->materials = $materials; 

     return $this; 
    } 

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

    /** 
    * Set image_path 
    * 
    * @param string $imagePath 
    * @return Reference 
    */ 
    public function setImagePath($imagePath) 
    { 
     $this->image_path = $imagePath; 

     return $this; 
    } 

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

    public function setFile(UploadedFile $file = null) 
    { 
     $this->file = $file; 
    } 

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

    /** 
    * Called before saving the entity 
    * 
    * @ORM\PrePersist() 
    * @ORM\PreUpdate() 
    */ 
    public function preUpload() 
    { 
     $oldImage = $this->image_path; 
     $oldImagePath = $this->getUploadRootDir().'/'.$oldImage; 

     if (null !== $this->file) { 
      if($oldImage && file_exists($oldImagePath)) unlink($oldImagePath); // not working correctly 
      $filename = sha1(uniqid(mt_rand(), true)); 
      $this->image_path = $filename.'.'.$this->file->guessExtension(); 
     } 
    } 

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

    /** 
    * Called after entity persistence 
    * 
    * @ORM\PostPersist() 
    * @ORM\PostUpdate() 
    */ 
    public function upload() 
    { 
     // the file property can be empty if the field is not required 
     if (null === $this->file) { 
      return; 
     } 

     // use the original file name here but you should 
     // sanitize it at least to avoid any security issues 

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

     // set the path property to the filename where you've saved the file 
     $this->image_path = $this->file->getClientOriginalName(); 

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

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

    protected function getUploadRootDir() 
    { 
     // the absolute directory path where uploaded 
     // documents should be saved 
     return __DIR__.'/../../../../'.$this->getUploadDir(); 
    } 

    protected function getUploadDir() 
    { 
     // get rid of the __DIR__ so it doesn't screw up 
     // when displaying uploaded doc/image in the view. 
     return 'uploads/references'; 
    } 

    public function getWebPath() 
    { 
     return $this->getUploadDir().'/'.$this->image_path; 
    } 
    /** 
    * Constructor 
    */ 
    public function __construct() 
    { 
     $this->materials = new \Doctrine\Common\Collections\ArrayCollection(); 
    } 

    /** 
    * Add materials 
    * 
    * @param \Acme\ReferenceBundle\Entity\Material $materials 
    * @return Reference 
    */ 
    public function addMaterial(\Acme\ReferenceBundle\Entity\Material $materials) 
    { 
     $this->materials[] = $materials; 

     return $this; 
    } 

    /** 
    * Remove materials 
    * 
    * @param \Acme\ReferenceBundle\Entity\Material $materials 
    */ 
    public function removeMaterial(\Acme\ReferenceBundle\Entity\Material $materials) 
    { 
     $this->materials->removeElement($materials); 
    } 
} 

任何想法?

回答

4

所以我找到解決方案。首先,我必須爲File Uploading創建一個Assert回調函數,因爲我使用NotNull()聲明Reference實體。所以如果我選擇了任何文件併發送表單,我總是得到錯誤You have to choose a file。所以我的第一個編輯在這裏:

use Symfony\Component\Validator\ExecutionContextInterface;  // <-- here 

/** 
* @ORM\Entity(repositoryClass="Acme\ReferenceBundle\Entity\ReferenceRepository") 
* @ORM\Table(name="`references`") 
* @ORM\HasLifecycleCallbacks 
* @Assert\Callback(methods={"isFileUploadedOrExists"})  <--- and here 
*/ 
class Reference 
{ 
    // code 
} 

,然後在我的代碼添加一個新方法:

public function isFileUploadedOrExists(ExecutionContextInterface $context) 
{ 
    if(null === $this->image_path && null === $this->file) 
     $context->addViolationAt('file', 'You have to choose a file', array(), null); 
} 

而且我在$image_path屬性刪除NotNull斷言。

然後它工作順利 - 如果我選擇了一個文件並提交了表單,則參考文件是使用圖像創建的。但尚未完成。有我在這個問題中問我的問題 - 刪除舊圖像,並創建一個新的圖像當然,新的路徑。

經過多次實驗,我發現工作和好看的解決方案。在我的控制器,我添加表單驗證之前,它是用來刪除舊圖像之後的一個變量:

$oldImagePath = $reference->getImagePath(); // get path of old image 

if($form->isValid()) 
{ 
    if ($form->get('file')->getData() !== null) { // if any file was updated 
     $file = $form->get('file')->getData(); 
     $reference->removeFile($oldImagePath); // remove old file, see this at the bottom 
     $reference->setImagePath($file->getClientOriginalName()); // set Image Path because preUpload and upload method will not be called if any doctrine entity will not be changed. It tooks me long time to learn it too. 
    } 
    $em->persist($reference); 
    try { 
     $em->flush(); 
    } catch (\PDOException $e) { 
     //sth 
    } 

而我removeFile()方法:

public function removeFile($file) 
{ 
    $file_path = $this->getUploadRootDir().'/'.$file; 
    if(file_exists($file_path)) unlink($file_path); 
} 

和結束時,我在刪除$this->image_path = $this->file->getClientOriginalName();upload()方法,因爲它會導致表單中的預覽圖像出現問題,如果使用任何。它將原始文件名設置爲路徑,但是如果重新加載頁面,則會看到圖像的真實路徑。刪除這條線將解決這個問題。

感謝大家發佈的答案,誰幫我找到解決方案。

1

image_path屬性上的@Assert \ NotNull在您的PrePersist/PreUpdate方法之前進行了測試,因此表單驗證並不滿意,因爲image_path僅在實體內部提供,請求未提供帶有「image_path」屬性,我認爲你應該刪除這個Assert,因爲它沒有鏈接到一個表單,所以我認爲這並不是很有用。

OR

舊IMAGE_PATH是新鮮的,而不是舊的,因爲它是後結合的形式處理。

+0

這很有用,因爲如果有人試圖發佈沒有上傳圖片的新表單,他會得到一個MySQL異常,這不是很漂亮。 –

+0

那麼,我怎麼能得到舊的圖像路徑? –

+0

我會嘗試在調用form-> handleRequest或form-> bind之前得到它,在實體中使用不同的方法,所以綁定後,實體是乾淨的 – Taytay

1

您應該使用event listeners,它比實體中的註釋事件更好,這樣您就可以在preUpdate事件中檢索正確的值。

,你可以使用的方法類似這樣:

hasChangedField($fieldName) to check if the given field name of the current entity changed. 
getOldValue($fieldName) and getNewValue($fieldName) to access the values of a field. 
setNewValue($fieldName, $value) to change the value of a field to be updated. 
2

如果IMAGE_PATH已經設置有要替換一個「老」的形象。

裏面你upload()方法,而不是...

// set the path property to the filename where you've saved the file 
    $this->image_path = $this->file->getClientOriginalName(); 

...檢查以前的文件的存及其之前將其刪除:

if ($this->image_path) { 
    if ($file = $this->getAbsolutePath()) { 
     unlink($file); 
    } 
} 
$this->image_path = $this->file->getClientOriginalName(); 
+0

如果我選擇要上傳的圖像,仍然在創建新的參考消息(您必須選擇一個文件)。 –

相關問題