Workflow xử lý
sequenceDiagram
autonumber
participant C as Client
participant S as Server
participant A as API
participant DB as Database
C ->> +S: Gởi yêu cầu (Request GET) kèm tham số (parameter) sp_ma={...}
note right of C: https://nentang.vn/frontend/sanpham/detail.php?sp_ma=5
S ->> S: phân tách dữ liệu từ người dùng gởi đến trong biến $_GET
note right of S: lấy dữ liệu $_GET['sp_ma']
S ->> +DB: thực thi câu lệnh (SQL QUERY) lấy thông tin Sản phẩm theo sp_ma
note over S,DB: SELECT * FROM sanpham WHERE sp_ma = $sp_ma ...
DB -->> -S: Database trả về Khối dữ liệu
S ->> S: phân tách khối dữ liệu
S ->> S: render giao diện Sản phẩm
S --x -C: trả về Phản hồi (response) giao diện FORM Chi tiết Sản phẩm
C ->> +A: khi người dùng nhập Số lượng và Bấm Thêm vào Giỏ hàng, gọi AJAX đến API giohang-themsanpham.php
A ->> S: lưu thông tin Sản phẩm vào Giỏ hàng trong SESSION
A -->> -C: trả về thông tin theo định dạng JSON Format
C -x C: cập nhật lại phần giao diện tương ứng
Giao diện trang Chi tiết Sản phẩm
Xem thêm bài khái niệm API và Web API là gì?
Step 1: tạo API thêm Sản phẩm vào Giỏ hàng trong Session
- Tạo file
frontend/api/giohang-themsanpham.php
<?php
// hàm `session_id()` sẽ trả về giá trị SESSION_ID (tên file session do Web Server tự động tạo)
// - Nếu trả về Rỗng hoặc NULL => chưa có file Session tồn tại
if (session_id() === '') {
// Yêu cầu Web Server tạo file Session để lưu trữ giá trị tương ứng với CLIENT (Web Browser đang gởi Request)
session_start();
}
// Truy vấn database để lấy danh sách
// 1. Include file cấu hình kết nối đến database, khởi tạo kết nối $conn
include_once(__DIR__ . '/../../dbconnect.php');
// 2. Lấy thông tin người dùng gởi đến
$sp_ma = $_POST['sp_ma'];
$sp_ten = $_POST['sp_ten'];
$soluong = $_POST['soluong'];
$gia = $_POST['sp_gia'];
$hinhdaidien = $_POST['hinhdaidien'];
// 3. Lưu trữ giỏ hàng trong session
// Nếu khách hàng đặt hàng cùng sản phẩm đã có trong giỏ hàng => cập nhật lại Số lượng, Thành tiền
if (isset($_SESSION['giohangdata'])) {
$data = $_SESSION['giohangdata'];
$data[$sp_ma] = array(
'sp_ma' => $sp_ma,
'sp_ten' => $sp_ten,
'soluong' => $soluong,
'gia' => $gia,
'thanhtien' => ($soluong * $gia),
'hinhdaidien' => $hinhdaidien
);
// lưu dữ liệu giỏ hàng vào session
$_SESSION['giohangdata'] = $data;
} else { // Nếu khách hàng đặt hàng sản phẩm chưa có trong giỏ hàng => thêm vào
$data[$sp_ma] = array(
'sp_ma' => $sp_ma,
'sp_ten' => $sp_ten,
'soluong' => $soluong,
'gia' => $gia,
'thanhtien' => ($soluong * $gia),
'hinhdaidien' => $hinhdaidien
);
// lưu dữ liệu giỏ hàng vào session
$_SESSION['giohangdata'] = $data;
}
// 4. Chuyển đổi dữ liệu về định dạng JSON
// Dữ liệu JSON, từ array PHP -> JSON
echo json_encode($_SESSION['giohangdata']);
Step 2: tạo API xóa Sản phẩm trong Giỏ hàng Session
- Tạo file
frontend/api/giohang-xoasanpham.php
<?php
// hàm `session_id()` sẽ trả về giá trị SESSION_ID (tên file session do Web Server tự động tạo)
// - Nếu trả về Rỗng hoặc NULL => chưa có file Session tồn tại
if (session_id() === '') {
// Yêu cầu Web Server tạo file Session để lưu trữ giá trị tương ứng với CLIENT (Web Browser đang gởi Request)
session_start();
}
// Truy vấn database để lấy danh sách
// 1. Include file cấu hình kết nối đến database, khởi tạo kết nối $conn
include_once(__DIR__ . '/../../dbconnect.php');
// Lấy thông tin người dùng gởi đến
$sp_ma = $_POST['sp_ma'];
// 2. Lưu trữ giỏ hàng trong session
// Nếu khách hàng đặt hàng cùng sản phẩm đã có trong giỏ hàng => cập nhật lại Số lượng, Thành tiền
if (isset($_SESSION['giohangdata'])) {
$data = $_SESSION['giohangdata'];
if(isset($data[$sp_ma])) {
unset($data[$sp_ma]);
}
// lưu dữ liệu giỏ hàng vào session
$_SESSION['giohangdata'] = $data;
}
// 3. Chuyển đổi dữ liệu về định dạng JSON
// Dữ liệu JSON, từ array PHP -> JSON
echo json_encode($_SESSION['giohangdata']);
Step 3: tạo API cập nhật Sản phẩm trong Giỏ hàng Session
- Tạo file
frontend/api/giohang-capnhatsanpham.php
<?php
// hàm `session_id()` sẽ trả về giá trị SESSION_ID (tên file session do Web Server tự động tạo)
// - Nếu trả về Rỗng hoặc NULL => chưa có file Session tồn tại
if (session_id() === '') {
// Yêu cầu Web Server tạo file Session để lưu trữ giá trị tương ứng với CLIENT (Web Browser đang gởi Request)
session_start();
}
// Truy vấn database để lấy danh sách
// 1. Include file cấu hình kết nối đến database, khởi tạo kết nối $conn
include_once(__DIR__ . '/../../dbconnect.php');
// 2. Lấy thông tin người dùng gởi đến
$sp_ma = $_POST['sp_ma'];
$soluong = $_POST['soluong'];
// 3. Lưu trữ giỏ hàng trong session
// Nếu khách hàng đặt hàng cùng sản phẩm đã có trong giỏ hàng => cập nhật lại Số lượng, Thành tiền
if (isset($_SESSION['giohangdata'])) {
$data = $_SESSION['giohangdata'];
$sanphamcu = $data[$sp_ma];
$data[$sp_ma] = array(
'sp_ma' => $sanphamcu['sp_ma'],
'sp_ten' => $sanphamcu['sp_ten'],
'soluong' => $soluong,
'gia' => $sanphamcu['gia'],
'thanhtien' => ($soluong * $sanphamcu['gia']),
'hinhdaidien' => $sanphamcu['hinhdaidien']
);
// lưu dữ liệu giỏ hàng vào session
$_SESSION['giohangdata'] = $data;
}
// 4. Chuyển đổi dữ liệu về định dạng JSON
// Dữ liệu JSON, từ array PHP -> JSON
echo json_encode($_SESSION['giohangdata']);
Step 4: Tạo giao diện Trang chi tiết sản phẩm
- Tạo file
/frontend/sanpham/detail.php
- Nội dung file:
<?php
// hàm `session_id()` sẽ trả về giá trị SESSION_ID (tên file session do Web Server tự động tạo)
// - Nếu trả về Rỗng hoặc NULL => chưa có file Session tồn tại
if (session_id() === '') {
// Yêu cầu Web Server tạo file Session để lưu trữ giá trị tương ứng với CLIENT (Web Browser đang gởi Request)
session_start();
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NenTang.vn</title>
<!-- Nhúng file Quản lý các Liên kết CSS dùng chung cho toàn bộ trang web -->
<?php include_once(__DIR__ . '/../layouts/styles.php'); ?>
<link href="/php/myhand/assets/frontend/css/style.css" type="text/css" rel="stylesheet" />
<style>
body {
font-family: 'open sans';
overflow-x: hidden;
}
img {
max-width: 100%;
}
.preview {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
@media screen and (max-width: 996px) {
.preview {
margin-bottom: 20px;
}
}
.preview-pic {
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-height: 300px;
}
.preview-thumbnail.nav-tabs {
border: none;
margin-top: 15px;
}
.preview-thumbnail.nav-tabs li {
width: 18%;
margin-right: 2.5%;
}
.preview-thumbnail.nav-tabs li img {
max-width: 100%;
display: block;
}
.preview-thumbnail.nav-tabs li a {
padding: 0;
margin: 0;
}
.preview-thumbnail.nav-tabs li:last-of-type {
margin-right: 0;
}
.tab-content {
overflow: hidden;
}
.tab-content img {
width: 100%;
-webkit-animation-name: opacity;
animation-name: opacity;
-webkit-animation-duration: .3s;
animation-duration: .3s;
}
.card {
margin-top: 50px;
background: #eee;
padding: 3em;
line-height: 1.5em;
}
@media screen and (min-width: 997px) {
.wrapper {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
}
.details {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
.colors {
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
-ms-flex-positive: 1;
flex-grow: 1;
}
.product-title,
.price,
.sizes,
.colors {
text-transform: UPPERCASE;
font-weight: bold;
}
.checked,
.price span {
color: #ff9f1a;
}
.product-title,
.rating,
.product-description,
.price,
.vote,
.sizes {
margin-bottom: 15px;
}
.product-title {
margin-top: 0;
}
.size {
margin-right: 10px;
}
.size:first-of-type {
margin-left: 40px;
}
.color {
display: inline-block;
vertical-align: middle;
margin-right: 10px;
height: 2em;
width: 2em;
border-radius: 2px;
}
.color:first-of-type {
margin-left: 20px;
}
.add-to-cart,
.like {
background: #ff9f1a;
padding: 1.2em 1.5em;
border: none;
text-transform: UPPERCASE;
font-weight: bold;
color: #fff;
-webkit-transition: background .3s ease;
transition: background .3s ease;
}
.add-to-cart:hover,
.like:hover {
background: #b36800;
color: #fff;
}
.not-available {
text-align: center;
line-height: 2em;
}
.not-available:before {
font-family: fontawesome;
content: "\f00d";
color: #fff;
}
.orange {
background: #ff9f1a;
}
.green {
background: #85ad00;
}
.blue {
background: #0076ad;
}
.tooltip-inner {
padding: 1.3em;
}
@-webkit-keyframes opacity {
0% {
opacity: 0;
-webkit-transform: scale(3);
transform: scale(3);
}
100% {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1);
}
}
@keyframes opacity {
0% {
opacity: 0;
-webkit-transform: scale(3);
transform: scale(3);
}
100% {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1);
}
}
</style>
</head>
<body class="d-flex flex-column h-100">
<!-- header -->
<?php include_once(__DIR__ . '/../layouts/partials/header.php'); ?>
<!-- end header -->
<main role="main" class="mb-2">
<!-- Block content -->
<?php
// Hiển thị tất cả lỗi trong PHP
// Chỉ nên hiển thị lỗi khi đang trong môi trường Phát triển (Development)
// Không nên hiển thị lỗi trên môi trường Triển khai (Production)
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// Truy vấn database
// 1. Include file cấu hình kết nối đến database, khởi tạo kết nối $conn
include_once(__DIR__ . '/../../dbconnect.php');
/* ---
--- 2.Truy vấn dữ liệu Sản phẩm
--- Lấy giá trị khóa chính được truyền theo dạng QueryString Parameter key1=value1&key2=value2...
---
*/
$sp_ma = $_GET['sp_ma'];
$sqlSelectSanPham = <<<EOT
SELECT sp.sp_ma, sp.sp_ten, sp.sp_gia, sp.sp_giacu, sp.sp_mota_ngan, sp.sp_mota_chitiet, sp.sp_soluong, lsp.lsp_ten
FROM `sanpham` sp
JOIN `loaisanpham` lsp ON sp.lsp_ma = lsp.lsp_ma
WHERE sp.sp_ma = $sp_ma
EOT;
// Thực thi câu truy vấn SQL để lấy về dữ liệu ban đầu của record
$resultSelectSanPham = mysqli_query($conn, $sqlSelectSanPham);
// Khi thực thi các truy vấn dạng SELECT, dữ liệu lấy về cần phải phân tích để sử dụng
// Thông thường, chúng ta sẽ sử dụng vòng lặp while để duyệt danh sách các dòng dữ liệu được SELECT
// Ta sẽ tạo 1 mảng array để chứa các dữ liệu được trả về
$sanphamRow;
while ($row = mysqli_fetch_array($resultSelectSanPham, MYSQLI_ASSOC)) {
$sanphamRow = array(
'sp_ma' => $row['sp_ma'],
'sp_ten' => $row['sp_ten'],
'sp_gia' => $row['sp_gia'],
'sp_gia_formated' => number_format($row['sp_gia'], 2, ".", ",") . ' vnđ',
'sp_giacu_formated' => number_format($row['sp_giacu'], 2, ".", ",") . ' vnđ',
'sp_mota_ngan' => $row['sp_mota_ngan'],
'sp_mota_chitiet' => $row['sp_mota_chitiet'],
'sp_soluong' => $row['sp_soluong'],
'lsp_ten' => $row['lsp_ten']
);
}
/* --- End Truy vấn dữ liệu Sản phẩm --- */
/* ---
--- 3.Truy vấn dữ liệu Hình ảnh Sản phẩm
---
*/
$sqlSelect = <<<EOT
SELECT hsp.hsp_ma, hsp.hsp_tentaptin
FROM `hinhsanpham` hsp
WHERE hsp.sp_ma = $sp_ma
EOT;
// Thực thi câu truy vấn SQL để lấy về dữ liệu ban đầu của record
$result = mysqli_query($conn, $sqlSelect);
// Khi thực thi các truy vấn dạng SELECT, dữ liệu lấy về cần phải phân tích để sử dụng
// Thông thường, chúng ta sẽ sử dụng vòng lặp while để duyệt danh sách các dòng dữ liệu được SELECT
// Ta sẽ tạo 1 mảng array để chứa các dữ liệu được trả về
$danhsachhinhanh = [];
while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
$danhsachhinhanh[] = array(
'hsp_ma' => $row['hsp_ma'],
'hsp_tentaptin' => $row['hsp_tentaptin']
);
}
/* --- End Truy vấn dữ liệu Hình ảnh sản phẩm --- */
// Hiệu chỉnh dữ liệu theo cấu trúc để tiện xử lý
$sanphamRow['danhsachhinhanh'] = $danhsachhinhanh;
?>
<div class="container mt-4">
<!-- Vùng ALERT hiển thị thông báo -->
<div id="alert-container" class="alert alert-warning alert-dismissible fade d-none" role="alert">
<div id="thongbao"> </div>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="card">
<div class="container-fliud">
<form name="frmsanphamchitiet" id="frmsanphamchitiet" method="post" action="">
<?php
$hinhsanphamdautien = empty($sanphamRow['danhsachhinhanh'][0]) ? '' : $sanphamRow['danhsachhinhanh'][0];
?>
<input type="hidden" name="sp_ma" id="sp_ma" value="<?= $sanphamRow['sp_ma'] ?>" />
<input type="hidden" name="sp_ten" id="sp_ten" value="<?= $sanphamRow['sp_ten'] ?>" />
<input type="hidden" name="sp_gia" id="sp_gia" value="<?= $sanphamRow['sp_gia'] ?>" />
<input type="hidden" name="hinhdaidien" id="hinhdaidien" value="<?= empty($hinhsanphamdautien) ? '' : $hinhsanphamdautien['hsp_tentaptin'] ?>" />
<div class="wrapper row">
<div class="preview col-md-6">
<!-- Nếu có hình sản phẩm nào => duyệt vòng lặp để hiển thị các hình ảnh -->
<?php if (count($sanphamRow['danhsachhinhanh']) > 0) : ?>
<div class="preview-pic tab-content">
<?php foreach ($sanphamRow['danhsachhinhanh'] as $hinhsanpham) : ?>
<div class="tab-pane <?= ($hinhsanpham == $hinhsanphamdautien) ? 'active' : '' ?>" id="pic-<?= $hinhsanpham['hsp_ma'] ?>">
<img src="/php/myhand/assets/uploads/products/<?= $hinhsanpham['hsp_tentaptin'] ?>" />
</div>
<?php endforeach; ?>
</div>
<ul class="preview-thumbnail nav nav-tabs">
<?php foreach ($sanphamRow['danhsachhinhanh'] as $hinhsanpham) : ?>
<li class="<?= ($hinhsanpham == $hinhsanphamdautien) ? 'active' : '' ?>">
<a data-target="#pic-<?= $hinhsanpham['hsp_ma'] ?>" data-toggle="tab">
<img src="/php/myhand/assets/uploads/products/<?= $hinhsanpham['hsp_tentaptin'] ?>" />
</a>
</li>
<?php endforeach; ?>
</ul>
<!-- Không có hình sản phẩm nào => lấy ảnh mặc định -->
<?php else : ?>
<div class="preview-pic tab-content">
<div class="tab-pane active" id="pic-1">
<img src="/php/myhand/assets/shared/img/default-image_600.png" />
</div>
</div>
<ul class="preview-thumbnail nav nav-tabs">
<li class="active">
<a data-target="#pic-1" data-toggle="tab">
<img src="/php/myhand/assets/shared/img/default-image_600.png" />
</a>
</li>
</ul>
<?php endif; ?>
</div>
<div class="details col-md-6">
<h3 class="product-title"><?= $sanphamRow['sp_ten'] ?></h3>
<div class="rating">
<div class="stars">
<span class="fa fa-star checked"></span>
<span class="fa fa-star checked"></span>
<span class="fa fa-star checked"></span>
<span class="fa fa-star"></span>
<span class="fa fa-star"></span>
</div>
<span class="review-no">999 đánh giá</span>
</div>
<p class="product-description"><?= $sanphamRow['sp_mota_ngan'] ?></p>
<small class="text-muted">Giá cũ: <s><span><?= $sanphamRow['sp_giacu_formated'] ?></span></s></small>
<h4 class="price">Giá hiện tại: <span><?= $sanphamRow['sp_gia_formated'] ?></span></h4>
<p><?= $sanphamRow['sp_mota_ngan'] ?></p>
<p class="vote"><strong>100%</strong> hàng <strong>Chất lượng</strong>, đảm bảo <strong>Uy
tín</strong>!</p>
<h5 class="sizes">sizes:
<span class="size" data-toggle="tooltip" title="cỡ Nhỏ">s</span>
<span class="size" data-toggle="tooltip" title="cỡ Trung bình">m</span>
<span class="size" data-toggle="tooltip" title="cỡ Lớn">l</span>
<span class="size" data-toggle="tooltip" title="cỡ Đại">xl</span>
</h5>
<h5 class="colors">colors:
<span class="color orange not-available" data-toggle="tooltip" title="Hết hàng"></span>
<span class="color green"></span>
<span class="color blue"></span>
</h5>
<div class="form-group">
<label for="soluong">Số lượng đặt mua:</label>
<input type="number" class="form-control" id="soluong" name="soluong">
</div>
<div class="action">
<a class="add-to-cart btn btn-default" id="btnThemVaoGioHang">Thêm vào giỏ hàng</a>
<a class="like btn btn-default" href="#"><span class="fa fa-heart"></span></a>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="card">
<div class="container-fluid">
<h3>Thông tin chi tiết về Sản phẩm</h3>
<div class="row">
<div class="col">
<?= $sanphamRow['sp_mota_chitiet'] ?>
</div>
</div>
</div>
</div>
<!-- End block content -->
</main>
<!-- footer -->
<?php include_once(__DIR__ . '/../layouts/partials/footer.php'); ?>
<!-- end footer -->
<!-- Nhúng file quản lý phần SCRIPT JAVASCRIPT -->
<?php include_once(__DIR__ . '/../layouts/scripts.php'); ?>
<!-- Các file Javascript sử dụng riêng cho trang này, liên kết tại đây -->
<script>
function addSanPhamVaoGioHang() {
// Chuẩn bị dữ liệu gởi
var dulieugoi = {
sp_ma: $('#sp_ma').val(),
sp_ten: $('#sp_ten').val(),
sp_gia: $('#sp_gia').val(),
hinhdaidien: $('#hinhdaidien').val(),
soluong: $('#soluong').val(),
};
// console.log((dulieugoi));
// Gọi AJAX đến API ở URL `/php/myhand/frontend/api/giohang-themsanpham.php`
$.ajax({
url: '/php/myhand/frontend/api/giohang-themsanpham.php',
method: "POST",
dataType: 'json',
data: dulieugoi,
success: function(data) {
console.log(data);
var htmlString =
`Sản phẩm đã được thêm vào Giỏ hàng. <a href="/php/myhand/frontend/thanhtoan/giohang.php">Xem Giỏ hàng</a>.`;
$('#thongbao').html(htmlString);
// Hiện thông báo
$('.alert').removeClass('d-none').addClass('show');
},
error: function(jqXHR, textStatus, errorThrown) {
console.log(textStatus, errorThrown);
var htmlString = `<h1>Không thể xử lý</h1>`;
$('#thongbao').html(htmlString);
// Hiện thông báo
$('.alert').removeClass('d-none').addClass('show');
}
});
};
// Đăng ký sự kiện cho nút Thêm vào giỏ hàng
$('#btnThemVaoGioHang').click(function(event) {
event.preventDefault();
addSanPhamVaoGioHang();
});
</script>
</body>
</html>
Hướng dẫn
Đoạn code bắt buộc phải có để có thể sử dụng SESSION trong PHP
Hướng dẫn
Lấy dữ liệu từ người dùng gởi đến qua REQUEST GET
|