Symfony2:使用Ajax和jQuery上传文件

时间:2016-01-20 17:04:36

标签: php jquery ajax symfony

我有一个Symfony2应用程序,其中包含一个文件类型字段的表单。我需要在那里上传一个学生的图像,所以我帮助了这个文档:How to Upload Files

这是我的代码:

控制器:

Replication

role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

实体:

public function createAction(Request $request)
{        
    if ($request->isXmlHttpRequest() && !$request->isMethod('POST')) {
    throw new HttpException('XMLHttpRequests/AJAX calls must be POSTed');
    }

    $entity = new Student();
    $form = $this->createCreateForm($entity);
    $form->handleRequest($request);

    if ($form->isValid()) {
       $file = $entity->getPhoto();

       $fileName = md5(uniqid()).'.'.$file->guessExtension();

       $photoDir = $this->container->getParameter('kernel.root_dir').'/../web/uploads/images';

       $file->move($photoDir, $fileName);

       $entity->setPhoto($fileName);

       $em = $this->getDoctrine()->getManager();
       $em->persist($entity);
       $em->flush();

       if ($request->isXmlHttpRequest()) {
            return new JsonResponse(array('message' => 'Success!','success' => true), 200);
        }

        if ($request->isMethod('POST')) {
        return new JsonResponse(array('message' => 'Invalid form','success' => false), 400);
    }

      return $this->redirect($this->generateUrl('student_show', array('id' => $entity->getId())));
    }
    return $this->render('BackendBundle:Student:new.html.twig', array(
        'entity' => $entity,
        'form'   => $form->createView(),
    ));
}

formtype:

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

   //...
   /**
   * @var string
   *
   * @ORM\Column(name="photo", type="string", length=255, nullable=true)
   * 
   */
   private $photo;


   public function setPhoto($photo)
   {
    $this->photo = $photo;

    return $this;
   }

   public function getPhoto()
   {
    return $this->photo;
   }

使用Javascript:

   //...

   ->add('photo', 'file', array('required' => false))

   //...

我现在遇到的问题是我必须使用Ajax请求,但不知道如何发送该文件字段,然后可以在Symfony控制器中使用它。

我见过一些 //... $('.form_student').on("submit",function(event) { event.preventDefault(); $.ajax({ type: 'POST', url: Routing.generate('student_create'), data: $(this).serialize(), dataType: 'json', success: function(response) { alert(response.message); }, error: function (response, desc, err){ if (response.responseJSON && response.responseJSON.message) { alert(response.responseJSON.message); } else{ alert(desc); } } }); }); ,但不知道它是如何使用的。

你能帮帮我吗?

3 个答案:

答案 0 :(得分:11)

我已经解决了我的代码更改问题:

  • data: new FormData($(this)[0])代替data: $ (this).serialize()

  • 添加ajax请求:

    processData: false,   contentType: false,   cache: false,

并正确发送文件

答案 1 :(得分:3)

如果您想使用Ajax,我可以通过以下方式解决此问题。

在您的实体中声明:

/** 
 *@ORM\HasLifecycleCallbacks
 */
class Student
{
    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    public $path;

    /**
     * @Assert\File(
     *   maxSize="60000",
     * )
     */
    private $file;

    private $temp;

    /**
     * Sets file.
     *
     * @param UploadedFile $file
     */
    public function setFile(UploadedFile $file = null)
    {
        $this->file = $file;
        if (isset($this->path)) {
            // store the old name to delete after the update
            $this->temp = $this->path;
            $this->path = null;
        } else {
            $this->path = 'initial';
        }
    }

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

    public function getAbsolutePath()
    {
        return null === $this->path
            ? null
            : $this->getUploadRootDirPath().'/'.$this->path;
    }

    public function getWebPath()
    {
        return null === $this->path
            ? null
            : $this->getUploadDirPath().'/'.$this->path;
    }

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

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

    /**
     * @ORM\PrePersist()
     * @ORM\PreUpdate()
     */
    public function preUpload()
    {
        if (null !== $this->getFile()) {
            // do whatever you want to generate a unique name
            $filename = basename($this->getFile()->getClientOriginalName(),'.'.$this->getFile()->getClientOriginalExtension());
            $this->path = $filename.'.'.$this->getFile()->getClientOriginalExtension();
            if(file_exists($this->getUploadRootDirPath().'/'.$this->path)==1)
            {
                $date = date('-d_M_Y_H:i');
                $this->path = $filename.$date.'.'.$this->getFile()->getClientOriginalExtension();
            }
        }
    }

    /**
     * @ORM\PostPersist()
     * @ORM\PostUpdate()
     */
    public function upload()
    {
        if (null === $this->getFile()) {
            return;
        }

        $this->getFile()->move($this->getUploadRootDirPath(), $this->path);

        if (isset($this->temp)) {
            // delete the old image
            unlink($this->getUploadRootDirPath().'/'.$this->temp);
            // clear the temp image path
            $this->temp = null;
        }
        $this->file = null;
    }


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

在您的FormType中:

->add('file', null, array('label' => 'Profile Picture', 'required' => false))

在你的控制器中:

   $entity->setFile($request->files->get('photo')); //here you have get your file field name
   $em->persist($entity);
   $em->flush();

你的ajax看起来很好,但如果这不会比使用

  data:new FormData(this),

而不是

  data: $(this).serialize(),

并在ajax中添加这两个参数:

      processData: false,
      contentType: false  

您可以根据需要更改保存文件方法,并将路径字段更改为照片。

答案 2 :(得分:0)

更新

我认为问题在于,如果您通过ajax提交,则必须对控制器中收到的信息进行反序列化

相应地,您应该明确地序列化表单,而不是使用此a = b += 12; // works in C#, but not in VB

序列化
echo "My Page" > index.html