Dropbox es un servicio de alojamiento de archivos multiplataforma en la nube, en este artículo vamos a trabajar en la integración del paquete llamado spatie/flysystem-dropbox que nos proporcionará algunos métodos para manejar la API de dicho servicio y asociarlo al File Storage de Laravel.

Requisitos

Antes de comenzar debemos tener en cuenta algunos requisitos y son los siguientes:

  • Versión de PHP igual o mayor a la 7.1.0.
  • Versión de Laravel igual o mayor a la 5.3.
  • Cuenta en Dropbox, (si no tienes puedes crearla asociándola a tu cuenta de Google o simplemente indicando todos los datos necesarios).

Crear nueva aplicación en Dropbox

Para comenzar debemos crear una nueva aplicación en Dropbox ingresando al siguiente enlace con la cuenta que usarás y así poder suministrar la información necesaria para nuestra nueva aplicación.

Seleccionamos la opción «Dropbox API», seguidamente la opción «App Folder» para que nuestra aplicación tenga su propia carpeta y no abarque todo el espacio de nuestra cuenta. Luego debemos indicar un nombre único de nuestra aplicación, para este tutorial usaré Stydebox, y al finalizar seremos redirigidos a la información de nuestra aplicación a algo parecido a:

Panel de usuario en Dropbox

En esta página podemos generar un Access Token el cual nos servirá para asociarlo a nuestra aplicación en Laravel más adelante, lo único que debemos hacer es pulsar sobre el botón Generate y recibiremos un hash el cual guardaremos.

Nueva instalación de Laravel

Para comenzar vamos a crear un nuevo proyecto con Laravel, ejecutando el siguiente comando de Composer en nuestra terminal:

composer create-project laravel/laravel stydebox

Configuración de nuestro proyecto

Para continuar vamos a crear un modelo llamado File con su respectiva migración y controlador ejecutando el siguiente comando dentro de la carpeta de nuestro proyecto:

php artisan make:model File -mc

Vamos a editar la migración generada y le colocaremos algunos campos que nos servirán para almacenar el nombre, tamaño, formato y URL pública de los archivos que subiremos a Dropbox:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateFilesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('files', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->integer('size');
            $table->string('extension');
            $table->string('public_url');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('files');
    }
}

En nuestro modelo File vamos a colocar la propiedad $guarded con un arreglo vacío para evitar algún tipo de problema con la asignación masiva y también agregaremos un getter, el cual nos devolverá el tamaño de nuestros archivos en Kilobytes:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class File extends Model
{
    protected $guarded = [];

    public function getSizeInKbAttribute()
    {
        return number_format($this->size / 1024, 1);
    }
}

Para terminar ejecutaremos las migraciones, pero antes recuerda asociar una base de datos a tu proyecto y colocar las credenciales de la base de datos necesarias en el archivo .env, una vez hecho podemos continuar ejecutando el comando:

php artisan migrate

Instalación & configuración del paquete

Vamos a indicarle a Composer que requerimos un nuevo paquete, para esto nos situamos en la carpeta de nuestro proyecto con nuestra terminal y ejecutamos:

composer require spatie/flysystem-dropbox

Una vez instalado el paquete en nuestro archivo config/filesystems.php vamos a agregar un nuevo driver llamado dropbox al arreglo disks :

'dropbox' => [
    'driver' => 'dropbox',
    'authorizationToken' => env('DROPBOX_TOKEN')
]

Como podemos notar hacemos referencia a una variable de entorno llamada DROPBOX_TOKEN, la cual aún no tenemos definida, para ello necesitamos colocarla con su respectivo valor en nuestro archivo .env:

DROPBOX_TOKEN=AQUI_HASH_GENERADO

El hash lo obtenemos en la página de información de la aplicación en Dropbox pulsando sobre el botón Generate

Una vez colocado, vamos a continuar creando un Service Provider llamado DropboxServiceProvider ya que necesitamos configurar este driver llamado dropbox, ejecutaremos el siguiente comando en nuestra terminal:

php artisan make:provider DropboxServiceProvider

Como siguiente paso vamos a registrar nuestro nuevo Service Provider en la aplicación y esto lo hacemos en config/app.php agregando la referencia a nuestra clase al final del arreglo providers de esta forma:

App\Providers\DropboxServiceProvider::class

Podemos proceder a editar la clase DropboxServiceProvider para indicarle la información necesaria de nuestro driver dropbox de esta forma:

<?php

namespace App\Providers;

use Storage;
use League\Flysystem\Filesystem;
use Illuminate\Support\ServiceProvider;
use Spatie\Dropbox\Client as DropboxClient;
use Spatie\FlysystemDropbox\DropboxAdapter;

