Upload o carga de archivos en Laravel Inertia con Vue

Video thumbnail

El proceso de carga de archivos es fundamental en cualquier sistema hoy en día, poder subir imágenes para publicaciones, para un avatar, o documentos que formen parte de un ciclo en la aplicación, son procesos rutinarios hoy en día, por lo tanto, ahora conoceremos cómo crear un proceso de upload o carga de archivos empleando Laravel Inertia.

Vamos a conocer cómo funciona el upload o carga de archivos en Laravel Inertia; como puedes suponer, todo lo que tiene que ver con el backend en Laravel base, se mantiene exactamente igual, y es en el cliente, que tenemos los cambios para poder usar la integración de la carga de archivos desde Inertia.

El upload de archivos en la web (también conocido como carga de archivos) es una funcionalidad que permite cargar o enviar archivos desde su PC o equipo local en general al servidor web en donde se encuentra la aplicación de Laravel. 

Esta funcionalidad es crucial práticamente en cualquier aplicación web en la cual se requiere cargar archivos como imágenes, archivos de audio, documentos de texto, videos, etc. La carga de archivos se puede implementar de diversas formas, como utilizando formularios HTML viene siendo la más clásiica pero, tambien se puede usar peticiones HTTP ya sera directamente o mediante plugins que facilitan la implementación de esta funcionalidad, tales como Dropzone.js o OrugaUI.

Configurar Disco

Vamos a crear el disco donde se van a cargar las imágenes de las publicaciones, que serían en la carpeta public:

config/filesystems.php

'public_upload' => [
    'driver' => 'local',
    'root' => public_path(),
],

Controlador para el upload

Inicialmente, vamos a manejar la carga de archivos mediante formularios en Inertia, específicamente la carga de imágenes de las publicaciones, de manera independiente al formulario que ya tenemos para la edición; usaremos el de Save.vue colocando un condicional solamente para editar:

app/Http/Controllers/Dashboard/PostController.php

public function edit(Post $post)
{
    $categories = Category::get();
    return inertia("Dashboard/Post/Edit", compact('post', 'categories'));
}

El controlador, para la carga de imágenes es lo normal, aplicar validaciones por el mime y que sea una imagen:

$request->validate(
   [
     'image' => 'required|mimes:jpg,jpeg,png,gif|max:10240'
   ]
);

Eliminar la imagen anterior (en caso de que exista):

Storage::disk("public_upload")->delete("image/post/".$post->image);

Generar un nombre aleatorio de la imagen:

time()."." .$request['image']->extension();

Mover a la carpeta public:

$request->image->move(public_path("image/post"),$filename);

Y actualizar el post:

$post->update($data);

Finalmente, tenemos:

app/Http/Controllers/Dashboard/PostController.php

***
use Illuminate\Support\Facades\Storage;
***
public function upload(Request $request, Post $post)
{
    $request->validate(
        [
            'image' => 'required|mimes:jpg,jpeg,png,gif|max:10240'
        ]
    );
    Storage::disk("public_upload")->delete("image/post/" . $post->image);
    $data['image'] = $filename = time() . "." . $request['image']->extension();
    $request->image->move(public_path("image/post"), $filename);
    $post->update($data);
    return to_route('post.index')->with('message', "Upload image to post successfully");
}

Creamos la ruta:

routes/web.php

Route::group(['middleware' => [
    'auth:sanctum',
    'prefix' => 'dashboard',
    config('jetstream.auth_session'),
    'verified',
]], function () {
    Route::resource('/category', App\Http\Controllers\Dashboard\CategoryController::class);
    Route::resource('/post', App\Http\Controllers\Dashboard\PostController::class);
    Route::post('/post/upload/{post}', [App\Http\Controllers\Dashboard\PostController::class,'upload'])->name('post.upload');
});

Formulario en Vue para la carga

En el formulario de editar, definimos un prop para la imagen:

 const form = useForm({
      // ***
      category_id: props.post.category_id,
      image: "",
    });

