Step 1: tạo file xử lý Logic trang Tìm kiếm Sản phẩm
- Tạo file
frontend/product/search.php
<?php
// Include file cấu hình ban đầu của `Twig`
require_once __DIR__ . '/../../bootstrap.php';
// 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.Truy vấn dữ liệu Loại Sản phẩm
---
*/
$sqlSelectLoaiSanPham = <<<EOT
SELECT lsp.lsp_ma, lsp.lsp_ten, COUNT(*) soluongsanpham
FROM `loaisanpham` lsp
LEFT JOIN `sanpham` sp ON lsp.lsp_ma = sp.lsp_ma
GROUP BY lsp.lsp_ma, lsp.lsp_ten
EOT;
// Thực thi câu truy vấn SQL để lấy về dữ liệu ban đầu của record
$resultSelectLoaiSanPham = mysqli_query($conn, $sqlSelectLoaiSanPham);
// 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ề
$loaisanphamData = [];
while ($row = mysqli_fetch_array($resultSelectLoaiSanPham, MYSQLI_ASSOC)) {
$loaisanphamData[] = array(
'lsp_ma' => $row['lsp_ma'],
'lsp_ten' => $row['lsp_ten'],
'soluongsanpham' => $row['soluongsanpham'],
);
}
/* --- End Truy vấn dữ liệu Loại Sản phẩm --- */
/* ---
--- 3.Truy vấn dữ liệu Nhà sản xuất
---
*/
$sqlSelectNhaSanXuat = <<<EOT
SELECT nsx.nsx_ma, nsx.nsx_ten, COUNT(*) soluongsanpham
FROM `nhasanxuat`nsx
LEFT JOIN `sanpham` sp ON nsx.nsx_ma = sp.nsx_ma
GROUP BY nsx.nsx_ma, nsx.nsx_ten
EOT;
// Thực thi câu truy vấn SQL để lấy về dữ liệu ban đầu của record
$resultSelectNhaSanXuat = mysqli_query($conn, $sqlSelectNhaSanXuat);
// 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ề
$nhasanxuatData = [];
while ($row = mysqli_fetch_array($resultSelectNhaSanXuat, MYSQLI_ASSOC)) {
$nhasanxuatData[] = array(
'nsx_ma' => $row['nsx_ma'],
'nsx_ten' => $row['nsx_ten'],
'soluongsanpham' => $row['soluongsanpham'],
);
}
/* --- End Truy vấn dữ liệu Nhà sản xuất --- */
/* ---
--- 4.Truy vấn dữ liệu Khuyến mãi
---
*/
$sqlSelectKhuyenMai = <<<EOT
SELECT km.km_ma, km.km_ten, km_noidung, km_tungay, km_denngay, COUNT(*) soluongsanpham
FROM `khuyenmai` km
LEFT JOIN `sanpham` sp ON km.km_ma = sp.km_ma
GROUP BY km.km_ma, km.km_ten, km_noidung, km_tungay, km_denngay
EOT;
// Thực thi câu truy vấn SQL để lấy về dữ liệu ban đầu của record
$resultSelectKhuyenMai = mysqli_query($conn, $sqlSelectKhuyenMai);
// 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ề
$khuyenmaiData = [];
while ($row = mysqli_fetch_array($resultSelectKhuyenMai, MYSQLI_ASSOC)) {
$khuyenmaiData[] = array(
'km_ma' => $row['km_ma'],
'km_ten' => $row['km_ten'],
'km_noidung' => $row['km_noidung'],
'km_tungay' => $row['km_tungay'],
'km_denngay' => $row['km_denngay'],
'soluongsanpham' => $row['soluongsanpham'],
);
}
/* --- End Truy vấn dữ liệu Nhà sản xuất --- */
/* ---
--- 5.Truy vấn dữ liệu Sản phẩm theo keyword tìm kiếm
---
*/
// Giữ lại keyword mà người dùng tìm kiếm
$keyword_tensanpham = isset($_GET['keyword_tensanpham']) ? $_GET['keyword_tensanpham'] : '';
$keyword_loaisanpham = isset($_GET['keyword_loaisanpham']) ? $_GET['keyword_loaisanpham'] : [];
$keyword_nhasanxuat = isset($_GET['keyword_nhasanxuat']) ? $_GET['keyword_nhasanxuat'] : [];
$keyword_khuyenmai = isset($_GET['keyword_khuyenmai']) ? $_GET['keyword_khuyenmai'] : [];
$keyword_sotientu = isset($_GET['keyword_sotientu']) ? $_GET['keyword_sotientu'] : 0;
$keyword_sotienden = isset($_GET['keyword_sotienden']) ? $_GET['keyword_sotienden'] : 50000000;
// Câu lệnh query động tùy theo yêu cầu tìm kiếm của người dùng
$sqlDanhSachSanPham = <<<EOT
SELECT sp.sp_ma, sp.sp_ten, sp.sp_gia, sp.sp_giacu, sp.sp_mota_ngan, sp.sp_soluong, lsp.lsp_ten, MAX(hsp.hsp_tentaptin) AS hsp_tentaptin
FROM `sanpham` sp
JOIN `loaisanpham` lsp ON sp.lsp_ma = lsp.lsp_ma
LEFT JOIN `hinhsanpham` hsp ON sp.sp_ma = hsp.sp_ma
LEFT JOIN `nhasanxuat` nsx ON sp.nsx_ma = nsx.nsx_ma
LEFT JOIN `khuyenmai` km ON sp.km_ma = km.km_ma
EOT;
// Tìm theo tên sản phẩm
$sqlWhereArr = [];
if (!empty($keyword_tensanpham)) {
$sqlWhereArr[] = "sp.sp_ten LIKE '%$keyword_tensanpham%'";
}
// Tìm theo loại sản phẩm
if (!empty($keyword_loaisanpham)) {
$value = implode(',', $keyword_loaisanpham);
$sqlWhereArr[] = "lsp.lsp_ma IN ($value)";
}
// Tìm theo nhà sản xuất
if (!empty($keyword_nhasanxuat)) {
$value = implode(',', $keyword_nhasanxuat);
$sqlWhereArr[] = "nsx.nsx_ma IN ($value)";
}
// Tìm theo khuyến mãi
if (!empty($keyword_khuyenmai)) {
$value = implode(',', $keyword_khuyenmai);
$sqlWhereArr[] = "km.km_ma IN ($value)";
}
// Tìm theo khoảng giá tiền
if (!empty($keyword_sotientu) && !empty($keyword_sotienden)) {
$sqlWhereArr[] = "sp.sp_gia BETWEEN $keyword_sotientu AND $keyword_sotienden";
}
// Câu lệnh cuối cùng
if (count($sqlWhereArr) > 0) {
$sqlWhere = "WHERE " . implode(' AND ', $sqlWhereArr);
$sqlDanhSachSanPham .= $sqlWhere;
}
$sqlDanhSachSanPham .= <<<EOT
GROUP BY sp.sp_ma, sp.sp_ten, sp.sp_gia, sp.sp_giacu, sp.sp_mota_ngan, sp.sp_soluong, lsp.lsp_ten
EOT;
// Thực thi câu truy vấn SQL để lấy về dữ liệu
$result = mysqli_query($conn, $sqlDanhSachSanPham);
// 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ề
$dataDanhSachSanPham = [];
while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
$dataDanhSachSanPham[] = array(
'sp_ma' => $row['sp_ma'],
'sp_ten' => $row['sp_ten'],
'sp_gia' => number_format($row['sp_gia'], 2, ".", ",") . ' vnđ',
'sp_giacu' => number_format($row['sp_giacu'], 2, ".", ","),
'sp_mota_ngan' => $row['sp_mota_ngan'],
'sp_soluong' => $row['sp_soluong'],
'lsp_ten' => $row['lsp_ten'],
'hsp_tentaptin' => $row['hsp_tentaptin'],
);
}
// dd($sqlWhereArr, $sqlWhere, $sqlDanhSachSanPham, $dataDanhSachSanPham);
// Yêu cầu `Twig` vẽ giao diện được viết trong file `frontend/product/search.html.twig`
echo $twig->render(
'frontend/product/search.html.twig',
[
// Danh mục tiêu chí tìm kiếm
'danhsachloaisanpham' => $loaisanphamData,
'danhsachnhasanxuat' => $nhasanxuatData,
'danhsachkhuyenmai' => $khuyenmaiData,
'danhsachsanpham' => $dataDanhSachSanPham,
// Keyword người dùng đã tìm kiếm
'keyword_tensanpham' => $keyword_tensanpham,
'keyword_loaisanpham' => $keyword_loaisanpham,
'keyword_nhasanxuat' => $keyword_nhasanxuat,
'keyword_khuyenmai' => $keyword_khuyenmai,
'keyword_sotientu' => $keyword_sotientu,
'keyword_sotienden' => $keyword_sotienden,
]
);
Step 2: tạo template giao diện trang Tìm kiếm
- Tạo file
templates/frontend/product/search.html.twig
{# Kế thừa layout frontend #}
{% extends "frontend/layouts/layout.html.twig" %}
{# Nội dung trong block title #}
{% block title %}
Liên hệ
{% endblock %}
{# End Nội dung trong block title #}
{# Nội dung trong block headline #}
{% block headline %}
Liên hệ
{% endblock %}
{# End Nội dung trong block headline #}
{# Nội dung trong block content #}
{% block content %}
<div class="container mt-4">
<form name="frmTimKiem" method="get" action="/project-nentang/frontend/product/search.php">
<h1 class="text-center">Tìm kiếm sản phẩm</h1>
<div class="row">
<div class="col col-md-12">
<h5 class="text-center">Cung cấp kiến thức nền tảng về Lập trình, Thiết kế Web, Cơ sở dữ liệu</h5>
<h5 class="text-center">Giúp các bạn có niềm tin, hành trang kiến thức vững vàng trên con đường trở
thành Nhà phát triển Phần mềm</h5>
<div class="text-center">
<button type="button" id="btnReset" class="btn btn-warning">Xóa bộ lọc</button>
<button class="btn btn-primary btn-lg">Tìm kiếm <i class="fa fa-forward"
aria-hidden="true"></i></button>
</div>
</div>
</div>
<div class="row">
<aside class="col-sm-4">
<p>Bộ lọc </p>
<div class="card">
<!-- Tìm kiếm theo tên sản phẩm -->
<article class="card-group-item">
<header class="card-header">
<h6 class="title">Tên sản phẩm </h6>
</header>
<div class="filter-content">
<div class="card-body">
<input class="form-control" type="text" placeholder="Tìm kiếm" aria-label="Search"
name="keyword_tensanpham"
value="{{ keyword_tensanpham ? keyword_tensanpham : '' }}">
</div> <!-- card-body.// -->
</div>
</article> <!-- // Tìm kiếm theo Tên sản phẩm -->
<!-- Tìm kiếm theo Loại sản phẩm -->
<article class="card-group-item">
<header class="card-header">
<h6 class="title">Loại sản phẩm </h6>
</header>
<div class="filter-content">
<div class="card-body">
{% for loaisanpham in danhsachloaisanpham %}
<div class="custom-control custom-checkbox">
<span
class="float-right badge badge-light round">{{ loaisanpham.soluongsanpham }}</span>
<input type="checkbox" class="custom-control-input" name="keyword_loaisanpham[]"
value="{{ loaisanpham.lsp_ma }}" id="chk-loaisanpham-{{ loaisanpham.lsp_ma }}"
{{ (loaisanpham.lsp_ma in keyword_loaisanpham) ? 'checked' : '' }}>
<label class="custom-control-label"
for="chk-loaisanpham-{{ loaisanpham.lsp_ma }}">{{ loaisanpham.lsp_ten }}</label>
</div> <!-- form-check.// -->
{% endfor %}
</div> <!-- card-body.// -->
</div>
</article> <!-- // Tìm kiếm theo Loại sản phẩm -->
<!-- Tìm kiếm theo Nhà sản xuất -->
<article class="card-group-item">
<header class="card-header">
<h6 class="title">Nhà sản xuất </h6>
</header>
<div class="filter-content">
<div class="card-body">
{% for nhasanxuat in danhsachnhasanxuat %}
<div class="custom-control custom-checkbox">
<span
class="float-right badge badge-light round">{{ nhasanxuat.soluongsanpham }}</span>
<input type="checkbox" class="custom-control-input" name="keyword_nhasanxuat[]"
value="{{ nhasanxuat.nsx_ma }}" id="chk-nhasanxuat-{{ nhasanxuat.nsx_ma }}"
{{ (nhasanxuat.nsx_ma in keyword_nhasanxuat) ? 'checked' : '' }}>
<label class="custom-control-label"
for="chk-nhasanxuat-{{ nhasanxuat.nsx_ma }}">{{ nhasanxuat.nsx_ten }}</label>
</div> <!-- form-check.// -->
{% endfor %}
</div> <!-- card-body.// -->
</div>
</article> <!-- // Tìm kiếm theo Nhà sản xuất -->
<!-- Tìm kiếm theo Khuyến mãi -->
<article class="card-group-item">
<header class="card-header">
<h6 class="title">Khuyến mãi </h6>
</header>
<div class="filter-content">
<div class="card-body">
{% for khuyenmai in danhsachkhuyenmai %}
<div class="custom-control custom-checkbox">
<span
class="float-right badge badge-light round">{{ khuyenmai.soluongsanpham }}</span>
<input type="checkbox" class="custom-control-input" name="keyword_khuyenmai[]"
value="{{ khuyenmai.km_ma }}" id="chk-khuyenmai-{{ khuyenmai.km_ma }}"
{{ (khuyenmai.km_ma in keyword_khuyenmai) ? 'checked' : '' }}>
<label class="custom-control-label"
for="chk-khuyenmai-{{ khuyenmai.km_ma }}">{{ khuyenmai.km_ten }}</label>
</div> <!-- form-check.// -->
{% endfor %}
</div> <!-- card-body.// -->
</div>
</article> <!-- // Tìm kiếm theo Nhà sản xuất -->
<!-- Tìm kiếm theo khoảng giá tiền -->
<article class="card-group-item">
<header class="card-header">
<h6 class="title">Khoảng tiền </h6>
</header>
<div class="filter-content">
<div class="card-body">
<div class="form-row">
<div class="form-group col-md-6">
<label>Từ</label>
<input type="range" class="custom-range" min="0" max="50000000" step="100000"
id="sotientu" name="keyword_sotientu"
value="{{ keyword_sotientu ? keyword_sotientu : 0 }}">
<span><span id="sotientu-text"></span></span>
</div>
<div class="form-group col-md-6 text-right">
<label>Đến</label>
<input type="range" class="custom-range" min="0" max="50000000" step="100000"
id="sotienden" name="keyword_sotienden"
value="{{ keyword_sotienden ? keyword_sotienden : 50000000 }}">
<span><span id="sotienden-text"></span></span>
</div>
</div>
</div> <!-- card-body.// -->
</div>
</article> <!-- // Tìm kiếm theo khoảng giá tiền -->
<!-- Tìm kiếm theo màu sắc sản phẩm -->
<article class="card-group-item">
<header class="card-header">
<h6 class="title">Màu sắc (tùy chọn thêm)</h6>
</header>
<div class="filter-content">
<div class="card-body">
<label class="btn btn-danger">
<input class="" type="checkbox" value="">
<span class="form-check-label">Đỏ</span>
</label>
<label class="btn btn-success">
<input class="" type="checkbox" value="">
<span class="form-check-label">Xanh lá</span>
</label>
<label class="btn btn-primary">
<input class="" type="checkbox" value="">
<span class="form-check-label">Xanh dương</span>
</label>
</div> <!-- card-body.// -->
</div>
</article> <!-- // Tìm kiếm theo màu sắc sản phẩm -->
</div> <!-- card.// -->
</aside> <!-- col.// -->
<!-- Giải thuật duyệt và render Danh sách sản phẩm theo dòng, cột của Bootstrap -->
{% set counter = 0 %}
{% set group = 2 %}
{% set limit = danhsachsanpham|length %}
{% set col_class_name = (12 / group) %}
<div class="col-sm-8 mt-2">
<div class="row">
<div class="col-md-12">
<h6>Tìm kiếm được {{ danhsachsanpham|length }} sản phẩm</h6>
</div>
</div>
<div class="row">
{% if danhsachsanpham|length >0 %}
{% for sanpham in danhsachsanpham %}
<div class="col-md-{{ col_class_name }}">
<div class="card mb-4 shadow-sm">
{% if sanpham.hsp_tentaptin %}
<a href="/project-nentang/frontend/sanpham/chitiet?sp_ma={{ sanpham.sp_ma }}">
<img class="bd-placeholder-img card-img-top" width="100%" height="350"
src="/project-nentang/assets/uploads/{{ sanpham.hsp_tentaptin }}" />
</a>
{% else %}
<a href="/project-nentang/frontend/sanpham/chitiet?sp_ma={{ sanpham.sp_ma }}">
<img class="bd-placeholder-img card-img-top" width="100%" height="350"
src="/project-nentang/assets/shared/img/default-image_600.png" />
</a>
{% endif %}
<div class="card-body">
<a href="/project-nentang/frontend/sanpham/chitiet?sp_ma={{ sanpham.sp_ma }}">
<h5>{{ sanpham.sp_ten }}</h5>
</a>
<h6>{{ sanpham.lsp_ten }}</h6>
<p class="card-text">{{ sanpham.sp_mota_ngan }}</p>
<div class="d-flex justify-content-between align-items-center">
<div class="btn-group">
<a class="btn btn-sm btn-outline-secondary"
href="/project-nentang/frontend/sanpham/chitiet?sp_ma={{ sanpham.sp_ma }}">Xem
chi tiết</a>
</div>
<small class="text-muted text-right">
<s>{{ sanpham.sp_giacu }}</s>
<b>{{ sanpham.sp_gia }}</b>
</small>
</div>
</div>
</div>
</div>
{% set counter = counter + 1 %}
{% if (counter % group == 0 and counter < limit) %}
</div>
<div class="row">
{% endif %}
{% endfor %}
{% else %}
<div class="col-md-12">
<h2>Xin lỗi, không tìm thấy sản phẩm nào theo yêu cầu!</h2>
</div>
{% endif %}
</div>
</div>
</div> <!-- row.// -->
</form>
</div>
{% endblock %}
{# End Nội dung trong block content #}
{% block customscripts %}
<script>
$(document).ready(function () {
$('#sotientu').on('change', function (e) {
var id = e.target.value;
document.getElementById("sotientu-text").innerHTML = id;
});
$('#sotientu').change();
$('#sotienden').on('change', function (e) {
var id = e.target.value;
document.getElementById("sotienden-text").innerHTML = id;
});
$('#sotienden').change();
function clearForm() {
var frm_elements = frmTimKiem.elements;
for (i = 0; i < frm_elements.length; i++) {
field_type = frm_elements[i].type.toLowerCase();
switch (field_type) {
case "text":
case "password":
case "textarea":
case "hidden":
frm_elements[i].value = "";
break;
case "radio":
case "checkbox":
if (frm_elements[i].checked) {
frm_elements[i].checked = false;
}
break;
case "select-one":
case "select-multi":
frm_elements[i].selectedIndex = -1;
break;
case "range":
if (frm_elements[i].name == 'keyword_sotientu') {
frm_elements[i].value = frm_elements[i].min;
document.getElementById("sotientu-text").innerHTML = frm_elements[i].min;
} else if (frm_elements[i].name == 'keyword_sotienden') {
frm_elements[i].value = frm_elements[i].max;
document.getElementById("sotienden-text").innerHTML = frm_elements[i].max;
}
break;
default:
break;
}
}
}
$('#btnReset').click(function (e) {
clearForm();
});
});
</script>
{% endblock %}
|