2013-10-24 48 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

如果我选择要上传的图像,仍然在创建新的参考消息(您必须选择一个文件)。 –

相关问题