Download Laravel App
https://laravel.com/docs/12.x/installation
Connecting our Database
open .env file root directory.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=8889
DB_DATABASE=laravel12dev
DB_USERNAME=root
DB_PASSWORD=root
Database Migration
php artisan migrate
myapp>php artisan migrate
Migration table created successfully.
check database table
Create tables Product Model php artisan make:model Product -m myapp>php artisan make:model Product -m Open new Products migrations yourproject/database/migrations laravelproject\database\migrations\_create_products_table.php
//laravelproject\database\migrations\_create_products_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('products', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('description')->nullable(); $table->integer('quantity'); $table->float('price'); $table->string('image')->nullable(); $table->enum('status', ['active', 'in-active'])->default('active'); $table->softDeletes(); $table->timestamps(); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('products'); } };run
myapp>php artisan migrate
update Product Model
app/models/Product.php
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; class Product extends Model { use SoftDeletes, HasFactory; protected $fillable = [ "name", "description", "quantity", "price", "status", "image", ]; }Create PostController
php artisan make:controller PostController
change it with the following codes:
app\Http\Controllers\PostController.php
//app\Http\Controllers\ProductController.php <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\Product; use Illuminate\Support\Facades\Storage; class ProductController extends Controller { public function index(Request $request) { // $products = Product::all(); $query = Product::query(); if (request()->has("search") && $request->search) { $query = $query->where("name", "like", "%" . $request->search . "%") ->orWhere('description', 'like', "%" . $request->search . "%"); } $products = $query->latest()->paginate(3); return view("product.index", compact("products")); } public function create() { return view("product.create"); } public function store(Request $request) { $validated = $request->validate([ "name" => "required|string", "description" => "nullable|string", "price" => "required|numeric", "quantity" => "required|numeric", "status" => "required", "image" => "nullable|image|mimes:jpg,png", ]); if ($request->hasFile("image")) { //php artisan storage:link $validated["image"] = $request->file("image")->store("products", "public"); } Product::create($validated); return redirect()->route("products.index")->with("success", "product added successfully"); } public function show($id) { $product = Product::find($id); return view("product.show", compact("product")); } public function edit($id) { $product = Product::find($id); return view("product.edit", compact("product")); } public function update(Request $request, $id) { $validated = $request->validate([ "name" => "required|string", "description" => "nullable|string", "price" => "required|numeric", "quantity" => "required|numeric", "status" => "required", "image" => "nullable|image|mimes:jpg,png", ]); if ($request->hasFile("image")) { if ($request->image && Storage::disk("public")->exists($request->image)) { Storage::disk("public")->delete($request->image); } $validated["image"] = $request->file("image")->store("products", "public"); } Product::find($id)->update($validated); return redirect()->route("products.index")->with("success", "product updated successfully!"); } public function destroy($id) { Product::find($id)->delete(); return redirect()->route("products.index")->with("success", "product deleted successfully!"); } public function trashedProducts(Request $request) { $query = Product::query()->onlyTrashed(); $products = $query->paginate(3); return view("product.deleted-products", compact("products")); } public function showTrashed($id) { $product = Product::onlyTrashed()->findOrFail($id); return view("product.show", compact("product")); } public function restoreProduct($id) { $product = Product::onlyTrashed()->findOrFail($id); $product->restore(); return redirect()->route("products.index")->with("success", "product restored successfully"); } public function destroyProduct($id) { $product = Product::onlyTrashed()->findOrFail($id); if ($product->image && Storage::exists($product->image)) { Storage::delete($product->image); } $product->forceDelete(); return redirect()->route("products.index")->with("success", "product was force deleted successfully!"); } }Create AuthController
php artisan make:controller AuthController
change it with the following codes:
app\Http\Controllers\AuthController.php
//app\Http\Controllers\AuthController.php <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Auth; use Illuminate\Validation\ValidationException; class AuthController extends Controller { public function login() { $pass = Hash::make("123456789"); return view("login")->with('password', $pass); } public function loginAction(Request $request) { $validated = $request->validate([ 'email' => 'required|email', 'password' => 'required' ]); if (!Auth::attempt($request->only('email', 'password'), $request->boolean('remember'))) { throw ValidationException::withMessages([ 'email' => trans('auth.failed') ]); } $request->session()->regenerate(); return redirect()->route("products.index")->with("success", "Login successfully"); } public function logout(Request $request) { Auth::guard('web')->logout(); $request->session()->invalidate(); return redirect('/login'); } }Create View File resources/views/layouts/app.blade.php
//resources/views/layouts/app.blade.php <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Laravel 12 CRUD</title> @vite(['resources/sass/app.scss', 'resources/js/app.js']) </head> <body> <nav class="py-2 bg-body-tertiary border-bottom"> <div class="container d-flex flex-wrap"> <ul class="nav me-auto"> <li class="nav-item"><a href="#" class="nav-link link-body-emphasis px-2 active" aria-current="page">Home</a></li> <li class="nav-item"><a href="#" class="nav-link link-body-emphasis px-2">Features</a></li> <li class="nav-item"><a href="#" class="nav-link link-body-emphasis px-2">Pricing</a></li> <li class="nav-item"><a href="#" class="nav-link link-body-emphasis px-2">FAQs</a></li> <li class="nav-item"><a href="#" class="nav-link link-body-emphasis px-2">About</a></li> </ul> <ul class="nav"> <li class="nav-item"><a href="#" class="nav-link link-body-emphasis px-2">Login</a></li> <li class="nav-item"><a href="#" class="nav-link link-body-emphasis px-2">Sign up</a></li> </ul> </div> </nav> <header class="py-3 mb-4 border-bottom"> <div class="container d-flex flex-wrap justify-content-center"> <a href="/" class="d-flex align-items-center mb-3 mb-lg-0 me-lg-auto link-body-emphasis text-decoration-none"> <svg class="bi me-2" width="40" height="32" aria-hidden="true"> <use xlink:href="#bootstrap"></use> </svg> <span class="fs-4">Cairocoders</span> </a> </div> </header> @yield('content') </body> </html>Home resources/views/product/index.blade.php
//resources/views/product/index.blade.php @extends('layouts.layout') @section('content') <div class="container"> <div class="card"> <div class="card-header"> <div class="row"> <div class="col"> <h2>Product List</h2> </div> <div class="col"> <div class="row"> <div class="col-md-12"> <div class="row"> <div class="col"> <div><a href="{{ route('products.trashed')}}" class="float-end btn btn-danger" style="margin-left:10px;">Deleted</a></div> <div><a href="{{ route('products.create')}}" class="float-end btn btn-primary">Add New</a></div> </div> </div> </div> <div class="col-md-12" style="padding-top:20px;"> <form class="d-flex" role="search" action="{{ route('products.index')}}" method="GET"> @csrf <input class="form-control me-2" name="search" type="search" placeholder="Search" aria-label="Search"> <button class="btn btn-outline-success" type="submit">Search</button> </form> </div> </div> </div> </div> </div> @if (Session::has('success')) <span class="alert alert-success p-2">{{ Session::get('success')}}</span> @endif @if (Session::has('error')) <span>{{ Session::get('error')}}</span> @endif <div class="card-body"> <table class="table table-striped"> <thead> <tr> <th scope="col">#</th> <th scope="col">Photo</th> <th scope="col">Product Name</th> <th scope="col">Quantity</th> <th scope="col">Price</th> <th scope="col">Status</th> <th scope="col">Description</th> <th scope="col">Action</th> </tr> </thead> <tbody> @if (count($products) > 0) @foreach ($products as $product) <tr> <th scope="row">{{ $loop->iteration }}</th> <td><img src="{{ asset('storage/' . $product->image) }}" width="100"></td> <td>{{ str($product->name)->words(2)}}</td> <td>{{ $product->quantity}}</td> <td>{{ $product->price}}</td> <td>{{ $product->status}}</td> <td>{{ str($product->description)->words(5)}}</td> <td> <a href="{{ route('products.show', $product->id) }} " class="btn btn-success btn">show</a> <a href="{{ route('products.edit', $product->id) }} " class="btn btn-primary btn">edit</a> <form action="{{ route('products.destroy', $product->id) }}" method="POST" style="display:inline-block"> @csrf @method('DELETE') <button onclick="return confirm('Are you sure?')" class="btn btn btn-danger">Delete</button> </form> </td> </tr> @endforeach @else <tr> <td colspan="8" class="text-center">No Data Found!</td> </tr> @endif </tbody> </table> {{ $products->links('pagination::bootstrap-5') }} </div> </div> </div> @endsectionresources/views/product/create.blade.php
//resources/views/product/create.blade.php @extends('layouts.layout') @section('content') <div class="container"> <div class="card"> <div class="card-header"> Add New Product </div> <div class="card-body"> <form action="{{ route('products.store')}}" method="post" enctype="multipart/form-data"> @csrf @include('product.form') <button type="submit" class="btn btn-primary">Save</button> <a href="{{ route('products.index')}}" class="btn btn-secondary">Cancel</a> </form> </div> </div> </div> @endsectionresources/views/product/form.blade.php
//resources/views/product/form.blade.php <div class="mb-3"> <label class="form-label">Product Name *</label> <input type="text" name="name" class="form-control" value="{{ old('name', $product->name ?? '') }}"> @error('name') <span class="text-danger">{{ $message }}</span> @enderror </div> <div class="mb-3"> <label class="form-label">Description</label> <textarea name="description" class="form-control">{{ old('description', $product->description ?? '') }}</textarea> @error('description') <span class="text-danger">{{ $message }}</span> @enderror </div> <div class="mb-3"> <label class="form-label">Price *</label> <input type="number" name="price" step="0.01" class="form-control" value="{{ old('price', $product->price ?? '') }}"> @error('price') <span class="text-danger">{{ $message }}</span> @enderror </div> <div class="mb-3"> <label class="form-label">Quantity *</label> <input type="number" name="quantity" class="form-control" value="{{ old('quantity', $product->quantity ?? '') }}"> @error('quantity') <span class="text-danger">{{ $message }}</span> @enderror </div> <div class="mb-3"> <label class="form-label">Status *</label> <select name="status" class="form-select"> <option value="active" {{ (old('status', $product->status ?? '') == 'active') ? 'selected' : '' }}>Active</option> <option value="in-active" {{ (old('status', $product->status ?? '') == 'in-active') ? 'selected' : '' }}>Inactive </option> </select> @error('status') <span class="text-danger">{{ $message }}</span> @enderror </div> <div class="mb-3"> <label class="form-label">Product Image</label> <input type="file" name="image" class="form-control"> @error('image') <span class="text-danger">{{ $message }}</span> @enderror @if (!empty($product->image)) <img src="{{ asset('storage/' . $product->image) }}" class="mt-2" width="300"> @endif </div>resources/views/product/edit.blade.php
//resources/views/product/edit.blade.php @extends('layouts.layout') @section('content') <div class="container"> <div class="card"> <div class="card-header"> Edit Product </div> <div class="card-body"> <form action="{{ route('products.update', $product->id) }}" method="POST" enctype="multipart/form-data"> @csrf @method('PUT') @include('product.form') <button type="submit" class="btn btn-primary">Update</button> <a href="{{ route('products.index')}}" class="btn btn-secondary">Cancel</a> </form> </div> </div> </div> @endsectionresources/views/product/show.blade.php
//resources/views/product/show.blade.php @extends('layouts.layout') @section('content') <div class="container"> <h2>Product Details</h2> <div class="card"> <div class="card-body"> @if($product->image) <img src="{{ asset('storage/' . $product->image) }}" width="250" class="mb-3"> @endif <p><strong>Name:</strong> {{ $product->name }}</p> <p><strong>Description:</strong> {{ $product->description }}</p> <p><strong>Price:</strong> ${{ number_format($product->price, 2) }}</p> <p><strong>Quantity:</strong> {{ $product->quantity }}</p> <p><strong>Status:</strong> <span class="badge bg-{{ $product->status === 'active' ? 'success' : 'secondary' }}"> {{ ucfirst($product->status) }} </span> </p> <a href="{{ route('products.edit', $product->id) }}" class="btn btn-warning">Edit</a> <a href="{{ route('products.index') }}" class="btn btn-secondary">Back</a> </div> </div> </div> @endsectionresources/views/product/deleted-products.blade.php
//resources/views/product/deleted-products.blade.php @extends('layouts.layout') @section('content') <div class="container"> <div class="card"> <div class="card-header"> <div class="row"> <div class="col"> <h2>Product List</h2> </div> <div class="col"> <div class="row"> <div class="col-md-12"> <a href="{{ route('products.index')}}" class="float-end btn btn-warning">View All Products</a> </div> <div class="col-md-12" style="padding-top:20px;"> <form class="d-flex" role="search" action="{{ route('products.trashed')}}" method="GET"> @csrf <input class="form-control me-2" name="search" type="search" placeholder="Search" aria-label="Search"> <button class="btn btn-outline-success" type="submit">Search</button> </form> </div> </div> </div> </div> </div> @if (Session::has('success')) <span class="alert alert-success p-2">{{ Session::get('success')}}</span> @endif @if (Session::has('error')) <span>{{ Session::get('error')}}</span> @endif <div class="card-body"> <table class="table table-striped"> <thead> <tr> <th scope="col">#</th> <th scope="col">Photo</th> <th scope="col">Product Name</th> <th scope="col">Quantity</th> <th scope="col">Price</th> <th scope="col">Status</th> <th scope="col">Description</th> <th scope="col">Action</th> </tr> </thead> <tbody> @if (count($products) > 0) @foreach ($products as $product) <tr> <th scope="row">{{ $loop->iteration }}</th> <td><img src="{{ asset('storage/' . $product->image) }}" width="100"></td> <td>{{ $product->name}}</td> <td>{{ $product->quantity}}</td> <td>{{ $product->price}}</td> <td>{{ $product->status}}</td> <td>{{ $product->description}}</td> <td> <a href="{{ route('trashed.show', $product->id) }}" class="btn btn-success btn">show</a> <form action="{{ route('trashed.restore', $product->id) }}" method="POST" style="display:inline-block"> @csrf @method('PUT') <button onclick="return confirm('Are you sure?')" class="btn btn btn-info">Restore</button> </form> <form action="{{ route('trashed.delete', $product->id) }}" method="POST" style="display:inline-block"> @csrf @method('DELETE') <button onclick="return confirm('Are you sure?')" class="btn btn btn-danger">Delete</button> </form> </td> </tr> @endforeach @else <tr> <td colspan="8" class="text-center">No Data Found!</td> </tr> @endif </tbody> </table> {{ $products->links() }} </div> </div> </div> @endsectionresources/views/login.blade.php
//resources/views/login.blade.php @extends('layouts.layout') @section('content') <div class="container"> <div class="card"> <div class="card-header"> Login </div> <div class="card-body"> <form action="{{ route('login.action') }}" method="POST" class="user"> @csrf @if ($errors->any()) <div class="alert alert-danger"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <div class="mb-3"> <label class="form-label">Email</label> <input name="email" type="email" class="form-control form-control-user" id="exampleInputEmail" aria-describedby="emailHelp" placeholder="Enter Email Address..."> </div> <div class="mb-3"> <label class="form-label">Password</label> <input name="password" type="password" class="form-control form-control-user" id="exampleInputPassword" placeholder="Password"> {{ $password }} </div> <div class="mb-3"> <div class="custom-control custom-checkbox small"> <input name="remember" type="checkbox" class="custom-control-input" id="customCheck"> <label class="custom-control-label" for="customCheck">Remember Me</label> </div> </div> <button type="submit" class="btn btn-primary btn-block btn-user">Login</button> </form> </div> </div> </div> @endsectionRoutes
routes/web.php
//routes/web.php <?php use Illuminate\Support\Facades\Route; use App\Http\Controllers\ProductController; use App\Http\Controllers\AuthController; Route::get('/', function () { return view('welcome'); }); Route::middleware('auth')->group(function () { //Route::get('dashboard', function () { // return view('dashboard'); //})->name('dashboard'); Route::controller(ProductController::class)->group(function () { Route::get('/admin/products', 'index')->name('products.index'); Route::get('/admin/products/create', 'create')->name('products.create'); Route::post('/admin/products', 'store')->name('products.store'); Route::get('/admin/products/show/{product}', 'show')->name('products.show'); Route::get('/admin/products/{product}/edit', 'edit')->name('products.edit'); Route::put('/admin/products/{product}', 'update')->name('products.update'); Route::delete('/admin/products/{product}', 'destroy')->name('products.destroy'); Route::get('/admin/deleted-products', 'trashedProducts')->name('products.trashed'); Route::get('/admin/show-trashed-product/{id}', 'showTrashed')->name('trashed.show'); Route::put('/admin/restore-product/{id}', 'restoreProduct')->name('trashed.restore'); Route::delete('/admin/delete-product/{id}', 'destroyProduct')->name('trashed.delete'); }); }); Route::controller(AuthController::class)->group(function () { Route::get('login', 'login')->name('login'); Route::post('login', 'loginAction')->name('login.action'); Route::get('logout', 'logout')->middleware('auth')->name('logout'); });