CRUD Project (Create | Read | Update | Delete) | Image Upload in Laravel 11

  <?php


namespace App\Http\Controllers;

use App\Models\Product;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Validator;

class ProductController extends Controller
{
    // This method will show products page
    public function index()
    {
        $products = Product::orderBy("created_at", "DESC")->get();
        return view("products.list", [
            "products" => $products
        ]);
    }

    // This method will show create product page
    public function create()
    {
        return view("products.create");
    }

    // This method will store a product in db
    public function store(Request $request)
    {
        $rules = [
            "name" => "required|min:5",
            "sku" => "required|min:3",
            "price" => "required|numeric"
        ];

        if ($request->image != "") {
            $rules["image"] = "image";
        }

        $validator = Validator::make($request->all(), $rules);

        if ($validator->fails()) {
            return redirect()->route("products.create")->withInput()->withErrors($validator);
        }

        // here we will insert product in db
        $product = new Product();

        $product->name = $request->name;
        $product->sku = $request->sku;
        $product->price = $request->price;
        $product->description = $request->description;
        $product->save();

        if ($request->image != "") {
            // here we will store image
            $image = $request->image;
            $ext = $image->getClientOriginalExtension();
            $imageName = time() . "." . $ext;   //Unique image name

            // Save image to products directory
            $image->move(public_path("uploads/products"), $imageName);

            // Save image name in database
            $product->image = $imageName;
            $product->save();
        }

        return redirect()->route("products.index")->with("success", "Product added successfully.");
    }

    // This method will show edit product page
    public function edit($id)
    {
        $product = Product::findOrFail($id);
        return view("products.edit", [
            "product" => $product
        ]);
    }

    // This method will update a product
    public function update($id, Request $request)
    {
        $product = Product::findOrFail($id);

        $rules = [
            "name" => "required|min:5",
            "sku" => "required|min:3",
            "price" => "required|numeric"
        ];

        if ($request->image != "") {
            $rules["image"] = "image";
        }

        $validator = Validator::make($request->all(), $rules);

        if ($validator->fails()) {
            return redirect()->route("products.edit", $product->id)->withInput()->withErrors($validator);
        }

        // here we will update product in db
        $product->name = $request->name;
        $product->sku = $request->sku;
        $product->price = $request->price;
        $product->description = $request->description;
        $product->save();

        if ($request->image != "") {
            // delete old image
            File::delete(public_path("uploads/products/" . $product->image));

            // here we will store image
            $image = $request->image;
            $ext = $image->getClientOriginalExtension();
            $imageName = time() . "." . $ext;   //Unique image name

            // Save image to products directory
            $image->move(public_path("uploads/products"), $imageName);

            // Save image name in database
            $product->image = $imageName;
            $product->save();
        }

        return redirect()->route("products.index")->with("success", "Product updated successfully.");
    }

    // This method will delete a product
    public function destroy($id)
    {
        $product = Product::findOrFail($id);

        // delete image
        File::delete(public_path("uploads/products/" . $product->image));

        // delete product from database
        $product->delete();

        return redirect()->route("products.index")->with("success", "Product deleted successfully.");
    }
}
Above File is app\Http\Controllers\ProductController.php File





Below File is app\Models\Product.php File
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    public $timestamps = true;
    protected $table = "products";
    protected $fillable = ["name", "sku", "price", "description", "image"];
}






Below File is database\migrations\2025_01_01_090826_create_products_table File
<?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('products', function (Blueprint $table) {
            $table->id();
            $table->string("name");
            $table->string("sku");
            $table->double("price", 10, 2);
            $table->text("description")->nullable();
            $table->string("image")->nullable();
            $table->timestamps();
        });
    }

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