class DropboxServiceProvider extends ServiceProvider
{
    /**
     * Perform post-registration booting of services.
     *
     * @return void
     */
    public function boot()
    {
        // Extendemos el Storage de Laravel agregando nuestro nuevo driver.
        Storage::extend('dropbox', function ($app, $config) { 
            $client = new DropboxClient(
                $config['authorizationToken'] // Hacemos referencia al hash
            );

            return new Filesystem(new DropboxAdapter($client)); 
        });
    }

    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

Con esto ya tenemos configurado nuestro driver dropbox con el File Storage de Laravel.

En Styde tenemos un tutorial básico de Cómo subir archivos con Laravel 5 , además en el Curso de novedades en Laravel 5.3 específicamente en la lección Almacenamiento de archivos en Laravel 5.3 con el método store se habla un poco sobre el File Storage.

Rutas necesarias para nuestro proyecto

Vamos a crear 4 rutas, las cuales se encargaran de listar todos los archivos, guardar, eliminar y descargar. Para esto nos dirigimos a nuestro archivo de rutas routes/web.php y tendríamos un resultado final como el siguiente:

<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', 'FileController@index')->name('files.index');

Route::post('/files', 'FileController@store')->name('files.store');

Route::delete('/files/{file}', 'FileController@destroy')->name('files.destroy');

Route::get('/files/{file}/download', 'FileController@download')->name('files.download');

Métodos necesarios en el controlador FileController

Nuestras rutas están haciendo referencia a 4 métodos de nuestro controlador ubicado en  app/Http/Controllers/FileController.php que se generó anteriormente junto con el modelo File y su migración. Este controlador tendrá el siguiente contenido, el cual está explicado en los comentarios del código:

<?php

namespace App\Http\Controllers;

use App\File;
use Spatie\Dropbox\Client;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class FileController extends Controller
{
    public function __construct()
    {
        // Necesitamos obtener una instancia de la clase Client la cual tiene algunos métodos
        // que serán necesarios.
        $this->dropbox = Storage::disk('dropbox')->getDriver()->getAdapter()->getClient();   
    }

    public function index()
    {
        // Obtenemos todos los registros de la tabla files
        // y retornamos la vista files con los datos.
        $files = File::orderBy('created_at', 'desc')->get();
        
        return view('files', compact('files'));
    }

    public function store(Request $request)
    {
        // Guardamos el archivo indicando el driver y el método putFileAs el cual recibe
        // el directorio donde será almacenado, el archivo y el nombre.
        // ¡No olvides validar todos estos datos antes de guardar el archivo!
        Storage::disk('dropbox')->putFileAs(
            '/', 
            $request->file('file'), 
            $request->file('file')->getClientOriginalName()
        );

        // Creamos el enlace publico en dropbox utilizando la propiedad dropbox
        // definida en el constructor de la clase y almacenamos la respuesta.
        $response = $this->dropbox->createSharedLinkWithSettings(
            $request->file('file')->getClientOriginalName(), 
            ["requested_visibility" => "public"]
        );

        // Creamos un nuevo registro en la tabla files con los datos de la respuesta.
        File::create([
            'name' => $response['name'],
            'extension' => $request->file('file')->getClientOriginalExtension(),
            'size' => $response['size'],
            'public_url' => $response['url']
        ]);
        
        // Retornamos un redirección hacía atras
        return back();
    }

    public function download(File $file)
    {
        // Retornamos una descarga especificando el driver dropbox
        // e indicándole al método download el nombre del archivo.
        return Storage::disk('dropbox')->download($file->name);
    }

    public function destroy(File $file)
    {
        // Eliminamos el archivo en dropbox llamando a la clase
        // instanciada en la propiedad dropbox.
        $this->dropbox->delete($file->name);
        // Eliminamos el registro de nuestra tabla.
        $file->delete();

        return back();
    }
}

Como se puede notar no se está agregando validación ni extrayendo la lógica a otras clases para no salirnos del contexto del tema ya que se trata de una demostración. Si deseas puedes hacerlo y dejarnos el resultado en los comentarios.

Para finalizar vamos a crear una nueva vista llamada files.blade.php la cual va a contener el listado de archivos y un pequeño formulario donde se podrán agregar nuevos, este es el contenido:

<table>
    <thead>
        <tr>
            <th>ID</th>
            <th>Nombre</th>
            <th>Tamaño</th>
            <th>Extensión</th>
            <th>Acciones</th>
        </tr>
    </thead>
    <tbody>
    @foreach ($files as $file)
        <tr>
            <td>{{ $file->id }}</td>
            <td>{{ $file->name }}</td>
            <td>{{ $file->sizeInKb }} KB</td>
            <td>{{ $file->extension }}</td>
            <td>
                <a href="{{ $file->public_url }}" target="_blank">
                    Enlace público
                </a>
                <a href="{{ route('files.download', $file) }}">
                    Descargar
                </a>
                <form action="{{ route('files.destroy', $file) }}" method="POST">
                    @csrf
                    @method('delete')
                    <button type="submit">Eliminar</button>
                </form>
            </td>
        </tr>
    @endforeach
    </tbody>
</table>

<form action="{{ route('files.store') }}" method="POST" enctype="multipart/form-data">
    @csrf
    <input type="file" name="file" required>    
    <button type="submit">Agregar nuevo archivo</button>
</form>

Como se puede notar agregamos 3 botones que nos permitirán: ver el enlace público, descargar el archivo o eliminarlo de nuestra tabla files y de Dropbox.

Este es el HTML básico que necesitas, sin embargo puedes ver la versión completa con sus clases de Bootstrap en nuestro repositorio en GitHub. Al finalizar tendremos un resultado como el siguiente si ingresamos a la dirección principal de nuestro proyecto:

Resultado final de nuestro ejercicioPara comprobar que todo está funcionando correctamente, puedes ingresar a la carpeta de la aplicación en Dropbox y ver que los archivos subidos están presentes. Para hacer esto, ingresa a https://www.dropbox.com/home, selecciona la carpeta Aplicaciones y luego la carpeta con el nombre de tu aplicación.

El código puedes obtenerlo en este repositorio y si encuentras algo qué mejorar puedes hacer un pull request. Con esto terminamos, te invito a que compartas este artículo en tus redes sociales y no olvides comentar las dudas que tengas o el resultado obtenido después de seguir este artículo.

Material Relacionado

Espero que te haya gustado este material. No olvides seguirnos en Twitter y suscribirte a nuestro boletín:

Suscríbete a nuestro boletín

Te enviaremos publicaciones con consejos útiles y múltiples recursos para que sigas aprendiendo.

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