A. Nội dung
1. Mô tả đề tài
Mục tiêu: Xây dựng một trang thương mại điện tử có tính năng hiện đại, dễ sử dụng và an toàn, nhằm cung cấp một nền tảng trực tuyến để người dùng có thể mua bán các sản phẩm đa dạng.
2. Công nghệ sử dụng
- Laravel: Framework PHP mạnh mẽ và linh hoạt, giúp xây dựng các ứng dụng web nhanh chóng với cấu trúc MVC (Model-View-Controller) rõ ràng.
- MySQL: Hệ quản trị cơ sở dữ liệu quan hệ phổ biến, dễ sử dụng và có hiệu suất cao.
- HTML/CSS/JavaScript: Các công nghệ front-end để xây dựng giao diện người dùng.
- Blade: Template engine của Laravel để tạo giao diện người dùng động.
3. Chức năng chính
- Đăng ký và đăng nhập người dùng
- Đăng ký tài khoản với email xác thực.
- Đăng nhập bằng email và mật khẩu.
- Quản lý sản phẩm
- Thêm, sửa, xóa sản phẩm (dành cho admin).
- Hiển thị danh sách sản phẩm theo danh mục.
- Tìm kiếm và lọc sản phẩm.
- Giỏ hàng và thanh toán
- Thêm sản phẩm vào giỏ hàng.
- Cập nhật số lượng hoặc xóa sản phẩm khỏi giỏ hàng.
- Thanh toán qua các phương thức thanh toán phổ biến.
- Quản lý đơn hàng
- Xem lịch sử đơn hàng của người dùng.
- Quản lý trạng thái đơn hàng (admin).
- Quản lý danh mục sản phẩm
- Thêm, sửa, xóa danh mục sản phẩm (admin).
- Tích hợp API
- Tích hợp API để cập nhật giá và tình trạng hàng từ các nhà cung cấp.
4. Thiết kế cơ sở dữ liệu
- Bảng users: Lưu thông tin người dùng (id, name, email, password, role, created_at, updated_at).
- Bảng products: Lưu thông tin sản phẩm (id, name, description, price, category_id, created_at, updated_at).
- Bảng categories: Lưu thông tin danh mục sản phẩm (id, name, created_at, updated_at).
- Bảng orders: Lưu thông tin đơn hàng (id, user_id, code, status, created_at, updated_at).
- Bảng order_items: Lưu thông tin chi tiết đơn hàng (id, order_id, product_id, quantity, price, created_at, updated_at).
5. Mô hình dữ liệu workbench
7. Model
User:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Notifications\Notifiable; use Laravel\Sanctum\HasApiTokens; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable { use HasApiTokens, HasFactory,Notifiable; /** * The attributes that are mass assignable. * * @var array<int, string> */ protected $fillable = [ 'name', 'email', 'password', 'role' ]; /** * The attributes that should be hidden for serialization. * * @var array<int, string> */ protected $hidden = [ 'password', 'remember_token', ]; /** * The attributes that should be cast. * * @var array<string, string> */ protected $casts = [ 'email_verified_at' => 'datetime', 'password' => 'hashed', ]; }
Category:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Category extends Model { use HasFactory; protected $fillable =['name','description']; // model relationship function products(){ return $this->hasMany(Product::class); } }
Product:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Product extends Model { use HasFactory; // model relationship protected $fillable =['img','name','description','price','quantity','category_id']; function category(){ return $this->belongsTo(Category::class); } function orderItems(){ return $this->hasMany(Order_Items::class); } }
Order:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Order extends Model { use HasFactory; // model relationship protected $fillable =['user_id','code','status']; function user(){ return $this->belongsTo(User::class); } function orderItems(){ return $this->hasMany(Order_Items::class); } }
Order_items:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Order_items extends Model { use HasFactory; // model relationship protected $fillable =['quantity','price']; function product(){ return $this->belongsTo(Product::class); } function order(){ return $this->belongsTo(Order::class); } }
8. Controller
Admin:
HomeController:
<?php namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class HomeController extends Controller { public function index() { return view('admin.home.index'); } }
ProductController:
<?php namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; use App\Models\Product; use Illuminate\Http\Request; class ProductController extends Controller { /** * Display a listing of the resource. */ public function index() { $productList = Product::all(); return view('Admin.products.index', ['productList' => $productList]); } /** * Show the form for creating a new resource. */ public function create() { return view('Admin.products.create'); } /** * Store a newly created resource in storage. */ public function store(Request $request) { $product = Product::create([ 'img' => $request->input('img'), // Ensure 'name' is included 'name' => $request->input('name'), // Ensure 'name' is included 'description' => $request->input('description'), 'price' => $request->input('price'), 'quantity' => $request->input('quantity'), ]); $message = $product ? "Successfully created" : "Creation failed"; return redirect()->route("Admin.products.index", ["id" => $product->id])->with("message", $message); } /** * Display the specified resource. */ public function show(string $id) { // } /** * Show the form for editing the specified resource. */ public function edit(string $id) { $product = Product::findOrFail($id); return view('Admin.products.edit', compact('product')); } /** * Update the specified resource in storage. */ public function update(Request $request, string $id) { $product = Product::findOrFail($id); $boll = $product->update($request->only(['img', 'name', 'description', 'price', 'quantity'])); $Message = "Successfully update message."; if (!$boll) { $Message = "Failed to update message."; } return redirect()->route('Admin.products.index')->with(['message' => $Message]);; } /** * Remove the specified resource from storage. */ public function destroy(string $id) { $Message = "Success deleted "; if (!Product::destroy($id)) { $Message = "Failed to delete "; } return redirect()->route('Admin.products.index')->with(['message' => $Message]); } }
OrderController:
<?php namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; use App\Models\Order; use Illuminate\Http\Request; class OrderController extends Controller { /** * Display a listing of the resource. */ public function index() { $orderList = Order::all(); return view('Admin.orders.index',['orderList' => $orderList]); } }
UserController:
<?php namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; use App\Models\User; use Illuminate\Http\Request; class UserController extends Controller { /** * Display a listing of the resource. */ public function index() { $userList = User::all(); return view('Admin.users.index',['userList' => $userList]); } /** * Show the form for creating a new resource. */ public function create() { return view( 'Admin.users.create'); } /** * Store a newly created resource in storage. */ public function store(Request $request) { $user = User::create([ 'name' => $request->input('name'), // Ensure 'name' is included 'email' => $request->input('email'), 'password' => $request->input('password'), 'role' => $request->input('role'), ]); $message = $user ? "Successfully created" : "Creation failed"; return redirect()->route("Admin.users.index", ["id" => $user->id])->with("message", $message); } /** * Display the specified resource. */ public function show(string $id) { // } /** * Show the form for editing the specified resource. */ public function edit(string $id) { $user=User::findOrFail($id); return view('Admin.users.edit', compact('user')); } /** * Update the specified resource in storage. */ public function update(Request $request, string $id) { $user =User::findOrFail($id); $boll= $user->update($request->only(['name','email','password'])); $Message = "Successfully update message."; if( !$boll){ $Message = "Failed to update message."; } return redirect()->route('Admin.users.index')->with(['message' => $Message]); ; } /** * Remove the specified resource from storage. */ public function destroy(string $id) { $Message = "Success deleted "; if(!User::destroy($id)){ $Message = "Failed to delete "; } return redirect()->route('Admin.users.index')->with(['message' => $Message]); } }
Home:
UserController:
<?php namespace App\Http\Controllers; use App\Models\User; use Illuminate\Http\Request; class UserController extends Controller { /* * Display a listing of the resource. */ public function index() { return User::all(); } /** * Show the form for creating a new resource. */ public function create() { // } /** * Store a newly created resource in storage. */ public function store(Request $request) { return User::create($request->only('name', 'email', 'password')); } /** * Display the specified resource. */ public function show(string $id) { return User::findOrFail($id); } /** * Show the form for editing the specified resource. */ public function edit(string $id) { // } /** * Update the specified resource in storage. */ public function update(Request $request, string $id) { User::findOrFail($id)->update($request->all()); } /** * Remove the specified resource from storage. */ public function destroy(string $id) { User::findOrFail($id)->destroy($id); } }
SearchController:
<?php namespace App\Http\Controllers; use App\Models\Product as ModelsProduct; use Illuminate\Http\Request; class SearchController extends Controller { /** * Display a listing of the resource. */ public function index( request $request) { $query = $request->input('search'); $productSearch = ModelsProduct::where('name', 'LIKE', "%$query%")->get(); // $productSearch = ModelsProduct::where('name', 'LIKE', '%$query%')->get(); ko loi nhung ko show dc return view('home.search', compact('productSearch')); } }
ProfileController:
<?php namespace App\Http\Controllers; use App\Http\Requests\ProfileUpdateRequest; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Redirect; use Illuminate\View\View; class ProfileController extends Controller { /** * Display the user's profile form. */ public function edit(Request $request): View { return view('profile.edit', [ 'user' => $request->user(), ]); } /** * Update the user's profile information. */ public function update(ProfileUpdateRequest $request): RedirectResponse { $request->user()->fill($request->validated()); if ($request->user()->isDirty('email')) { $request->user()->email_verified_at = null; } $request->user()->save(); return Redirect::route('profile.edit')->with('status', 'profile-updated'); } /** * Delete the user's account. */ public function destroy(Request $request): RedirectResponse { $request->validateWithBag('userDeletion', [ 'password' => ['required', 'current_password'], ]); $user = $request->user(); Auth::logout(); $user->delete(); $request->session()->invalidate(); $request->session()->regenerateToken(); return Redirect::to('/'); } }
ProductController:
<?php namespace App\Http\Controllers; use App\Models\Product; use Illuminate\Http\Request; use Throwable; class ProductController extends Controller { /** * Display a listing of the resource. */ public function index(Request $request) { $query = Product::query(); // Lọc theo mức giá nếu được chọn if ($request->has('price')) { // Phân tách mức giá thành hai phần: min và max $price = explode('-', $request->price); // Lọc các sản phẩm trong phạm vi từ min đến max if (count($price) == 2) { $query->whereBetween('price', [$price[0], $price[1]]); } elseif ($price[0] > 0) { $query->where('price', '>=', $price[0]); } } // Sắp xếp sản phẩm if ($request->has('sort')) { $query->orderBy('price', $request->sort); } $productList = $query->paginate(8); return view('Products.index', ['productList' => $productList]); } /** * Show the form for creating a new resource. */ public function create() { // } /** * Store a newly created resource in storage. */ public function store(Request $request) { return Product::create($request->all()); } /** * Display the specified resource. */ public function show(string $id) { $products =product::findOrFail($id); return view('Products.show',['product' => $products]); } /** * Show the form for editing the specified resource. */ public function edit(string $id) { // } /** * Update the specified resource in storage. */ public function update(Request $request, string $id) { // try { // // return $request->all(); // Product::findOrFail($id)->update($request->all()); // } catch (\Throwable $th) { // dd($th); // } } /** * Remove the specified resource from storage. */ public function destroy(string $id) { Product::findOrFail($id)->destroy($id); } public function search(Request $request) { // try { // $query = $request->input('search'); // // dd($query); // //để thực hiện một truy vấn đến cơ sở dữ liệu // $productSearch = Product::where('name', 'LIKE', "%$query%")->get(); // return view('products.search', compact('productSearch')); // } catch (Throwable $th) { // return $th; // } } }
OrderItemController:
<?php namespace App\Http\Controllers; use App\Models\Order_items; use Illuminate\Http\Request; class OrderItemController extends Controller { /** * Display a listing of the resource. */ public function index() { return Order_items::all(); } public function store(Request $request) { return Order_items::create($request->all()); } /** * Display the specified resource. */ public function show(string $id) { return Order_items::findOrFail($id); } /** * Update the specified resource in storage. */ public function update(Request $request, string $id) { Order_items::findOrFail($id)->update($request); } /** * Remove the specified resource from storage. */ public function destroy(string $id) { Order_items::findOrFail($id)->destroy(); } }
OrderController:
<?php namespace App\Http\Controllers; use App\Models\Order; use Illuminate\Http\Request; class OrderController extends Controller { /** * Display a listing of the resource. */ public function index() { return Order::all(); } /** * Store a newly created resource in storage. */ public function store(Request $request) { return Order::create($request->all()); } /** * Display the specified resource. */ public function show(string $id) { return Order::findOrFail($id); } /** * Update the specified resource in storage. */ public function update(Request $request, string $id) { Order::findOrFail($id)->update($request); } /** * Remove the specified resource from storage. */ public function destroy(string $id) { Order::findOrFail($id)->destroy(); } }
HomeController:
<?php namespace App\Http\Controllers; use App\Models\Product; use Illuminate\Http\Request; class HomeController extends Controller { /** * Display a listing of the resource. */ public function index() { $productListHome = Product::paginate(8); return view('home.index',['productList'=> $productListHome]); } }
Controller:
<?php namespace App\Http\Controllers; use App\Models\Category; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Routing\Controller as BaseController; class Controller extends BaseController { public function __construct() { $categoryList =Category::all(); view()->share('categoryList', $categoryList); } }
CategoryShowController:
<?php namespace App\Http\Controllers; use App\Models\Category; use Illuminate\Http\Request; class CategoryShowController extends Controller { /** * Display a listing of the resource. */ public function index($category_id) { $category = Category::findOrFail($category_id); $products = $category->products; // Assuming you have a relationship defined in Category model return view('products.show', compact('products')); } }
CategoryController:
<?php namespace App\Http\Controllers; use App\Models\Category; use App\Models\Product; use Illuminate\Http\Request; class CategoryController extends ProductController { /** * Display a listing of the resource. */ public function index(Request $request) { $categoryList = Category::all(); return view('home.category', compact('categoryList')); } /** * Display the specified resource. */ public function show(string $id) { // $category = Category::where('id', $id)->get(); // $products = $category->products; // return view('home.showCategory', compact('category', 'products')); $category = Category::where('id', $id)->first(); // Retrieve a single category $products = $category->products; // Access products related to this category return view('home.category', compact('category', 'products')); } }
CartController:
<?php namespace App\Http\Controllers; use App\Models\Product; use Illuminate\Http\Request; class CartController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { $cart = session()->get('cart', []); // Calculate total quantity of items in the cart $totalQuantity = 0; foreach ($cart as $item) { $totalQuantity += $item['quantity']; } return view('cart.index', [ 'cart' => $cart, 'totalQuantity' => $totalQuantity, ]); } /** * Add a product to the cart. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function addToCart(Request $request) { $product_id = $request->input('product_id'); $quantity = $request->input('quantity', 1); $product = Product::findOrFail($product_id); $cart = session()->get('cart', []); if (isset($cart[$product_id])) { $cart[$product_id]['quantity'] += $quantity; } else { $cart[$product_id] = [ 'name' => $product->name, 'price' => $product->price, 'quantity' => $quantity, 'image' => $product->image ]; } session()->put('cart', $cart); return redirect()->route('cart.index')->with('success', 'Product added to cart successfully!'); } // Other methods like edit, update, destroy, and getItemCount can be defined here }