Laravel 8 image Upload full crud with spatie mediaLibrary package

Hello Friend !

in this tutorial you will see how to upload image with spatie mediaLibrary package.

you will also learn how to upload image,image edit,image delete.today you will see all in one place

I’m pretty sure many of you may have found yourself gotten into the situation where you do not edit,

or delete image with post

Laravel image Upload full crud with spatie mediaLibrary package


  • Step 1: Set Up Laravel Project
  • Step 2: Set Up Database Details in ENV
  • Step 3: Create Model and Migration
  • Step 4: Install laravel-medialibrary
  • Step 5: Set Up laravel-medialibrary
  • Step 6: Perform Crud Operations


Set Up Laravel Project

Installing a fresh new laravel application, so head over to the terminal, type the command, and create a new laravel app.


composer create-project --prefer-dist laravel/laravel laravel_image_crud

Now, You have to move to the project folder:


cd laravel_image_crud

Set Up Database Details in ENV

Now, you have to connect the laravel app to the database, hence open the .env configuration file and add the database credentials as suggested below.

.env


DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=database_name
DB_USERNAME=database_user_name
DB_PASSWORD=database_password

Create Model and Migration

In the terminal screen, type the recommended command and execute it to generate model and migration files.


php artisan make:model Image -m

You need to add the $fillable array and add the table values  app/Models/Image.php file.


<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia\HasMediaTrait;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;

class Image extends Model implements HasMedia
{
    use HasFactory, InteractsWithMedia;

    protected $fillable = [
        'name'
    ];
}

Now , add name in migration file


<?php

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

class CreateImagesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('images', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });
    }

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

Install laravel-medialibrary

in this project we are use 9.0.0 you can use older version if you like


composer require "spatie/laravel-medialibrary:^9.0.0"

 Set Up laravel-medialibrary

Now, You need to publish the migration to create the media table:


php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="migrations"

Now,we to migrate


php artisan migrate


Migration table created successfully.
Migrating: 2021_05_18_105041_create_images_table
Migrated2021_05_18_105041_create_images_table (21.92ms)
Migrating: 2021_05_18_112243_create_media_table
Migrated2021_05_18_112243_create_media_table (45.90ms)

you can see we got new table meadia database/migrations/create_media_table.php file.


<?php

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

class CreateMediaTable extends Migration
{
    public function up()
    {
        Schema::create('media', function (Blueprint $table) {
            $table->bigIncrements('id');

            $table->morphs('model');
            $table->uuid('uuid')->nullable()->unique();
            $table->string('collection_name');
            $table->string('name');
            $table->string('file_name');
            $table->string('mime_type')->nullable();
            $table->string('disk');
            $table->string('conversions_disk')->nullable();
            $table->unsignedBigInteger('size');
            $table->json('manipulations');
            $table->json('custom_properties');
            $table->json('generated_conversions');
            $table->json('responsive_images');
            $table->unsignedInteger('order_column')->nullable();

            $table->nullableTimestamps();
        });
    }
}

Set Up laravel-medialibrary

Now, you need to add few class laravel-medialibrary (HasMediaTrait , HasMedia, InteractsWithMedia)


<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia\HasMediaTrait;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;

class Image extends Model implements HasMedia
{
    use HasFactory, InteractsWithMedia;

    protected $fillable = [
        'name'
    ];
}

Now , you need to link storage, so type the command in the terminal and run the command.


php artisan storage:link                        

Notice: we need to set url path like 8000, or your current server


APP_URL=http://localhost
to
APP_URL=http://localhost:8000

in production you need to your Domain otherwise you are not seen image


Perform Crud Operations

Next, step to generate Controller and routes , so type the command in the terminal and run the command.


php artisan make:controller ImageController -r

Create routes

we are using resource route for save time and much shorter code


<?php

use App\Http\Controllers\ImageController;
use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| 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('/', function () {
    return view('welcome');
});

Route::resource('images', ImageController::class);

let implements code


<?php

namespace App\Http\Controllers;

use App\Models\Image;
use Illuminate\Http\Request;

class ImageController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $images = Image::all();

        return view('images.index', compact('images'));
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        return view('images.create');
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $this->validate($request, [
            'name' => 'required'
        ]);

        $image = Image::create([
            'name' => $request->name
        ]);

        if ($image) {
            if ($request->hasFile('image')) {
                $image->addMediaFromRequest('image')->toMediaCollection('images');
            }
        }

        session()->flash('success', 'Image create successfully');

        return redirect()->route('images.index');
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        $image = Image::find($id);

        return view('images.edit', compact('image'));
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        $this->validate($request, [
            'name' => 'required'
        ]);

        $image = Image::find($id);
        $image->name = $request->name;
        $image->save();

        if ($image) {
            if ($request->hasFile('image')) {
                $image->clearMediaCollection('images');
                $image->addMediaFromRequest('image')->toMediaCollection('images');
            }
        }

        session()->flash('success', 'Image Update successfully');

        return redirect()->route('images.index');
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        $image = Image::find($id);
        $image->delete();

        session()->flash('success', 'Image Delete successfully');

        return redirect()->route('images.index');
    }
}

On Image Store you can see we are store image toMediaCollection to save file


if ($image) {
    if ($request->hasFile('image')) {
        $image->addMediaFromRequest('image')->toMediaCollection('images');
    }
}