Below File is resources\views\products\create.blade.php File
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Create Page</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<body>
    <div class="bg-dark py-3">
        <h3 class="text-white text-center">Simple Laravel 11 CRUD</h3>
    </div>
    <div class="container">
        <div class="row justify-content-center mt-4">
            <div class="col-md-10 d-flex justify-content-end">
                <a href="{{ route('products.index') }}" class="btn btn-dark">Back</a>
            </div>
        </div>
        <div class="row d-flex justify-content-center">
            <div class="col-md-10">
                <div class="card border-0 shadow-lg my-4">
                    <div class="card-header bg-dark">
                        <h3 class="text-white">Create Product</h3>
                    </div>
                    <form action="{{ route('products.store') }}" method="POST" enctype="multipart/form-data">
                        @csrf
                        <div class="card-body">
                            <div class="mb-3">
                                <label for="name" class="form-label h5">Name</label>
                                <input type="text" name="name" id="name" value="{{ old("name") }}" class="form-control form-control-lg @error("name") is-invalid @enderror" placeholder="Name"/>
                                @error("name")
                                    <p class="invalid-feedback">{{ $message }}</p>
                                @enderror
                            </div>
                            <div class="mb-3">
                                <label for="sku" class="form-label h5">Sku</label>
                                <input type="text" name="sku" id="sku" value="{{ old("sku") }}" class="form-control form-control-lg @error("sku") is-invalid @enderror" placeholder="Sku"/>
                                @error("sku")
                                    <p class="invalid-feedback">{{ $message }}</p>
                                @enderror
                            </div>
                            <div class="mb-3">
                                <label for="price" class="form-label h5">Price</label>
                                <input type="text" name="price" id="price" value="{{ old("price") }}" class="form-control form-control-lg @error("price") is-invalid @enderror" placeholder="Price"/>
                                @error("price")
                                    <p class="invalid-feedback">{{ $message }}</p>
                                @enderror
                            </div>
                            <div class="mb-3">
                                <label for="description" class="form-label h5">Description</label>
                                <textarea name="description" id="description" value="{{ old("description") }}" class="form-control" cols="30" rows="5" placeholder="Description"></textarea>
                            </div>
                            <div class="mb-3">
                                <label for="image" class="form-label h5">Image</label>
                                <input type="file" name="image" id="image" class="form-control form-control-lg" placeholder="Price"/>
                            </div>
                            <div class="d-grid">
                                <button type="submit" class="btn btn-lg btn-primary">Submit</button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</body>
</html>





Below File is resources\views\products\edit.blade.php File
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Create Page</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<body>
    <div class="bg-dark py-3">
        <h3 class="text-white text-center">Simple Laravel 11 CRUD</h3>
    </div>
    <div class="container">
        <div class="row justify-content-center mt-4">
            <div class="col-md-10 d-flex justify-content-end">
                <a href="{{ route('products.index') }}" class="btn btn-dark">Back</a>
            </div>
        </div>
        <div class="row d-flex justify-content-center">
            <div class="col-md-10">
                <div class="card border-0 shadow-lg my-4">
                    <div class="card-header bg-dark">
                        <h3 class="text-white">Edit Product</h3>
                    </div>
                    <form action="{{ route('products.update',$product->id) }}" method="POST" enctype="multipart/form-data">
                        @csrf
                        @method("PUT")
                        <div class="card-body">
                            <div class="mb-3">
                                <label for="name" class="form-label h5">Name</label>
                                <input type="text" name="name" id="name" value="{{ old("name",$product->name) }}" class="form-control form-control-lg @error("name") is-invalid @enderror" placeholder="Name"/>
                                @error("name")
                                    <p class="invalid-feedback">{{ $message }}</p>
                                @enderror
                            </div>
                            <div class="mb-3">
                                <label for="sku" class="form-label h5">Sku</label>
                                <input type="text" name="sku" id="sku" value="{{ old("sku",$product->sku) }}" class="form-control form-control-lg @error("sku") is-invalid @enderror" placeholder="Sku"/>
                                @error("sku")
                                    <p class="invalid-feedback">{{ $message }}</p>
                                @enderror
                            </div>
                            <div class="mb-3">
                                <label for="price" class="form-label h5">Price</label>
                                <input type="text" name="price" id="price" value="{{ old("price",$product->price) }}" class="form-control form-control-lg @error("price") is-invalid @enderror" placeholder="Price"/>
                                @error("price")
                                    <p class="invalid-feedback">{{ $message }}</p>
                                @enderror
                            </div>
                            <div class="mb-3">
                                <label for="description" class="form-label h5">Description</label>
                                <textarea name="description" id="description" value="{{ old("description",$product->description) }}" class="form-control" cols="30" rows="5" placeholder="Description"></textarea>
                            </div>
                            <div class="mb-3">
                                <label for="image" class="form-label h5">Image</label>
                                <input type="file" name="image" id="image" class="form-control form-control-lg" placeholder="Price"/>

                                @if($product->image != "")
                                    <img src="{{ asset('uploads/products/'.$product->image) }}" class="w-50 my-3" alt=""/>
                                @endif
                            </div>
                            <div class="d-grid">
                                <button type="submit" class="btn btn-lg btn-primary">Update</button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</body>
