Laravel File Manager using Spatie Media Library

Hello Artisans, today we'll discuss how to integrate Spatie FIle Manager using spatie new media Library package. This package is useful to keep track of each and every piece of information we may need for an uploaded file/image. So, no more talk, let's see how we can integrate spatie file manager in our Laravel Application.

Note: Tested on Laravel 9.11

Table of Contents

  1. Install and configure Spatie Media Library
  2. Create and Setup Controller
  3. Setup Model
  4. Define Routes
  5. Create and Setup blade File
  6. Output

Install and configure Spatie Media Library

To install the spatie media library, fire the below command in your terminal

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

After successfully completing the installation, run the below command to publish the migration

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

After publishing the migrations, migrate the tables with the following command.

php artisan migrate

That's all you need to do to install the spatie media library package.

Create and Setup Controller

First of all, create a controller so that we can write our logics or query to show the result. So, fire the below commands in the terminal.

php artisan make:controller UserController -r

It'll create a controller under app\Http\Controllers called UserController.php. Open the file and replace with below codes.

app/Http/Controllers/UserController.php
<?php

namespace App\Http\Controllers;

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

class UserController extends Controller
{

    public function index(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application
    {
        $data = [
            'users' => User::latest()->get()
        ];

        return view('users',$data);
    }

    public function create(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application
    {
        return view('create');
    }

    public function store(Request $request): \Illuminate\Http\RedirectResponse
    {
        $request->validate([
            'name'      => 'required',
            'email'     => 'required|email',
            'password'  => 'required|min:6',
            'image'     => 'required',
        ]);

        $request['password'] = bcrypt($request->password);

        $user = User::create($request->all());

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

        session()->flash('success','User Created Successfully');
        return redirect()->route('users.index');
    }
}

Setup Model

Now we need change the model a little bit in which we want to associate media with a model. The model must implement the following interface and trait:

class YourModel extends Model implements HasMedia
{
    use InteractsWithMedia;
}

So, in our case we want to associate media with our User.php model. So finally our model will be look like below.

app/Models/User.php
<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;

class User extends Authenticatable implements HasMedia
{
    use HasApiTokens, HasFactory, Notifiable,InteractsWithMedia;

    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    protected $hidden = [
        'password',
        'remember_token',
    ];

    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

Define Routes

Now we need to put the below routes in our web.php

routes/web.php
Route::resource('users',\App\Http\Controllers\UserController::class)->only('index','create','store');

Create and Setup blade File

Now we need to create a blade files for viewing the list of users and from where we'll create new user with image. So, create two files under resources\views named

  1. users.blade.php
  2. create.blade.php

Now open the files and replace with the following corresponding file codes.

resources/views/users.blade.php
<html>
<head>
    <title>Laravel Spatie Media Library Example - shouts.dev</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.0.1/css/bootstrap.min.css" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha512-SfTiTlX6kk+qitfevl/7LibUOeJWlt9rbyDn92a1DqWOw9vWG2MFoays0sgObmWazO5BQPiFucnnEAjpAB+/Sw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
    <style type="text/css" media="screen">
        body{
            background-color: #f7fcff;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-8 offset-2">
            <div class="card mt-5">
                <div class="card-header">
                    <div class="row">
                        <div class="col-lg-12">
                            @if(Session::has('success'))
                                <div class="alert alert-success">
                                    {{ Session::get('success') }}
                                    @php
                                        Session::forget('success');
                                    @endphp
                                </div>
                            @endif
                        </div>
                        <div class="col-md-11">
                            <h4>Laravel Spatie Media Library Example - shouts.dev</h4>
                        </div>
                        <div class="col-md-1 text-center">
                            <a href="{{ route('users.create') }}" class="btn btn-success"><i class="fa fa-plus py-1" aria-hidden="true"></i></a>
                        </div>
                    </div>
                </div>
                <div class="card-body">
                    <table class="table table-bordered">
                        <thead>
                        <tr>
                            <th>No</th>
                            <th width="25%">Image</th>
                            <th>Name</th>
                            <th>Email</th>
                        </tr>
                        </thead>
                        <tbody>
                        @foreach($users as $key => $user)
                            <tr>
                                <td>{{ ++$key }}</td>
                                <td><img src="{{ $user->getFirstMediaUrl('images', 'thumb')}}"  width="100%"></td>
                                <td>{{ $user->name }}</td>
                                <td>{{ $user->email }}</td>
                            </tr>
                        @endforeach
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>
resources/views/create.blade.php
<!DOCTYPE html>
<html>
<head>
    <title>Laravel Spatie Media Library Example - shouts.dev</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.0.1/css/bootstrap.min.css" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha512-SfTiTlX6kk+qitfevl/7LibUOeJWlt9rbyDn92a1DqWOw9vWG2MFoays0sgObmWazO5BQPiFucnnEAjpAB+/Sw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
    <style type="text/css" media="screen">
        body{
            background-color: #f7fcff;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-8 offset-2">
            <div class="card mt-5">
                <div class="card-header">
                    <div class="row">
                        <div class="col-md-11">
                            <h4>Laravel Spatie Media Library Example - shouts.dev</h4>
                        </div>
                        <div class="col-md-1 text-center">
                            <a href="{{ route('users.index') }}" class="btn btn-secondary text-white"><i class="fa fa-arrow-left" aria-hidden="true"></i></a>
                        </div>
                    </div>
                </div>
                <div class="card-body">
                    <form action="{{ route('users.store') }}" method="post" enctype="multipart/form-data">
                        @csrf
                        <div class="row">
                            <div class="col-md-12 mb-3">
                                <div class="form-group">
                                    <label for="name">Name:</label>
                                    <input type="text" id="name" name="name" class="form-control" placeholder="Enter Name">
                                    <span class="text-danger">{{ $errors->first('name') }}</span>
                                </div>
                            </div>
                            <div class="col-md-12 mb-3">
                                <div class="form-group">
                                    <label for="email">Email:</label>
                                    <input type="email" id="email" name="email" class="form-control" placeholder="Enter Email">
                                    <span class="text-danger">{{ $errors->first('email') }}</span>
                                </div>
                            </div>
                            <div class="col-md-12 mb-3">
                                <div class="form-group">
                                    <label for="password">Password:</label>
                                    <input type="password" id="password" name="password" class="form-control" placeholder="Enter Password">
                                    <span class="text-danger">{{ $errors->first('password') }}</span>
                                </div>
                            </div>
                            <div class="col-md-12 mb-3">
                                <label for="image">Image:</label>
                                <input type="file" id="image" name="image" class="form-control">
                                <span class="text-danger">{{ $errors->first('image') }}</span>
                            </div>
                        </div>

                        <div class="row">
                            <div class="col-md-12 mb-3 text-center">
                                <button class="btn btn-success btn-block">Submit</button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

Output

First of all note that we need to fire the below commands to see the images

php artisan storage:link

And after that we need to fix the our App URL in our .env file like below.

routes/web.php
APP_URL=http://localhost:8000

Or if you use any custom host/server then define that link.

And finally we're ready with our setup. It's time to check our output. Now go to http://127.0.0.1:8000/users, If everything goes well you'll find a below output.

File Manager using Spatie Media Library

That's it for today. Hope you'll enjoy this tutorial. You can also download this tutorial from GitHub. Thanks for reading.๐Ÿ™‚