Laravel CRUD Operation with File Upload 

Welcome to the 11th chapter of Being an Artisanary. In show CRUD(create-read-edit-delete) operation with file upload. So if you already complete the previous chapters/sections, then you're good to go, if not my recommendation would be please complete the previous chapters. Because we'll use the same old repository.


Note: Tested on Laravel 10.0

Table of Contents

  1. Install Image Intervention for Image Processing
  2. Create and Setup a Repository
  3. Create and Setup Observer
  4. Create and Setup the Controller
  5. Setup Model and Migration
  6. Define Routes
  7. Create and Setup View
  8. Output

Install Image Intervention for Image Processing

Image intervention is one of the most used packages for image processing. For installing image intervention fire the below command in the terminal.

composer require intervention/image

And it'll be enough, no need to do anything.

Create and Setup a Repository

At first, we'll create a repository class called BlogRepository.php where we'll write our all database logic so that we can use the same query everywhere.

BlogRepository.php
<?php

namespace App\Repositories;

use App\Models\Blog;
use Illuminate\Support\Str;
use Intervention\Image\Facades\Image;

class BlogRepository
{
    public function all()
    {
        return Blog::latest()->paginate();
    }

    protected function createData($data)
    {
        if (array_key_exists('image', $data)) {
            $image = $data['image'];
            $image_name = Str::uuid() . '.' . $image->getClientOriginalExtension();

            $destinationPath = public_path('uploads/');

            if (!is_dir($destinationPath)) {
                mkdir($destinationPath, 0777, true);
            }
            Image::make($data['image'])->resize(50,null, function ($constraint) {
                $constraint->aspectRatio();
            })->save($destinationPath.$image_name);

            $data['image'] = 'uploads/'.$image_name;
        }

        return $data;
    }
    public function store($data)
    {
        return Blog::create($this->createData($data));
    }

    public function find($id)
    {
        return Blog::find($id);
    }

    public function update($id,$data)
    {
        $blog = $this->find($id);

        if (array_key_exists('image', $data) && $blog->image) {
            $image_path = public_path($blog->image);
            if (file_exists($image_path)) {
                unlink($image_path);
            }
        }
        return $blog->update($this->createData($data));
    }

    public function destroy($id)
    {
        return Blog::destroy($id);
    }
}

Create and Setup Observer

We'll already discussed what is Observer and why we use observer, so I'll not repeat here.

BlogObserver.php
<?php

namespace App\Observers;

use App\Models\Blog;
use Illuminate\Support\Str;

class BlogObserver
{
    public function creating(Blog $blog)
    {
        $blog->slug = Str::slug($blog->title);
    }
    public function created(Blog $blog): void
    {
        $blog->unique_id    = 'PR-'.$blog->id;
        $blog->save();
    }

    public function updating(Blog $blog): void
    {
        $blog->slug = Str::slug($blog->title);
    }
    public function updated(Blog $blog): void
    {
        //
    }

    public function deleted(Blog $blog): void
    {
        $image_path = public_path($blog->image);
        if (file_exists($image_path)) {
            unlink($image_path);
        }
    }

    public function restored(Blog $blog): void
    {
        //
    }

    public function forceDeleted(Blog $blog): void
    {
        //
    }
}

Create and Setup the Controller

Then, we'll create a controller called BlogController.php where we'll write our logic or insert the data. So, fire the below command in the terminal.

php artisan make:controller BlogController -r

It'll create a file under app\Http\Controllers called BlogController.php. Now open the file and replace it with the below codes.

BlogController.php
<?php

namespace App\Http\Controllers;

use App\Http\Requests\BlogRequest;
use App\Repositories\BlogRepository;

class BlogController extends Controller
{
    protected $blogRepository;

    public function __construct(BlogRepository $blogRepository)
    {
        $this->blogRepository = $blogRepository;
    }

    public function index(): \Illuminate\Contracts\View\Factory|\Illuminate\Foundation\Application|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application|\Illuminate\Http\RedirectResponse
    {
        try {
            $data = [
                'blogs' => $this->blogRepository->all()
            ];
            return view('backend.blogs.index', $data);
        } catch (\Exception $e) {
            return back()->with('error', $e->getMessage());
        }
    }

    public function create(): \Illuminate\Contracts\View\View|\Illuminate\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\Foundation\Application
    {
        return view('backend.blogs.form');
    }
    public function store(BlogRequest $request)
    {
        try {
            $this->blogRepository->store($request->all());
            return redirect()->route('blogs.index')->with('success', 'Blog created successfully');
        } catch (\Exception $e) {
            return back()->withInput()->with('error', $e->getMessage());
        }
    }
    public function edit(string $id): \Illuminate\Contracts\View\Factory|\Illuminate\Foundation\Application|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application|\Illuminate\Http\RedirectResponse
    {
        try {
            $data = [
                'edit' => $this->blogRepository->find($id)
            ];
            return view('backend.blogs.form', $data);
        } catch (\Exception $e) {
            return back()->with('error', $e->getMessage());
        }
    }
    public function update(BlogRequest $request, $id): \Illuminate\Http\RedirectResponse
    {
        try {
            $this->blogRepository->update($id, $request->all());
            return redirect()->route('blogs.index')->with('success', 'Blog updated successfully');
        } catch (\Exception $e) {
            return back()->withInput()->with('error', $e->getMessage());
        }
    }

    public function destroy(string $id): \Illuminate\Http\RedirectResponse
    {
        try {
            $this->blogRepository->destroy($id);
            return redirect()->route('blogs.index')->with('success', 'Blog deleted successfully');
        } catch (\Exception $e) {
            return back()->with('error', $e->getMessage());
        }
    }
}

Setup Model and Migration

Now we'll set up our model and migration file. And we also discuss each attribute that we going to use there in the previous lecture. So I don't want to repeat it here.

Blog.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Blog extends Model
{
    use HasFactory;

    protected $fillable = [
        'title',
        'slug',
        'unique_id',
        'description',
        'image',
        'user_id',
    ];

    public function user(): \Illuminate\Database\Eloquent\Relations\BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function scopeActive($query)
    {
        return $query->where('status', 1);
    }
}
2023_04_20_060332_create_blogs_table.php
<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('blogs', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained('users');
            $table->string('title');
            $table->string('slug');
            $table->string('unique_id')->nullable();
            $table->text('description');
            $table->string('image');
            $table->boolean('status')->default(1);
            $table->timestamps();
        });
    }

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

Define Routes

Put these routes in web.php.

Route::resource('blogs', BlogController::class)->except(['show']);

The whole file will look like the below

web.php
<?php

use App\Http\Controllers\BlogController;
use App\Http\Controllers\ProfileController;
use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return view('welcome');
});

Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');

Route::middleware('auth')->group(function () {
    Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
    Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
    Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');

    Route::resource('blogs', BlogController::class)->except(['show']);
});

require __DIR__.'/auth.php';

Create and Setup View

So at first, we'll create a blade file where we put our flash messages which we discuss in our previous chapter. And later we'll just @include() on every page.

alert.blade.php
@if(session()->has('success'))
<div class="alert alert-success  alert-dismissible fade show" role="alert">
    <strong>Success!</strong> {{ session()->get('success') }}
    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
        <span aria-hidden="true">&times;</span>
    </button>
</div>
@endif
@if(session()->has('error'))
<div class="alert alert-danger  alert-dismissible fade show" role="alert">
    <strong>Error!</strong> {{ session()->get('error') }}
    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
        <span aria-hidden="true">