[Series] Xây dựng RESTful API từ con số 0 với PHP Thuần & MVC - Phần 20: Quản lý Danh sách yêu thích (Wishlist)
Chào các bạn, mình đã quay trở lại!
Một website bán hàng hiện đại mà thiếu đi cái "nút thả tim" (Wishlist) thì quả là một thiếu sót lớn. Wishlist không chỉ giúp người dùng lưu trữ sản phẩm họ quan tâm mà còn là nguồn dữ liệu quý giá để hệ thống thực hiện các chiến dịch Marketing như "Sản phẩm bạn yêu thích đang giảm giá".
Trong bài viết này, chúng ta sẽ tiếp tục mở rộng mô hình MVC để xử lý Wishlist. Chúng ta sẽ tập trung vào việc truy vấn dữ liệu liên kết (JOIN) và xóa bỏ các mục không còn mong muốn, tất cả đều được bảo mật bằng JWT Auth Middleware.
1. Cấu trúc bảng dữ liệu (Wishlists)
Chúng ta cần một bảng trung gian để lưu giữ mối quan hệ giữa Người dùng và Sản phẩm họ yêu thích.
CREATE TABLE Wishlists (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
product_id INT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES Users(id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES Products(id) ON DELETE CASCADE
);
2. Tầng Model: Truy vấn và Xử lý (Wishlist.php)
Model này sẽ chịu trách nhiệm lấy ra danh sách sản phẩm kèm theo các thông tin cần thiết như tên, giá và slug để Frontend có thể hiển thị đẹp mắt.
File: app/Models/Wishlist.php
<?php
namespace App\Models;
use App\Core\Database;
class Wishlist {
protected $db;
public function __construct() {
$this->db = Database::getInstance();
}
/**
* Lấy danh sách yêu thích của một User cụ thể
*/
public function getByUser($userId) {
$stmt = $this->db->prepare("
SELECT w.id, p.id AS product_id, p.name, p.price, p.slug
FROM Wishlists w
JOIN Products p ON w.product_id = p.id
WHERE w.user_id = ?
ORDER BY w.created_at DESC
");
$stmt->execute([$userId]);
return $stmt->fetchAll();
}
/**
* Xóa sản phẩm khỏi danh sách yêu thích
*/
public function delete($id) {
$stmt = $this->db->prepare("DELETE FROM Wishlists WHERE id = ?");
return $stmt->execute([$id]);
}
}
3. Tầng Controller: Xác thực JWT (WishlistController.php)
Vì Wishlist là dữ liệu cá nhân, chúng ta bắt buộc phải sử dụng AuthMiddleware để xác định chính xác ai đang yêu cầu xem danh sách.
File: app/Controllers/WishlistController.php
<?php
namespace App\Controllers;
use App\Models\Wishlist;
use App\Middleware\AuthMiddleware;
use App\Core\Response;
class WishlistController
{
/**
* Lấy danh sách Wishlist của user hiện tại
*/
public function index() {
// Xác thực JWT và lấy payload
$user = AuthMiddleware::check();
$wishlistModel = new Wishlist();
$items = $wishlistModel->getByUser($user->sub);
Response::json([
'status' => 'success',
'count' => count($items),
'wishlist' => $items
]);
}
/**
* Xóa một mục khỏi Wishlist
*/
public function destroy($id) {
// Kiểm tra đăng nhập trước khi xóa
AuthMiddleware::check();
$wishlistModel = new Wishlist();
/**
* Gợi ý bảo mật: Bạn nên kiểm tra xem item_id này
* có thực sự thuộc về user_id đang đăng nhập không trước khi xóa.
*/
$wishlistModel->delete($id);
Response::json(['message' => 'Đã xóa sản phẩm khỏi danh sách yêu thích']);
}
}
4. Cấu hình Route (index.php)
Đăng ký các điểm cuối API cho Wishlist vào hệ thống Router của bạn.
File: public/index.php
use App\Controllers\WishlistController;
$wishlistController = new WishlistController();
// 1. Lấy danh sách wishlist (GET /api/wishlist)
if ($uri === '/api/wishlist' && $method === 'GET') {
$wishlistController->index();
// 2. Xóa mục khỏi wishlist (DELETE /api/wishlist/{id})
} elseif (preg_match('#^/api/wishlist/(\d+)$#', $uri, $matches) && $method === 'DELETE') {
$wishlistController->destroy($matches[1]);
}
5. Kiểm thử API (Test with Curl)
Đừng quên đính kèm Token trong Header để chứng minh bạn là "chủ nhân" của danh sách nhé.
Xem danh sách yêu thích:
curl -X GET http://localhost:8000/api/wishlist \
-H "Authorization: Bearer {JWT_TOKEN_CUA_BAN}"
Xóa một mục khỏi danh sách (ví dụ ID: 7):
curl -X DELETE http://localhost:8000/api/wishlist/7 \
-H "Authorization: Bearer {JWT_TOKEN_CUA_BAN}"
Tạm kết
Vậy là hệ thống của chúng ta đã có thêm một tính năng cực kỳ thân thiện với người dùng. Việc kết hợp chặt chẽ giữa JWT và các câu lệnh SQL JOIN giúp bạn quản lý dữ liệu cá nhân một cách an toàn và hiệu quả. Hãy để lại bình luận phía dưới nhé! Đừng quên Upvote để ủng hộ mình ra bài đều đặn. Chúc các bạn code vui vẻ, bố đời!
All rights reserved