Cómo subir varias imágenes en Laravel usando Dropzone

Aprende a subir múltiples imágenes en Laravel con solo arrastrar y soltar (drag and drop), usando Dropzone.

Dropzone infografía

Subir imágenes usando drag and drop

En este tutorial aprenderás a programar lo siguiente:

Dropzone funcionamiento

Una zona en la que tus usuarios podrán arrastrar y soltar imágenes.

De hecho, ellos podrán ver una miniatura (thumbnail) de cada imagen que están subiendo, y una barra de progreso por cada una de ellas.

¿Y si simplemente quiero seleccionar y subir varias imágenes?

También se puede.

Con dropzone puedes dar un clic al área correspondiente, y podrás seleccionar las imágenes desde tus archivos.

Cómo usar Dropzone en nuestro proyecto

Dropzone.js es la librería Javascript que vamos a usar para conseguir implementar el área de "drag & drop".

Con la intención que todo el proceso te parezca más claro, he dividido el tutorial en 4 simples pasos:

  1. Añadir dropzone a nuestro proyecto.
  2. Configurar nuestro formulario para la subida de imágenes.
  3. Procesar las peticiones en el servidor.
  4. Verificar que todo funcione (y sorprenderse de lo sencillo que es).

Paso 1: Añadir dropzone a nuestro proyecto

Para esto tienes 2 opciones:

Si elegiste la primera opción tendrás algo como:

<script src="/js/dropzone.js"></script>

Pero si elegiste la segunda opción:

<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/4.3.0/min/dropzone.min.js"></script>

Muy bien:

Ya tenemos los archivos JavaScript para que dropzone funcione.

Ahora solo nos falta añadir los estilos.

La CDN también nos proporciona una forma de incluir el CSS correspondiente:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/4.3.0/min/dropzone.min.css">

Paso 2: Configurar nuestro formulario

Para agilizar este paso vamos a partir del ejemplo que aparece en la documentación oficial.

Creamos nuestro formulario:

<form action="/file-upload"
      class="dropzone"
      id="my-awesome-dropzone">
</form>

E inicializamos dropzone usando JavaScript de esta manera:

Dropzone.options.myAwesomeDropzone = {
    paramName: "file", // Las imágenes se van a usar bajo este nombre de parámetro
    maxFilesize: 2 // Tamaño máximo en MB
};

En este ejemplo, myAwesomeDropzone es el id de nuestro formulario (usando notación camelCase).

Y así es como tenemos nuestro dropzone ya configurado en el lado del cliente.

Sin embargo, hace falta configurar nuestro servidor (backend) para que esté listo para recibir estas imágenes y guardarlas.

Paso 3: Procesar las peticiones en nuestro controlador

¿Qué es lo que tenemos que hacer en este punto?

  • Guardar la imagen en una carpeta de nuestro proyecto Laravel.
  • Guardar un registro en nuestra base de datos, con el nombre de la imagen, para acceder a ella posteriormente.

El código a usar para este propósito va a depender mucho del proyecto que estés desarrollando:

  • Podrías estar trabajando en un galería para cada uno de tus usuarios.
  • Podrías tener muchas galerías por cada usuario, o incluso, tener galerías compartidas.

Tus requerimientos van a influir en el modelado de las tablas que vas a necesitar.

A modo de ejemplo, vamos a hacer lo siguiente:

  • Cada usuario tendrá una lista de proyectos.
  • Por cada proyecto un usuario podrá subir imágenes (ninguna, una o muchas).

En este caso particular, tenemos 3 modelos:

  • User (con su correspondiente migración users)
  • Project (con su correspondiente migración projects)
  • ProjectImage (con su correspondiente migración project_images)

Para este ejemplo cada proyecto sería equivalente a una galería de imágenes.

Pero lo cierto es que un proyecto puede tener más muchos datos, además de las imágenes.

Repito: todo depende de tus requerimientos específicos.

Nuestro modelo y migración para las imágenes los podemos crear así:

php artisan make:model ProjectImage -m

Entonces en nuestra migración podemos tener:

Schema::create('project_images', function (Blueprint $table) {
    $table->increments('id');

    $table->integer('project_id')->unsigned();
    $table->foreign('project_id')->references('id')->on('projects');

    $table->integer('user_id')->unsigned();
    $table->foreign('user_id')->references('id')->on('users');

    $table->string('name');
    $table->string('description');
    $table->string('file_name');

    $table->timestamps();
});
  • Tenemos una clave foránea, para saber a qué proyecto pertence la imagen.
  • Y otra clave foránea para saber qué usuario subió la imagen.
  • Puedes tener más datos, tantos como desees, pero nunca olvides de tener un campo para guardar el nombre de la imagen.

Todo esto lo puse para darte una idea más clara del ejemplo que estamos viendo.

Ahora sí entremos en materia.


El atributo action del formulario es importantísimo, porque allí se define la ruta a la que se harán las peticiones para subir las imágenes.

En el código de ejemplo, tiene el valor de /file-upload.

Aquí puedes usar la ruta que creas correspondiente.

Para este ejemplo usaremos /proyecto/{id}/imagenes.

De tal forma que en el parámetro de ruta id indicaremos el proyecto para el que se subirán las imágenes.

<form action="{{ asset('/proyecto/'.$project->id.'/imagenes') }}"
    class="dropzone" id="my-awesome-dropzone">
      {{ csrf_field() }}
</form>

