Symfony2文件一步一步上传

Tyr*_*ael 55 upload file formbuilder symfony doctrine-orm

我还在学习Symfony2并且不了解如何上传文件.

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

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

我找到了很好的教程,试图混合它们但没有成功.每次出现不同的问题:文件在表单上的每次提交时重新上传(即使文件字段为空),guessExtension也不可能使用,tmp路径存储在数据库而不是正确的路径,文件没有移动,不可能在重命名中使用了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
}
Run Code Online (Sandbox Code Playgroud)

和控制器:

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())
    );
}
Run Code Online (Sandbox Code Playgroud)

您现在知道添加什么是"重要"功能,以便能够上传照片并重命名吗?

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

你用Symfony2做这种事情的实际方法是什么?我知道有很多Bundle会为你做所有这些事情,但我想学会这样做并理解这个过程.

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

fer*_*tor 110

您现在知道添加什么是"重要"功能,以便能够上传照片并重命名吗?

请参阅有关如何执行此操作的官方文档.简单的文件上传有很好的工作示例.还要检查生命周期回调的学说文档.

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

每个浏览器都有一些HTML表单验证.有关元素中的HTML 属性,请参阅此问题.同样在Symfony2中,您可以使用此批注指定上载文件的MIME类型:accept=""input

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

即使您不想使用任何捆绑包,我也必须向您推荐KnpDoctrineBehavioursBundle,这样可以更轻松地上传文件.


一步步:

因为您已经阅读了文档,我将逐步为您提供代码示例.

首先,你需要一个实体.我们称之为Image:

/**
 * Class Image
 *
 * @ORM\Entity()
 * @ORM\HasLifecycleCallbacks
 */
class Image extends BaseEntity
{
Run Code Online (Sandbox Code Playgroud)

注意@ORM\HasLifecycleCallbacks注释.这非常重要,您以后需要它.我们创造所有基本领域ID,如何,不是.我们还需要一个字段来存储文件路径:

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

而一个是图像本身.在这里,我们还定义了图像的验证.在我的例子中,它必须是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;
Run Code Online (Sandbox Code Playgroud)

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

php app/console doctrine:schema:update --force
Run Code Online (Sandbox Code Playgroud)

接下来我们需要生命周期.它们是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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

在实体被删除之前调用.这使您有时间从文件夹中删除图像或记录消息(如果需要).

/**
 * 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;
}
Run Code Online (Sandbox Code Playgroud)

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

接下来你需要的是一个表格.表单类本身非常简单.只需确保您设置默认值,data_class如下所示:

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

可以在buildForm()方法中非常轻松地创建文件上载字段:

$builder->add('file', 'file');
Run Code Online (Sandbox Code Playgroud)

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


你需要记住的更多事情:

  • 您需要为app上载文件的文件夹授予写入权限.虽然看起来很明显,如果你有多台服务器就可以运行应用程序.
  • Image Constraint你的实体也有一个.你可以在这里找到它.但是既然你在谈论文件上传,我就用了File Constraint.
  • 正如我在本文顶部提到的,有许多Bundles可以为您处理所有这些事情.如果你想要轻松生活,请检查它们.

编辑:

  • 从改变DoctrineExtensionsBundleDoctrineBehaviours,因为在旧的发展有利于终止DoctrineBehaviours束.

  • 由于与OP类似的原因,我被引导到了这个问题.这个答案比官方文档更清晰!对你好,两年后,它仍然比文档更有意义......我发现这样的事情到目前为止Symfony的唯一问题.它功能强大但文档很差 (3认同)

Sid*_*lak 13

我建议你使用vlabs媒体包.

  • 这完美无缺 - 简单,并有适当的文档.谢谢! (2认同)

Tim*_*ius 6

VichUploaderBundle也易于上传文件:

https://github.com/dustin10/VichUploaderBundle