Home » Php » php – Symfony2: Uploads a file using Ajax and jQuery

php – Symfony2: Uploads a file using Ajax and jQuery

Posted by: admin July 12, 2020 Leave a comment

Questions:

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?

How to&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

Answer:

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.

Answer:

Update:

I think the problem is that you must deserialize the received in your controller in case you are submitting via ajax

Addentionally you should serialize the form explicitly and not serialize using thisthis

var data= $('form.form_student').serialize();