Symfony2文件一步一步上传

我仍然在学习Symfony2,不明白如何上传文件。

别担心,我已经检查了文件 。 这真的很好,但我的问题没有在任何教程中解释。

我正在寻找如何上传与Symfony2文件,但与所有人都需要的东西(如扩展的约束,基于ID和东西的文件重命名,存储在path中的数据库等)的指导…)

我发现很好的教程,试图混合他们,但没有成功。 每次出现不同的问题:文件在表单上的每一个提交上重新上传(即使文件字段为空),guessExtension不可能使用,tmppath存储在数据库而不是正确的path,文件不移动,不可能在重命名中使用了id,因为id是自动递增的,所以还没有生成)。

所以,我会把一个“标准”的实体,说:Photo.php

/** * Photo * * @ORM\Table(name="photo") * @ORM\Entity * @ORM\HasLifecycleCallbacks */ class Photo { // Annotation for the id and auto increment etc private $id; /** * @var string * @Assert\File( maxSize = "3072k", mimeTypesMessage = "Please upload a valid Image") * @ORM\Column(name="image", type="string", length=245, nullable=false) */ private $image private $title private $description // all the function get, set for the 4 previous variables } 

和控制器:

 public function addPhotoAction() { $add_photo = new Photo; $formBuilderPhoto = $this->createFormBuilder($add_photo); $formBuilderPhoto ->add('title','text',array('label' => 'Title of the photo', 'required' => true)) ->add('image','file', array('required' => true, 'data_class' => null)) ->add('description','textarea',array('label' => 'Description of your photo', 'required' => false)) ; $form_photo = $formBuilderPhoto->getForm(); if ($request->getMethod() == 'POST') { $form_photo->bind($request); if ($form_photo->isValid()) { // ... } } return $this->render('MyBundle:frontend:photo.html.twig', array('form_photo' => $form_photo->createView()) ); } 

你现在知道什么是“重要的”function来添加上传照片并重新命名吗?

你如何检查扩展,看是否可以上传?

你用Symfony2做这样的事情的实际方法是什么? 我知道有很多Bundle能够为你做所有这些事情,但是我想学习如何去理解这个过程。

用Symfony2实现file upload和重命名function的“经典”方式是什么?

你现在知道什么是“重要的”function来添加上传照片并重新命名吗?

请参阅有关如何执行此操作的官方文档 。 有一个简单的file upload很好的工作示例。 还请检查生命周期callback的原则文档。

你如何检查扩展,看是否可以上传?

在每个浏览器中都有一些HTML-Formvalidation。 在input元素中看到这个问题的HTML accept=""属性。 同样在Symfony2中,您可以使用这个注释来指定上传文件的MIMEtypes :

 /** * @Assert\File( * maxSize = "1024k", * mimeTypes = {"application/pdf", "application/x-pdf"}, * mimeTypesMessage = "Please upload a valid PDF" * ) */ 

即使你不想使用任何捆绑包,我将不得不推荐你使用file upload方式的KnpDoctrineBehavioursBundle 。


一步步:

因为你已经阅读过文档,我会逐步给你一个代码示例。

首先你需要一个实体。 我们称之为Image

 /** * Class Image * * @ORM\Entity() * @ORM\HasLifecycleCallbacks */ class Image extends BaseEntity { 

请注意@ORM\HasLifecycleCallbacks注释。 这是非常重要的,你以后需要它。 我们创build所有的基本领域,如ID和什么不是。 我们还需要一个字段来存储文件path:

  /** * Image path * * @var string * * @ORM\Column(type="text", length=255, nullable=false) */ protected $path; 

而一个为图像本身。 这里我们也定义了图像的validation。 在我的例子中,它必须是5M大的和定义的mimeTypes 。 这应该是不言自明的。 否则, 官方文件一如既往的帮助。

  /** * Image file * * @var File * * @Assert\File( * maxSize = "5M", * mimeTypes = {"image/jpeg", "image/gif", "image/png", "image/tiff"}, * maxSizeMessage = "The maxmimum allowed file size is 5MB.", * mimeTypesMessage = "Only the filetypes image are allowed." * ) */ protected $file; 

添加所有Getters & Setters并使用以下命令更新数据库模式:

 php app/console doctrine:schema:update --force 

接下来我们需要生命周期 。 它们是Entity中被某些事件调用的方法。 例如,在一个方法之前, @ORM\PreUpdate()注释表示在实体更新之前正在调用此方法。

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

在实体被存储或更新之前调用此方法。 您可以使用它来生成一个唯一的文件名。

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

在实体被移除之前调用。 这样可以让您有时间从文件夹中删除图像,或者在需要时logging消息。

 /** * 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->path ); // Set the path property to the filename where you've saved the file //$this->path = $this->file->getClientOriginalName(); // Clean up the file property as you won't need it anymore $this->file = null; } 

这是您的文件实际移动到正确的目录的重要部分。 请注意,我已经使用了一些额外的方法。 你们都可以从官方文档中获得 。

接下来你需要的是一个表单。 表单类本身非常简单。 只要确保你像这样设置默认的data_class

 public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults( array( 'data_class' => 'FSchubert\SiyabongaBundle\Entity\Image', ) ); } 

buildForm()方法中可以很容易地创build一个file upload字段:

 $builder->add('file', 'file'); 

你的Controller的方法有点长,只是粘贴在这里,恕我直言,这不是回答你的问题的一部分。 有无数的例子,为您的目的写一个适当的Controller Action


更多的事情你必须记住:

  • 你需要给你的app写file upload文件的权限。 虽然看起来很明显,如果你有多个服务器运行应用程序,这可能很烦人。
  • 还有一个你的实体的Image Constraint 。 你可以在这里find它。 但是既然你是在谈论一个文件上传,我用File Constraint来代替。
  • 正如我在这篇文章的顶部所提到的,有很多Bundle为你处理所有这些事情。 检查出来,如果你想要一个轻松的生活。

编辑:

  • DoctrineExtensionsBundle更改为DoctrineExtensionsBundle ,因为旧版本的开发停止了DoctrineBehaviours包。

我build议你使用vlabs媒体包 。

VichUploaderBundle也很容易使用上传文件:

https://github.com/dustin10/VichUploaderBundle