Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2: Uploads a file using Ajax and jQuery

I have a Symfony2 application with a form where a file type field. I need to upload an image of a student there, so I helped this documentation: How to Upload Files

It is my code:

Controller:

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

Entity:

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

formtype:

   //...

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

   //...

Javascript:

 //...

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

The problem I have now is I have to do it with an Ajax request, but do not know how to send that file field and it can be used then in Symfony controller.

I have seen some FormData(), but do not know how it is used.

Could you help me?

like image 309
Joseph Avatar asked Jan 20 '16 17:01

Joseph


People also ask

Can we upload file using AJAX?

Ajax file uploadsA component must exist on the server to handle the file upload and save the resource locally; The server must send a response to the browser indicating the JavaScript file upload was successful; and. The client's browser must provide an Ajax-based response indicating the file uploaded successfully.

How upload file with jQuery Ajax in MVC?

Uploading Files in MVC using jQuery AJAX FormDataGo to File->New->Project. Give a suitable name to the Application. Click OK. As you can see in the above image, two files are sent to C# ActionMethod, and both will be uploaded now.


2 Answers

I've solved changing in my code:

  • data: new FormData($(this)[0]) instead of data: $ (this).serialize()

  • Adding the ajax request:

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

and the file is sent correctly

like image 133
Joseph Avatar answered Oct 24 '22 07:10

Joseph


I have solve this in following way, if you want to do it using Ajax.

In your entity declare this :

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

In your FormType :

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

In you Controller :

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

your ajax looks fine, but if this will not work than use

  data:new FormData(this),

instead of

  data: $(this).serialize(),

and add these two parameters in ajax:

      processData: false,
      contentType: false  

You can change save file method as your requirement and change path field to photo.

like image 3
herr Avatar answered Oct 24 '22 09:10

herr