dropzone-laravel-5

En un post anterior les hablaba sobre  Cómo subir archivos con Laravel 5 usando la clase Storage(), el día de hoy les enseñaré un ejemplo básico de cómo usar Dropzone, una librería en javascript que permite la subida de archivos con  drag and drop. 

Lo primero que debemos hacer es descargar la librería desde la página oficial (link al final del post), o desde este repositorio en Github:

https://github.com/enyo/dropzone

Una vez descargado busca dentro del directorio una carpeta llamada dist, y copia los archivos dropzone.css y dropzone.js dentro del directorio public de tu aplicación de Laravel.

Personalmente recomiendo ubicar cada archivo en la carpeta correspondiente js/dropzone.js, css/dropzone.css, y además dentro de public crea una nueva carpeta llamada uploads, allí será donde se almacenarán todos los archivos que vamos a enviar desde el formulario. Al final tendrás algo parecido a esto:

Para integrar el plugin se deben agregar los archivos css y js a la vista, esto se pude hacer incluyendo los enlaces directamente desde el archivo app.blade.php, pero, como no serán necesarios para todas las vistas prefiero agregarlos de la siguiente forma:

Ingresamos al archivo resources/views/app.blade.php que es la plantilla que trae por defecto Laravel 5 y de la cual extienden las demás vistas y, en lugar de agregar los enlaces, le indicamos que incluya dos nuevas secciones con:

<head>
	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>Laravel</title>

	<link href="{{ asset('/css/app.css') }}" rel="stylesheet">
        @yield('css')

esta sección «css» será para los estilos y al final del archivo agregamos esto para los scripts:

	<!-- Scripts -->
	<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
	<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/js/bootstrap.min.js"></script>
    
        @yield('scripts')

Si estás usando Laravel 5.1, ya no trae por defecto el archivo app.blade.php, pero lo podemos crear fácilmente en el directorio resources/views así:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Laravel</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
    <link rel="stylesheet" href="{{ asset('css/app.css') }}">
    @yield('css')

</head>
<body>
<nav class="navbar navbar-default">
    <div class="container-fluid">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1">
                <span class="sr-only">Toggle Navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="#">styde.net</a>
        </div>
    </div>
</nav>

@yield('content')

<!-- Scripts -->
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/js/bootstrap.min.js"></script>
@yield('scripts')
</body>
</html>

Bien, vamos crear ahora la vista del formulario con la cual subiremos los archivos a la aplicación, para ello creamos una nueva vista llamada form.blade.php

@extends('app')
@section('css')
    <link href="{{ asset('/css/dropzone.css') }}" rel="stylesheet">
@endsection
@section('content')
    <div class="container">
        <div class="row"    >
            <div class="panel panel-primary">
                <div class="panel-heading">
                    Dropzone
                </div>
                <div class="panel-body">
                    {!! Form::open(['route'=> 'file.store', 'method' => 'POST', 'files'=>'true', 'id' => 'my-dropzone' , 'class' => 'dropzone']) !!}
                    <div class="dz-message" style="height:200px;">
                        Drop your files here
                    </div>
                    <div class="dropzone-previews"></div>
                    <button type="submit" class="btn btn-success" id="submit">Save</button>
                    {!! Form::close() !!}
                </div>
            </div>
        </div>
    </div>
@endsection
@section('scripts')
    {!! Html::script('js/dropzone.js'); !!}
    <script>
        Dropzone.options.myDropzone = {
            autoProcessQueue: false,
            uploadMultiple: true,
            maxFilezise: 10,
            maxFiles: 2,
            
            init: function() {
                var submitBtn = document.querySelector("#submit");
                myDropzone = this;
                
                submitBtn.addEventListener("click", function(e){
                    e.preventDefault();
                    e.stopPropagation();
                    myDropzone.processQueue();
                });
                this.on("addedfile", function(file) {
                    alert("file uploaded");
                });
                
                this.on("complete", function(file) {
                    myDropzone.removeFile(file);
                });

                this.on("success", 
                    myDropzone.processQueue.bind(myDropzone)
                );
            }
        };
    </script>
@endsection

Para que el formulario funcione debes tener implementado en el proyecto los componentes Html y Form, si no sabes cómo puedes revisar Instalación del paquete Styde\Html.

La variable autoProcessQueue la dejamos en false para que la subida se haga manualmente con el botón submit, activamos la opción uploadMultiple para indicar que vamos a enviar varios archivos y definimos también el tamaño y la cantidad de archivos permitidos en la subida. Si lo deseas, en la configuración puedes indicar cuantos archivos se subirán en paralelo con parallelUploads, por defecto se suben de dos en dos.

Recuerda que todas estas validaciones son para el frontend, para una aplicación en producción es imprescindible realizar las validaciones igualmente en el backend.

Dropzone se encarga de manejar la subida de archivos al form con drag and drop, muestra una miniatura y ofrece información sobre el estatus del proceso, pero recuerda que se trata de javascript y todo esto ocurre de parte del cliente, ahora debemos crear la lógica para capturar los archivos en el submit y almacenarlos en el servidor.

Como puedes ver en la vista, el formulario apunta a la ruta file.store, la definimos de la siguiente forma para ahorrar un poco de tiempo:

Route::resource('file', 'FileController');

Con ello, estamos creando un recurso llamado file y lo asociamos a un controlador llamado FileController que podemos crear desde la consola usando artisan:

$ php artisan make:controller FileController

Si quieres ver las rutas disponibles con la creación del recurso file puedes ejecutar desde la consola

$ php artisan route:list

Vamos a editar la función store() del controlador FileController de esta forma :

public function store(Request $request)
	{
            $path = public_path().'/uploads/';
            $files = $request->file('file');
            foreach($files as $file){
                $fileName = $file->getClientOriginalName();
                $file->move($path, $fileName);
            }
	}

En esta función se define la ruta al directorio donde se subirán los archivos, en nuestro caso uploads, se recibe un array de los archivos enviados y luego se recorre este array para obtener el nombre original y moverlo al directorio final.

Debemos tambien editar la funcion index del controlador para que devuelva la vista del formulario:

public function index()
{
    return view('form');
}

Si ingresamos a la url ruta_de_tu_proyecto/file podremos ver el formulario:

Para agregar archivos basta con hacer click sobre el cuadro vacío, donde te saldrá un cuadro de dialogo o puedes arrastrar y soltar directamente.

En este punto los archivos están preparados para guardar pero no han sido almacenados en el servidor, para ello debes hacer click en el botón save.

Al finalizar la subida el formulario se limpia nuevamente para que puedas seguir subiendo nuevos archivos.

Para confirmar que todo ha salido bien puedes verificar el directorio uploads 

Epero que te haya gustado el post, recuerda compartir en tus redes sociales y como siempre no olvides dejar tus comentarios y sugerencias.

Lecturas recomendadas

Información adicional 

Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.

Lección anterior Creando menús con el componente Styde\Html Lección siguiente Traducciones con el componente Styde\Html