On Update Image you can see we are clear old image using clearMediaCollection first then store new image


if ($image) {
    if ($request->hasFile('image')) {
        $image->clearMediaCollection('images');
        $image->addMediaFromRequest('image')->toMediaCollection('images');
      }
} 

Now,let see blade file view/images/index.blade.php


<!DOCTYPE html>
<html lang="en">

    <head>
        <title>Laravel image Upload full crud with spatie mediaLibrary package</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    </head>

    <body>

        <div class="container mt-5">
            <div class="row">
                @if ($message = Session::get('success'))
                <div class="alert alert-success alert-dismissible" role="alert">
                    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                    </button>
                    {{ $message }}
                </div>
                @endif
                <div class="col-md-12">
                    <h2>Laravel image Upload full crud with spatie mediaLibrary package</h2>
                    <div class="card">
                        <div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
                            <a href="{{ route('images.create') }}" class="btn btn-success">Create</a>
                            <h6 class="m-0 font-weight-bold text-primary">Image List</h6>
                        </div>
                    </div>
                    <table class="table">
                        <thead>
                            <tr>
                                <th>#</th>
                                <th>Name</th>
                                <th>Image</th>
                                <th>Edit</th>
                                <th>Delete</th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach ($images as $image)
                            <tr>
                                <td>{{ $image->id }}</td>
                                <td>{{ $image->name }}</td>
                                <td><img src="{{ $image->getFirstMediaUrl('images') }}" alt="no image" width="100" height="100"></td>
                                <td>
                                    <a class="btn btn-xs btn-primary" href="{{ route('images.edit',$image->id) }}">
                                        Edit
                                    </a>
                                </td>
                                <td>
                                    <form action="{{ route('images.destroy',$image->id) }}" method="POST" onsubmit="return confirm('{{ trans('are You Sure ? ') }}');"
                                        style="display: inline-block;">
                                        <input type="hidden" name="_method" value="DELETE">
                                        <input type="hidden" name="_token" value="{{ csrf_token() }}">
                                        <input type="submit" class="btn btn-xs btn-danger" value="Delete">
                                    </form>
                                </td>
                            </tr>
                            @endforeach
                        </tbody>
                    </table>
                </div>
            </div>

            
        </div>

    </body>

</html>


view/images/index.blade.php


Now,let see blade file view/images/create.blade.php


<!DOCTYPE html>
<html lang="en">

    <head>
        <title>Laravel image Upload full crud with spatie mediaLibrary package</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    </head>

    <body>

        <div class="container mt-5">
            <div class="row">
                <div class="col-md-12">
                    <h2>Create</h2>
                    <div class="card">
                        <div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
                            <a href="{{ route('images.create') }}" class="btn btn-success">Create</a>
                            <h6 class="m-0 font-weight-bold text-primary">Create Image</h6>
                        </div>
                    </div>
                </div>
            </div>

            <div class="card-body">
                <form action="{{ route("images.store") }}" method="POST" enctype="multipart/form-data">
                    @csrf

                    <div class="form-group">
                        <label for="Name">Name</label>
                        <input type="text" name="name" class="form-control" placeholder="name">
                        @if($errors->has('name'))
                        <strong class="text-danger">{{ $errors->first('name') }}</strong>
                        @endif
                    </div>

                    <div class="form-group">
                        <div class="mb-3">
                            <label>image file</label>
                            <input type="file" name="image" class="form-control">
                            @if($errors->has('image'))
                            <strong class="text-danger">{{ $errors->first('image') }}</strong>
                            @endif
                        </div>
                    </div>

                    <button type="submit" class="btn btn-primary">Submit</button>
                </form>
            </div>

        </div>

    </body>

</html>


view/images/create.blade.php

Now,let see blade file view/images/edit.blade.php


<!DOCTYPE html>
<html lang="en">

    <head>
        <title>Laravel image Upload full crud with spatie mediaLibrary package</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    </head>

    <body>

        <div class="container mt-5">
            <div class="row">
                <div class="col-md-12">
                    <h2>Edit</h2>
                    <div class="card">
                        <div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
                            <a href="{{ route('images.create') }}" class="btn btn-success">Create</a>
                            <h6 class="m-0 font-weight-bold text-primary">Edit Image</h6>
                        </div>
                    </div>
                </div>
            </div>

            <div class="card-body">
                <form action="{{ route("images.update",$image->id) }}" method="POST" enctype="multipart/form-data">
                    @csrf
                    @method('put')
                    <div class="form-group">
                        <label for="Name">Name</label>
                        <input type="text" name="name" class="form-control" placeholder="name"
                        value="{{ old('name',$image->name )}}">
                        @if($errors->has('name'))
                        <strong class="text-danger">{{ $errors->first('name') }}</strong>
                        @endif
                    </div>

                    <div class="form-group">
                        <div class="mb-3">
                            <label>image file</label>
                            <input type="file" name="image" class="form-control">
                            @if($errors->has('image'))
                            <strong class="text-danger">{{ $errors->first('image') }}</strong>
                            @endif
                            <img src="{{ $image->getFirstMediaUrl('images') }}" alt="no image" width="100" height="100">
                        </div>
                    </div>

                    <button type="submit" class="btn btn-primary">Submit</button>
                </form>
            </div>

        </div>

    </body>

</html>



view/images/edit.blade.php