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>
@endsection
resources/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>
@endsection
resources/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>
@endsection
resources/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>
@endsection
resources/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>
@endsection
resources/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>
@endsection
Routes 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');
});