</html>






Below File is resources\views\products\list.blade.php File
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Create Page</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<body>
    <div class="bg-dark py-3">
        <h3 class="text-white text-center">Simple Laravel 11 CRUD</h3>
    </div>
    <div class="container">
        <div class="row d-flex justify-content-center mt-4">
            <div class="col-md-10 d-flex justify-content-end">
                <a href="{{ route('products.create') }}" class="btn btn-dark">Create</a>
            </div>
        </div>
        <div class="row d-flex justify-content-center">
            @if(Session::has("success"))
            <div class="col-md-10 mt-4">
                <div class="alert alert-success">
                    {{ Session::get("success") }}
                </div>
            </div>
            @endif
            <div class="col-md-10">
                <div class="card border-0 shadow-lg my-4">
                    <div class="card-header bg-dark">
                        <h3 class="text-white">Products</h3>
                    </div>
                    <div class="card-body">
                        <table class="table table-bordered table-striped table-hovered">
                            <thead>
                                <th>ID</th>
                                <th>Image</th>
                                <th>Name</th>
                                <th>Sku</th>
                                <th>Price</th>
                                <th>Created At</th>
                                <th>Action</th>
                            </thead>
                            @if($products->isNotEmpty())
                            @foreach($products as $data)
                                <tbody>
                                    <td>{{ $data->id }}</td>
                                    <td>
                                        @if($data->image != "")
                                            <img src="{{ asset('uploads/products/'.$data->image) }}" width="50" alt=""/>
                                        @endif
                                    </td>
                                    <td>{{ $data->name }}</td>
                                    <td>{{ $data->sku }}</td>
                                    <td>${{ $data->price }}</td>
                                    <td>{{ \Carbon\Carbon::parse($data->created_at)->format("d M, Y") }}</td>
                                    <td>
                                        <a href="{{ route('products.edit',$data->id) }}" class="btn btn-dark">Edit</a>
                                        <a href="#" onclick="deleteProduct({{ $data->id }});" class="btn btn-danger">Delete</a>
                                        <form id="delete-product-from-{{ $data->id }}" action="{{ route('products.destroy',$data->id) }}" method="POST">
                                            @csrf
                                            @method("DELETE")
                                        </form>
                                    </td>
                                </tbody>
                            @endforeach
                            @endif
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

<script>
    function deleteProduct(id)
    {
        if(confirm("Are you sure you want to delete product ?")) {
            document.getElementById("delete-product-from-"+id).submit();
        }
    }
</script>





Below File is routes\web.php File
<?php

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

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

Route::controller(ProductController::class)->group(function () {
    Route::get("/products/create", "create")->name("products.create");
    Route::post("/products", "store")->name("products.store");
    Route::get("/products", "index")->name("products.index");
    Route::get("/products/{product}/edit", "edit")->name("products.edit");
    Route::put("/products/{product}", "update")->name("products.update");
    Route::delete("/products/{product}", "destroy")->name("products.destroy");
});







Comments