基于MVC的MySQL分页查询问题:传递页码与分类ID
问题解决指南:MVC分页+分类查询的常见问题修复
看起来你在MVC架构下实现商品分页和分类查询时遇到了几个典型问题,我来一步步帮你解决:
1. 修复LIMIT查询无数据返回的问题
你的当前代码有两个核心问题导致无数据:
- SQL参数拼接的风险与类型问题:直接把
$arithmetic拼进SQL语句,即使$pn是整数,PDO默认会把它当作字符串处理,可能导致MySQL解析LIMIT参数出错。应该用参数绑定并指定整数类型。 - 总数量计算错误:你用
count($products)获取总商品数,但这只是当前页的商品数量,不是整个分类的总数量,会导致分页逻辑完全错误(比如如果当前页没数据,$total为0,分页页码直接消失)。
修正后的Model函数
// 获取分页商品列表,支持排序 function get_products_by_category($category_id, $pn, $per_page = 8, $sort_by = 'productID', $sort_order = 'ASC') { global $db; // 白名单验证排序字段,防止SQL注入 $allowed_sort_fields = ['productID', 'productName', 'price', 'categoryID']; $sort_by = in_array($sort_by, $allowed_sort_fields) ? $sort_by : 'productID'; $sort_order = strtoupper($sort_order) === 'DESC' ? 'DESC' : 'ASC'; $offset = ($pn - 1) * $per_page; // 使用参数绑定LIMIT的偏移量和每页数量,指定整数类型 $query = "SELECT * FROM products WHERE products.categoryID = :category_id ORDER BY $sort_by $sort_order LIMIT :offset, :per_page"; $statement = $db->prepare($query); $statement->bindValue(":category_id", $category_id, PDO::PARAM_INT); $statement->bindValue(":offset", $offset, PDO::PARAM_INT); $statement->bindValue(":per_page", $per_page, PDO::PARAM_INT); $statement->execute(); $products = $statement->fetchAll(); $statement->closeCursor(); return $products; } // 获取分类下的总商品数,用于计算分页 function get_total_products_by_category($category_id) { global $db; $query = "SELECT COUNT(*) FROM products WHERE categoryID = :category_id"; $statement = $db->prepare($query); $statement->bindValue(":category_id", $category_id, PDO::PARAM_INT); $statement->execute(); $total = $statement->fetchColumn(); $statement->closeCursor(); return $total; }
2. 修复分页链接同时传递page_number和category_id的问题
你的分页链接有两个错误:
- URL参数格式错误:用了
&?category_id,正确的参数连接只需要&,不需要重复加? - 错误使用循环变量:
$category['categoryID']是分类循环结束后的最后一个分类ID,应该用当前选中的分类ID
修正后的Controller代码(关键部分)
// 定义每页数量,避免硬编码 define('PER_PAGE', 8); if ($action == 'list_products') { $category_id = filter_input(INPUT_GET, 'category_id', FILTER_VALIDATE_INT); if ($category_id == NULL || $category_id == FALSE) { $category_id = 1; } // 获取总商品数 $total_products = get_total_products_by_category($category_id); // 获取当前页商品 $products = get_products_by_category($category_id, $pn, PER_PAGE); // 计算总页数(用ceil向上取整,避免小数页码) $total_page = ceil($total_products / PER_PAGE); // 确保页码不超出范围 if ($pn > $total_page && $total_page > 0) { $pn = $total_page; $products = get_products_by_category($category_id, $pn, PER_PAGE); } // 把当前分类ID传递给视图 $current_category = $category_id; include('product_list.php'); }
修正后的视图分页链接
<section> <?php if ($total_page > 1): ?> <?php for($i = 1; $i <= $total_page; $i++) { // 用http_build_query自动拼接参数,避免手动拼接出错 $params = http_build_query([ 'page_number' => $i, 'category_id' => $current_category ]); ?> <a href="?<?php echo $params; ?>"><?php echo $i; ?></a> <?php } ?> <?php endif; ?> </section>
3. 避免硬编码与多查询函数的优化
- 硬编码页面/数量:用
define('PER_PAGE', 8)定义每页数量,后续修改只需要改这一处;视图里的分页逻辑通过$total_page动态生成,不需要硬编码页码。 - 多查询函数问题:给Model函数添加可选的排序参数(
$sort_by和$sort_order),并通过白名单验证防止SQL注入,这样同一个函数可以支持不同的排序需求,不需要创建多个查询函数。
如果需要添加排序功能,只需要在Controller里获取排序参数并传递给Model:
// Controller里添加排序参数获取 $sort_by = filter_input(INPUT_GET, 'sort', FILTER_SANITIZE_STRING); $sort_order = filter_input(INPUT_GET, 'order', FILTER_SANITIZE_STRING); // 调用Model时传递参数 $products = get_products_by_category($category_id, $pn, PER_PAGE, $sort_by, $sort_order);
然后在视图里添加排序链接:
<!-- 示例:按价格排序的链接 --> <a href="?<?php echo http_build_query([ 'category_id' => $current_category, 'page_number' => $pn, 'sort' => 'price', 'order' => $sort_order === 'ASC' ? 'DESC' : 'ASC' ]); ?>"> 按价格 <?php echo $sort_order === 'ASC' ? '降序' : '升序'; ?> </a>
内容的提问来源于stack exchange,提问作者MuscleSenpai
相关产品推荐
相关产品推荐

