Symfony2文件上传一步一步 [英] Symfony2 file upload step by step

查看:202
本文介绍了Symfony2文件上传一步一步的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



我正在寻找如何使用Symfony2上传文件的指导,但是所有人都需要(例如扩展的约束,基于id和东西重命名文件,将路径存储在db中等等)



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



所以,我会放一个标准实体,让我们说:Photo.php

  / ** 
*照片
*
* @ ORM\\ \\ Table(name =photo)
* @ ORM\Entity
* @ ORM\HasLifecycleCallbacks
* /
class Photo
{
// id和auto increment等的注释
private $ id;

/ **
* @var string
* @ Assert\File(maxSize =3072k,mimeTypesMessage =请上传有效的图片)
* @ ORM\Column(name =image,type =string,length = 245,nullable = false)
* /
private $ image

private $标题

private $ description

//所有的函数get,为4个以前的变量设置
}
/ pre>

和控制器:

  public function addPhotoAction() 
{
$ add_photo = new Photo;
$ formBuilderPhoto = $ this-> createFormBuilder($ add_photo);
$ formBuilderPhoto
- > add('title','text',array('label'=>'照片的标题','required'=> true))
- > add('image','file',array('required'=> true,'data_class'=> null))
- > add('description','textarea' array('label'=>'照片描述','required'=> false))
;

$ form_photo = $ formBuilderPhoto-> getForm();

if($ request-> getMethod()=='POST'){
$ form_photo-> bind($ request);
if($ form_photo-> isValid()){
// ...
}
}
return $ this-> render('MyBundle:前端:photo.html.twig',
数组('form_photo'=> $ form_photo-> createView())
);
}

你现在知道什么是重要功能添加到能够上传照片并重命名?



如何查看扩展程序以查看是否可以上传?



您在Symfony2中做什么的实际方式是什么?我知道有很多Bundle可以为您做所有这些事情,但我想学习做和理解这个过程。



什么是经典的方式使用Symfony2实现文件上传表单和重命名功能?

解决方案


你现在知道什么是添加的重要功能可以上传照片并重命名?


请参阅官方文档如何做到这一点。有一个很好的工作示例,用于简单的文件上传。还要查看生命周期回调的原则文档。


如何查看扩展程序以查看是否可以上传?


每个浏览器都有一些HTML-Form验证。请参阅此问题 HTML accept = 元素中的属性。另外在Symfony2中,您可以指定MIME类型使用此注释上传的文件:

  / ** 
* @ Assert\File(
* maxSize =1024k,
* mimeTypes = {application / pdf,application / x-pdf},
* mimeTypesMessage =请上传有效的PDF
*)
* /

即使您不想使用任何软件包,我不得不推荐你 KnpDoctrineBehavioursBundle ,使文件上传更容易。



< hr>

分步:



因为你已经阅读了文档,我会给你一步一步的代码 -



首先需要一个实体。让我们称之为图像

  / ** 
*类图像
*
* @ ORM\Entity()
* @ ORM\HasLifecycleCallbacks
* /
类图像扩展BaseEntity
{$ b注意 @ ORM\HasLifecycleCallbacks 注释。这是非常很重要,您需要它。我们创建所有基本字段,如 ID ,而不是。另外,我们需要一个字段来存储文件路径:

  / ** 
*图像路径
*
* @var string
*
* @ ORM\Column(type =text,length = 255,nullable = false)
* /
protected $路径;

另一个用于图片本身。这里我们还定义了图像的验证。在我的例子中,它必须是 5M 大,并且定义的 mimeTypes 之一。应该不言自明。否则官方文档将一如既往的帮助。

  / ** 
*图像文件
*
* @var文件
*
* @ Assert\File(
* maxSize =5M,
* mimeTypes = {image / jpeg,image / gif,image / png,image / tiff} ,
* maxSizeMessage =最大允许的文件大小为5MB,
* mimeTypesMessage =只允许文件类型的图像
*)
* /
保护$文件;

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

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

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

  / ** 
*保存实体前调用
*
* @ ORM\\ \\ PrePersist()
* @ ORM\PreUpdate()
* /
public function preUpload()
{
if(null!== $ this-> ;文件){
//做任何你想要生成的唯一名称
$ filename = sha1(uniqid(mt_rand(),true));
$ this-> path = $ filename。'。'$ this-> file-> guessExtension();
}
}

在实体存储或更新之前,此方法被称为。你可以用它来生成唯一的文件名。

  / ** 
*实体删除前调用
*
* @ ORM\ PreRemove()
* /
public function removeUpload()
{
if($ file = $ this-> getAbsolutePath()){
unlink($ file );
}
}

在实体被移除之前调用。这样,您可以随时从文件夹中删除图像,或者如果您想要的话,请记录消息。

  / ** 
*在实体持久化后调用
*
* @ ORM\PostPersist()
* @ ORM\PostUpdate()
* /
public function upload()
{
//如果不需要该字段,该文件属性可以为空
if(null === $ this-> file){
return;
}

//在这里使用原始文件名,但是您应该
//至少消除它以避免任何安全问题

// move取目标目录,然后
//目标文件名移动到
$ this-> file-> move(
$ this-> getUploadRootDir(),
$ this-> path
);

//将path属性设置为保存文件的文件名
// $ this-> path = $ this-> file-> getClientOriginalName();

//清理文件属性,因为您不再需要它
$ this-> file = null;
}

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



下一件你需要的是一个表单。表单类本身很简单。只需确保您设置默认的 data_class ,如下所示:

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

);
}

