无限级分类知识点其实理解起来比较简单。因为在实际的项目中比如典型的如电商网站、一些CMS内容发布站点等都会涉及到无限级分类的知识。所以这篇文章准备用原生PHP代码来简单的现实一些典型的无限级分类。本次文章记录的是在实验楼这个网站上的一个实验经历,整理成自己的博文
实验环境PHP 7.0.12
CentOS7.4
MySQL 5.7
Web服务器就使用PHP内置的Server,直接在项目根目录下执行php -S 127.0.0.1:8080就可以,然后通过http://127.0.0.1:8080来进行访问即可。
代码仓库待补充(gitee)
实验介绍
本次介绍的无限级分类采用省市结构的方式来展示,如下图
最终的效果如下面图片所展示
创建数据库、表
首先我们建立一个简单的数据表,用来存放上面的省市结构数据。表结构SQL如下create database category;
CREATE TABLE `category` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自动增长id',
`pid` int(11) NOT NULL COMMENT '父id',
`category` varchar(255) NOT NULL COMMENT '分类名称',
`orderid` int(11) NOT NULL DEFAULT '0' COMMENT '排序id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
然后我们往表里初始化一些数据,方便页面显示。INSERT INTO `category` VALUES ('1', '0', '中国', '0');
INSERT INTO `category` VALUES ('2', '1', '河北', '0');
INSERT INTO `category` VALUES ('3', '1', '山西', '0');
INSERT INTO `category` VALUES ('4', '2', '石家庄', '0');
INSERT INTO `category` VALUES ('5', '2', '邯郸', '0');
INSERT INTO `category` VALUES ('6', '3', '太原', '0');
INSERT INTO `category` VALUES ('7', '3', '大同', '0');
INSERT INTO `category` VALUES ('8', '4', '桥东', '0');
INSERT INTO `category` VALUES ('9', '4', '桥西', '0');
INSERT INTO `category` VALUES ('10', '5', '邯山', '0');
INSERT INTO `category` VALUES ('11', '5', '丛台', '0');
INSERT INTO `category` VALUES ('12', '6', '小店', '0');
INSERT INTO `category` VALUES ('13', '6', '迎泽', '0');
INSERT INTO `category` VALUES ('14', '7', '南郊', '0');
INSERT INTO `category` VALUES ('15', '7', '新荣', '0');
数据库DB类
我们简单的封装一下DB类,以便于后面的整体复用。DB类我们采用单例的模式,以避免重复的创建数据库实例。
这里提一下单例模式3个要点要声明一个静态变量来存储这个实例
类的构造函数必须为私有
必须建立一个获取实例的方法
那么首先创建一个db.php,内容大致如下。<?php
class db
{
//私有变量保存实例
private static $_instance;
//定义一个私有静态变量保存数据库连接
private static $_conn;
private function __construct() {}
//定义获取数据库实例的方法
public static function getInstance()
{
if (self::$_instance === null) {
self::$_instance = new self();
}
return self::$_instance;
}
public static function connect()
{
if (! self::$_conn) {
self::$_conn = new mysqli('127.0.0.1', 'root', 'root', 'category');
}
mysqli_query(self::$_conn, "set names UTF8");
return self::$_conn;
}
}
编写好db类以后,可以使用下面一段简单的代码来测试下是否可以正常连接到数据库。<?php
include 'db.php';
$db = db::getInstance()->connect();
$result = $db->query("select * from category");
while ($row = $result->fetch_assoc()) {
echo $row['id'] . ':' . $row['category'] . '
';
}
output:
1:中国
2:河北
3:山西
4:石家庄
5:邯郸
6:太原
...
分类列表展示页面(index.php)
由于在分类列表展示页面中我们需要获取所有分类列表数据,所以我们使用递归的方式来获取这个数组。首先建立一个function.php文件。编写一个getCate方法function getCate($pid = 0, &$result = array(), $s = 0)
{
// 分类层级前展示的空格数
$s = $s + 4;
$conn = db::getInstance()->connect();
//获取数据对象
$sql = "SELECT * FROM `category` where `pid` = $pid";
$res = $conn->query($sql);
while ($row = $res->fetch_assoc()) {
$row['category'] = str_repeat(" ", $s) . '|--' . $row['category'];
$result[] = $row;
getCate($row['id'], $result, $s);
}
return $result;
}
上面这个就是使用递归算法来获取所有的层级分类
函数中有三个参数:第一个参数是查父ID的所有分类。
第二个参数把查到的数据及所有的自己放到这个数组地址中来。
第三个是我们每次层级深度前面的加的空格数。
执行步骤:第一步是执行查询pid为0的所有子类,放到 resqult[] 数组中。
第二步是循环查找第一步查出的子类,pid 为子类的 ID。查出的所有的子类,并放到 resqult[] 数组中。
最后查出分类没有子类后,循环不成立,不能继续执行 getCate 函数,此时函数已经不再调用自己,开始将流程的主控权交回给上一层函数来执行,开始执行所有的数据:return $resault。
最后编写index.php页面内容,如下<?php
require_once('./db.php');
require_once('function.php');
?>
分类管理id分类名操作
$rs = getCate();
foreach ($rs as $key => $value) {
?>
<?php echo $value['id'] ?><?php echo $value['category'] ?> 编辑 | 删除}
?>
添加分类页面
建立一个名为categoryadd.php页面,内容如下<?php
require_once('./db.php');
require_once('function.php');
$conn = db::getInstance()->connect();
// $result = $conn-> query("select * from category");
$result = getCate();
// dd($result->fetch_assoc());
?>
添加分类效果图如下
这里主要也是调用了getCate函数来获取到上级菜单列表,然后展示出来。分类添加的数据处理,我们稍后在编写。
分类编辑页面
在管理页面,我们可以对每条分类进行编辑操作,所以需要创建一个页面来实现分类的编辑更新操作。在项目目录下,新建categoryedit.php,编辑如下:
数据处理页面
最后到了数据的入库、编辑等操作了。所以我们创建一个action.php的文件来处理前台提交过来的数据,如下:<?php
require_once 'db.php';
require_once 'function.php';
$action = $_GET['action'];
switch ($action) {
case 'add':
$pid = $_POST['pid'];
$category = $_POST['category'];
categoryAdd($pid, $category);
break;
case 'update':
$id = $_POST['id'];
$pid = $_POST['pid'];
$category = $_POST['category'];
categoryUpdate($id, $pid, $category);
break;
case 'del':
$id = (int)$_GET['id'];
categoryDel($id);
break;
default:
exit('非法操作');
}
function categoryAdd($pid, $category) {
$conn = db::getInstance()->connect();
$sql = "INSERT INTO `category` (`pid`, `category`) VALUES ({$pid}, '{$category}')"; //注意string类型要加单引号
// echo $sql;exit;
$res = $conn->query($sql);
if ($res) {
echo "";
exit;
} else {
echo "";
}
}
function categoryDel($id) {
$conn = db::getInstance()->connect();
//查询当前分类下是否有子分类
$sql = "SELECT count(*) AS `count` FROM `category` WHERE `pid` = '{$id}'";
$res = $conn->query($sql);
$result = $res->fetch_array();
if ($result[0] > 0) {
echo "";
exit;
} else {
//删除操作
$sql = "DELETE FROM `category` WHERE `id` = '{$id}'";
$res = $conn->query($sql);
if ($res) {
echo "";
}
}
}
function categoryUpdate($id, $pid, $category) {
$conn = db::getInstance()->connect();
$sql = "UPDATE `category` SET `pid` = '{$pid}', `category` = '{$category}' WHERE `id` = '{$id}'";
$res = $conn->query($sql);
if ($res) {
echo "";
}
}
这个action.php文件主要就是接受不同的动作、接受前台提交过来的数据,然后拼接SQL语句以后执行对应的数据库操作。注意:在拼接sql语句的时候要主要字符串类型的数据需要加引号('),不然语句无法执行成功。