Image upload system in Laravel and Vue.js

Image upload system in Laravel and Vue.js

The combination of Laravel 9 and Vue.js 3 provides a powerful platform for building modern web applications. One of the most common requirements for web apps is the ability to upload images. In this article, we will explain the steps necessary to upload an image from a Vue form Laravel storage.

Note: this process relies on Inertia.js. If your project doesn't use Inertia, you'll need to make several changes regarding form submission and data transmission.

For simplicity, we won't be going over creating a project, but you can check out our article about starting a Laravel & Vue.js project Here.

  1. Create the Vue Form

  2. Set up Laravel Routing and Controller

  3. Displaying the image in Vue.js.

  4. Deleting the image (optional).

Create the Vue.js Form

In Vue, we will use the Inertia.js useForm form helper to handle the file upload. create a new Vue component that will contain the file upload form and add the following code:

<template>
    <form @submit.prevent="submit">
       <input type="file" name="image" id="image"
            @input="form.imgurl = $event.target.files[0]" />
        <button type="submit">Upload</button>
    </form>
</template>

In the component's script tag, we'll need to import the useForm function from @inertiajs/inertia-vue3.

<script>
import { useForm } from "@inertiajs/inertia-vue3";
const form = useForm({
    imgurl: "",
});
methods: {
    submit() {
       form.post(route("upload"), {
             forceFormData: true,
             onSuccess: () => {
             form.reset(
                "imgurl",
             );
             let file = document.getElementById("image");
             file.value = null;
           },
       });
    }
}
</script>

In this code, the submit method makes a POST request to the /upload route with the uploaded file. With our file being sent, let's see how to store it.

Set up Laravel Routing and Controller

Before We get into the Laravel Code, we need to set a symbolic link in our storage directory using the following command:

 php artisan storage:link

In Laravel, we need to set up a route and a controller that will handle the file upload. To create a new route, open the routes/web.php file and add the following code:

// Web.php
use App\Http\Controllers\FileUploadController;
Route::post('/upload', [FileUploadController::class, 'store']);

Next, create the controller by running the following command:

$ php artisan make:controller FileUploadController

Open the newly created FileUploadController and add the following code to the store method:

// FileUploadController.php 
use Illuminate\Http\Request;

class FileUploadController extends Controller{
    public function store(Request $request){
        $request->validate([
         'imgurl' =>'required|image|mimes:jpg,png,jpeg,gif|max:2048',
        ]);
        $image_path = $request->file('imgurl')->store('images','public');
    }
}

This process verifies if the image meets the specified conditions, and if it does, it creates a new images directory within the storage/app/public folder located in the root directory of our application. The image is then saved in this newly created directory and a file path is returned, which we store in the $image_path variable.

To utilize the image in the future, we need to save its path in our database.

// FileUploadController.php 
use App\Models\Images;
use Illuminate\Http\Request;

class FileUploadController extends Controller{
    public function store(Request $request){
        $request->validate([
         'imgurl' =>'required|image|mimes:jpg,png,jpeg,gif|max:2048',
        ]);
        $image_path = $request->file('imgurl')->store('images','public');
        $record = new Images([
            'imgurl' => asset('storage/'.$image_path),
        ]);
        sleep(1);
        $record->save();
        return Redirect::route('gallery');
    }
}

In this example, the Image model serves as a placeholder that should be substituted with your own implementation and includes a fillable field of imgurl.

Displaying the image in Vue.js.

Now, there are several ways to fetch the image path from the database. Feel free to use whichever way fits your needs as long as the data is made available in the Vue component. For simplicity, we will use a method that fetches all Images and renders a Gallery page.

use Inertia\Inertia;
class FileUploadController extends Controller{
    public function index(){
        $images = Images::->get();
        return Inertia::render('Gallery', ['images' => $images]);
    }
}
// Web.php
use App\Http\Controllers\FileUploadController;
Route::get('/gallary', [FileUploadController::class, 'index'])
->name('gallery');

This renders the Gallery page and passes the data from the model as a prop that can be accessed within the page.

To display the images all that is left is to loop over the images object and render them in the img element

// Gallery.vue 
<script>
    export default{
        props:{
            images: Object;
        }
    }
</script>

<template>
    <div v-for="image in images" :key="image.id">
        <img :src="image.imgurl" />
    </div>
</tepmlate>

Deleting the image (optional)

Now that we stored and displayed the image, it is very common to want to delete it. This requires deleting the image from the storage folder and the record from the database.

In the gallery page, we need to send the Id of the image to be deleted to the backend.

// Gallery.vue 
<script>
import { Link } from "@inertiajs/inertia-vue3";
export default{
   props:{
      images: Object;
   }
}
</script>

<template>
    <div v-for="image in images" :key="image.id">
        <img :src="image.imgurl" />
        <Link :href="route('delete')" method="post" as="button" :data="{id :image.id}"> Delete image </Link>
    </div>
</tepmlate>

Next, setup the delete route and controller to handle the request

// Web.php
Route::post('/delete', [FileUploadController::class, 'destroy'])
->name('delete');
$id = $request->get('id');
$imgurl = Images::where('id', $id)->limit(1)->get('imgurl');
$imagename = substr($imgurl[0]['imgurl'], strpos($imgurl[0]['imgurl'], 'images/') + 7);
@unlink('storage/images/' . $imagename);
DB::table('images')->Where('id', $id)->delete();
return redirect('gallery')->with('success', 'Image Deleted');

We start by retrieving the value of the "id" query parameter from the incoming HTTP request using the $request->get method. The method then queries the images table to obtain the imgurl value of the image record with the same id value.

The image name is extracted from the imgurl value and the actual image file is deleted from the storage/images/ directory using the unlink function. Finally, the method deletes the image record from the images table and returns a redirect response to the gallery page.

Conclusion

With that, we have reached the end of this article discussing image upload in Laravel and Vue. If you have any further questions or need clarification, please don't hesitate to ask in the comments section. We hope this information was helpful and until next time.