可以在 buildForm()方法:

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

您的控制器的方法有点长久以来只是粘贴他们在这里和IMHO它不是回答你的问题的一部分。为了您的目的,有无数的例子为您编写适当的控制器操作






更多的事情你必须记住:




  • 你需要给你的应用程序将上传文件的文件夹写入权限。虽然看起来很明显,如果您有多个服务器,您可以运行应用程序,那么可能会令人烦恼。

  • 为您提供了一个 Image Constraint 实体也是。你可以找到它 here 。但是,由于您正在谈论文件上传,因此我使用文件约束

  • 正如我所提到的在这篇文章的顶部,有很多Bundles可以处理所有这些事情。如果你想要一个简单的生活,请检查出来。



编辑:




  • DoctrineExtensionsBundle 更改为 DoctrineBehaviours 由于旧版开发停止了 DoctrineBehaviours bundle。


I am still learning Symfony2 and don't understand how to upload a file.

Don't worry, I've already checked the documentation. It's really good, but my problem isn't explained in any tutorial.

I am looking for guidance on how to upload a file with Symfony2 but with all the thing everybody needs (such as constraint of extension, rename of the file based on the id and stuff, store the path in the db, etc...)

I found good tutorials, tried to mixed them but with no success. Each time a different problem appears: file re-uploads on every submit on the form (even if the file field is empty), guessExtension impossible to used, tmp path stored in the database instead of the right path, file not moved, impossible to used the id in the rename because the id is on auto-increment and so not yet generated).

So, I'll put an 'standard' entity, let say: 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
}

and the controller:

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())
    );
}

Do you know now what are the 'important' function to add to be able to upload the photo and rename it ?

How do you check the extension to see if the upload is possible?

What is your actual way of doing such a thing with Symfony2? I know there is a lot of Bundle that do all those things for you but I want to learn to do it and understand the process.

What is the 'classic' way to implement a file upload form and rename function with Symfony2?

解决方案

Do you know now what are the 'important' function to add to be able to upload the photo and rename it?

See the official documentation on how to do this. There are good working examples for a simple file upload. Also check the doctrine documentation for lifecycle callbacks.

How do you check the extension to see if the upload is possible?

There is some HTML-Form validation in each browser. See this question for the HTML accept="" attribute in input elements. Also in Symfony2 you can specify the MIME-type of an uploaded file using this annotation:

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

Even though you did not want to use any bundles I'll have to recommend you the KnpDoctrineBehavioursBundle which makes file uploading way easier.


Step-by-step:

Because you read the documentation already I'll give you a step by step code-example.

First of all you need an entity. Let's call it Image:

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

Note the @ORM\HasLifecycleCallbacks annotation. It is very important and you need it later. We create all the basic fields like ID and what not. Also we need a field to store the file path in:

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

And one for the Image itself. Here we also define the Validation for the images. In my example it has to be 5M big and of one of the defined mimeTypes. It should be self-explanatory. Otherwise the official docs help as always.

    /**
     * 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;

Add all the Getters & Setters and update your database schema with this command:

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

Next we need the lifecycles. They are methods in the Entity that are called on certain events. For example the @ORM\PreUpdate() annotation before a method says that this method is being called right before the entity gets updated.

/**
 * 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();
    }
}

Before the entity gets stored or updated this method is called. You can use it to e.g. generate a unique file name.

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

Called before the entity gets removed. This gives you time to delete the image from your folders or log a message if you want to.

/**
 * 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;
}

This is the important part where your file is actually moved to the right directory. Note that I have used some additional methods. You can all get them from the official docs.

Next thing you need is a form. The form class itself is very simple. Just make sure you set the default data_class like this:

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

A file upload field can be created very easily in the buildForm() method:

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

The methods for your Controller are a little long for just pasting them here and IMHO it's not part of answering your question. There are countless examples out there for writing a proper Controller Action for your purpose.


More things you have to keep in mind:

  • You need to give your app writing permissions to the folders you upload the files to. Although it seems obvious it can be annoying if you have multiple servers you run the application on.
  • There is an Image Constraint for your entity as well. You can find it here. But since you were talking about a file upload I used the File Constraint instead.
  • As I mentioned in the top of this post, there are many Bundles that handle all these things for you. Check them out if you want an easy life.

Edit:

  • Changed from DoctrineExtensionsBundle to DoctrineBehaviours since development on the old one stopped in favour of the DoctrineBehaviours bundle.

这篇关于Symfony2文件上传一步一步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