Y ahora, vamos a colocar un bloque adicional, para manejar la carga de archivos, como se comentó antes, la carga de la imagen, se realizará de manera independiente del formulario de actualización:

resources/js/Pages/Dashboard/Post/Save.vue

  <div v-if="post.id != ''">
            <div class="container">
                <div class="card">
                    <div class="card-body">
                        <div class="grid grid-cols-2 gap-2">
                            <div class="col-span-6">
                                <InputLabel value="Image" />
                                <TextInput type="file" @input="form.image = $event.target.files[0]" />
                                <InputError :message="errors.image" class="mt-2" />

                                <PrimaryButton @click="upload">Upload</PrimaryButton>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

    </AppLayout>
***
setup(props) {
    const form = useForm({
      // ***
      image: "",
    });

    function submit() {
      router.put(route("post.update", form.id), form);
    }

    function upload() {
      router.post(route("post.upload", form.id), form);
    }

    return { form, submit, upload };
  },

El código anterior, es sencillo, un campo de tipo file con su botón, que llama a una función llamada upload() en la cual enviamos el formulario, tal cual hacemos cuando se actualiza un registro; es importante notar que, para usar la carga de archivos, debe ser una petición de tipo POST; si quieres usar la carga de archivos en otro tipo de peticiones como DELETE, PATCH o PUT, debes de usar la petición de tipo POST y especificar el método en cuestión (esto lo veremos más adelante):

router.post(route(***), {
    _method: "put",
    // tus datos
},

Con esto, tendremos la carga de archivos completamente funcional.

Drag and Drop en Vue

Video thumbnail

La siguiente operación que vamos a aplicar es poder ordenar los todos es decir mediante el drag and poder reordenar para que tengan valga la redundancia otro orden para esto vamos a emplear el siguiente plugin hay más pero este no funciona bastante bien que es del agente o es una variante mejor dicho de sortable js que es un plugin bastante famoso para javascript y en este caso este viene siendo como que el port para Vue viene siendo este simplemente escribimos Drag and Drop next en Vue y sería aquí la siguiente página:

https://github.com/SortableJS/vue.draggable.next

Importante la que dice next al menos a la fecha tienes que chequear eso es para la de Vue 3 tal cual indica por acá la de Vue 2 y un sería esta que tenemos aquí al menos a la fecha se mantiene así y como te indicaba es de la agente de sort js aquí le puedes dar un ojo al plugin en caso de que no lo conozcas que es solamente para javascript bueno por aquí tenemos la instalación y ahorita ya vamos a ver su uso copiamos el Comando e instalamos:

$ npm i -S vuedraggable@next

Y a diferencia de otros plugins, no hay necesidad de configurarlo en la instancia principal de Vue; basta con importarlo como un componente cualquiera:

<script>
import draggable from "vuedraggable";

export default {
 components: {
   draggable,
 },
}
</script>

Y usarlo; para usarlo, existen varias configuraciones y cuyo detalle lo puedes ver en la documentación oficial, pero, el uso básico, que consiste en crear una lista que se pueda reordenar via Drag and Drop, tenemos:

<draggable v-model="myArray">
 <template #item="{ element }">
   <div>
     {{ element }}
   </div>
 </template>
</draggable>
***
data() {
 return {
   myArray: ["Test", "Test 2", "Test 3", "Test 4"],
 };
},

Mediante el componente draggable, indicamos el v-model indicamos la propiedad, que debe ser un array, ya sea de String, como en el ejemplo anterior, o de objetos; no hay necesidad de emplear un v-for para iterar los datos, en su lugar, podemos usar el:

#item="{ element }"

El siguiente paso, la navegación SPA entre páginas mediante Inertia Link.

Acepto recibir anuncios de interes sobre este Blog.

Veremos las el proceso de upload o carga de archivos en Laravel Inertia, que incluye una implementación que muestra como implementar el upload por Drag And Drop.

| 👤 Andrés Cruz

🇺🇸 In english