No olvidar el CSRF Token. Laravel lo necesita porque se trata de una petición POST.

Y ya está. Ya lo tenemos.

Esta pequeña ruta será procesada por nuestro controlador cuando se trate de una petición POST.

Route::get('/proyecto/{id}/imagenes', 'ProjectImageController@index');
Route::post('/proyecto/{id}/imagenes', 'ProjectImageController@upload');

Así, en ProjectImageController tenemos:

public function index($id)
{
    $project = Project::find($id);
    return view('projects.images.index')->with(compact('project'));
}

public function upload($id, Request $request)
{
    //
}

El método upload es el que hará la magia.

Allí tenemos el $id del proyecto para el que se está subiendo la imagen.

Y un objeto $request con información de la imagen subida.

Por lo tanto:

public function upload($id, Request $request)
{
    $file = $request->file('file');
    $path = public_path() . '/images/projects';
    $fileName = uniqid() . $file->getClientOriginalName();

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

    $projectImage = new ProjectImage();
    $projectImage->project_id = $id;
    $projectImage->user_id = auth()->user()->id;
    $projectImage->file_name = $fileName;
    $projectImage->save();
}

Con esto ya debería funcionar todo. Pero, de todas formas ...

Repasemos línea por línea lo que hace el método upload:

  • Obtiene la información del archivo que se ha subido en un objeto llamado $file.
  • Define una variable $path con la ruta donde queremos guardar nuestras imágenes.
  • Define una variable $fileName con el nombre que se usará para guardar la imagen. Aquí se usa uniqid() para asegurarnos de que el nombre no se repita y ninguna imagen se termine sobreescribiendo.
  • Guardamos la imagen usando move (le indicamos dónde guardar y con qué nombre).
  • Por último creamos en nuestra base de datos un registro con información de la imagen que se acaba de guardar. Este registro nos permitirá mostrar la imagen en nuestra galería.

Conclusión

Laravel y PHP nos facilitan la tarea de subir imágenes.

Como puedes ver en el último snippet de código, lo podemos hacer con muy pocas líneas.

Por otro lado, Dropzone nos permite subir imágenes con una interfaz amigable para el usuario.

Y todo esto se puede configurar rápidamente.

Tal vez el tutorial ha sido un poco extenso por entrar en detalles. Pero si sigues los pasos, verás que realmente es fácil.

Disculpa que vaya por allí con tantos rodeos, pero quiero que sea útil incluso para quienes empiezan a usar Laravel.

Gracias por tu visita, y recuerda compartir si te ha sido de ayuda.

Extra: reducir el tamaño de las imágenes antes de guardar

Si te interesa hacer alguna operación sobre las imágenes que suben tus usuarios, como:

  • Disminuir el tamaño
  • Rotar X grados
  • Cortar la imagen
  • O aplicar algún efecto sobre la misma

Te recomiendo ver el siguiente video:

Extra 2: capturar la respuesta del servidor

Generalmente tenemos una sección donde están todas las imágenes subidas, y una segunda sección con el dropzone.

Los usuarios pueden arrastrar y soltar sus imágenes sobre el área donde aplicamos el dropzone.

Estas imágenes se subirán al instante. Pero, no se mostrarán en el listado de imágenes ya subidas.

Si queremos mostrarlas de ese lado, es necesario usar el evento success de dropzone, para capturar la respuesta que se recibe desde el controlador, luego de una subida exitosa.

Entonces, en nuestro controlador devolvemos la información de la imagen que se acaba de subir, añadiendo una línea al final del método upload:

public function upload($id, Request $request)
{
    $file = $request->file('file');
    $path = public_path() . '/images/projects';
    $fileName = uniqid() . $file->getClientOriginalName();

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

    $projectImage = new ProjectImage();
    $projectImage->project_id = $id;
    $projectImage->user_id = auth()->user()->id;
    $projectImage->file_name = $fileName;
    $projectImage->save();

    return $projectImage;
}

Y en nuestro Javascript capturamos esa respuesta:

Dropzone.options.myAwesomeDropzone = {
    paramName: "file", // The name that will be used to transfer the file
    maxFilesize: 2, // MB
    success: function (file, response) {
        console.log(response);
    }
};

Así, obtenemos en la consola algo como lo siguiente:

Respuesta en la consola

Aquí lo que nos interesa es principalmente el atributo file_name, ya que con este dato podemos renderizar la imagen que se acaba subir.

Pero he devuelto toda la información para que veas que se puede capturar la respuesta del servidor.

# laravel

Logo de Programación y más

Comparte este post si te fue de ayuda 🙂.

Regístrate

Accede a todos los cursos, y resuelve todas tus dudas.

Cursos Recomendados

Imagen para el curso Aprende Laravel

Aprende Laravel

Aprende Laravel desde cero y desarrolla aplicaciones web reales, en tiempo récord, de la mano de Laravel.

Iniciar curso
Imagen para el curso Laravel Upgrade

Laravel Upgrade

Actualiza tus proyectos desde cualquier versión hasta la última versión estable de Laravel.

Iniciar curso
Imagen para el curso Laravel y Vue

Laravel y Vue

Desarrollemos un Messenger! Aprende sobre Channels, Queues, Vuex, JWT, Sesiones, BootstrapVue y mucho más.

Iniciar curso

Espera un momento ...

¿Te gustaría llevar mi curso de Laravel, gratis?

Sólo debes ingresar tus datos: