You work with Symfony, but the concept of dependency injection is a little blurry for you? Find out how to take advantage of the component reading this article.
Upload file with AJAX
Today, I would like to share with you a feature often requested in an application: uploading a file. Very often, the upload of a file is done via a form in html with the attribute enctype="multipart/form-data". Then the form is posted to the server. But when a file weighs several megabytes, or several gigabytes, the user waits without any response from server during file uploading.
This is where AJAX comes in! (Wouhou!) It will both allow us to make this upload as asynchronous and allow to have information about its state.
Implementing the Symfony form
My form will contain two fields: name and file. The first one will contain the name of the file that the user wants to give. The second will be the representation of the file via the Symfony\Component\HttpFoundation\File\UploadedFile object.
Symfony has a FormType that is FileType. As the name suggests, it allows you to manage a form field of file type.
In addition to this form, I'll link it to an AppBundle\Entity\File entity, which will then allow me to persist it in the database.
I added constraints on the file field. It allows me to validate that the file that I will upload is the right type and a maximum size of 1Go.
On the controller side, I set up a route to display my form and another to handle the file upload query.
I set up a listener on the kernel.view event to handle the case where the form is invalid (see src/AppBundle/EventListener/ViewListener.php).
So far, nothing surprising. I invite you to read the Symfony documentation for more information: http://symfony.com/doc/current/controller/upload_file.html.
I will first set up the HTML form.
Like the Symfony form that I just created earlier, there are two fields: name and file.
I added 3 DOM elements. They will allow me to display any errors and the progress of the upload.
Then I will add a listener on the submit event of the form. This will allow me to upload to AJAX instead of the html form.
At first, I will take all the form fields and put them in the FormData object. It facilitates the transport of form values. This object will then be used during the AJAX query.
Then, I prepare my XMLHttpRequest object. I tell him where to post the data, add some listeners and finally I pass my FormData object to the send() method to send the data.
In this way, this will create an upload request with the multipart header and all this asynchronously.
Example of HTTP request:
One of the listener allows me to track the advanced upload of the file: xhr.upload.addEventListener("progress", onUploadProgress, false);
A ProgressEvent object passed to the onUploadProgress callback function. It contains information about the progress of the file upload. In my example, I display percentage progress. But we can imagine a progress bar in CSS.
Small demo in GIF and full code here https://github.com/lepiaf/file-upload
We have seen together how to implement the upload of a file asynchronously with AJAX and Symfony. This method allows you to encode and send the file as a binary data stream. Unlike a base64 file encoding, it does not inflate the file's weight on the network. The representation of the file in base64 increases the weight of the file by ~33%. For a few kilobytes file this increase in weight is not significant, but with a file of several megabytes, this has a significant impact. In addition, the file is properly managed by the browser and the server. This makes the upload more efficient and allows the use of a file resource representation on the server-side ($_FILES on the PHP side).