MySQL / PHP - 多层类别结构
Posted
技术标签:
【中文标题】MySQL / PHP - 多层类别结构【英文标题】:MySQL / PHP - Multi tier category structure 【发布时间】:2016-04-04 20:22:39 【问题描述】:我正在构建一个包含产品数据库的网站。每个产品都属于一个类别。类别的结构是多层的,可以包含任意数量的层,例如:
Electronics
> Games Consoles
> Xbox
> Xbox One
> Games
> etc..
Fashion
> Mens
> Shirts
> Long Sleeved
我总是将产品分配到层中的“最后一个”类别。
这是我的类别表的结构:
id name parent_id
================================
1 Fashion NULL
2 Mens 1
3 Shirts 2
4 Long Sleeved 3
5 Short Sleeved 3
我使用 Yii2 作为我的应用程序框架,但相同的概念应该适用于大多数 MVC 框架,或者至少是那些实现像 ActiveRecord 这样的 ORM 的框架。
我想做的是:
-
对于任何类别级别,获取“主”父级。 IE。对于
Shirts
,它将是Fashion
对于任何类别级别,获取该层中所有“最后”级别的类别。 IE。对于Mens
,它将是Long Sleeved
和Short Sleeved
。
(更高级)对于任何类别级别,找出其拥有的孩子/父母的数量。
我的模型中有以下默认关系:
public function getParent()
return $this->hasOne(Category::className(), ['id' => 'parent_id']);
public function getParent()
return $this->hasMany(Category::className(), ['parent_id' => 'id']);
以下是我创建的一个函数,它输出任何给定类别的“树”:
public function getParentTree()
$array = [];
// $this->parent refers to the 'getParent()' relation above
if(!empty($this->parent))
$array[] = $this->parent->name;
if(!empty($this->parent->parent))
$array[] = $this->parent->parent->name;
if(!empty($this->parent->parent->parent))
$array[] = $this->parent->parent->parent->name;
else
$array[] = "(none)";
$output = implode(" --> ", array_reverse($array));
return $output;
但是这里有很多重复,看起来很难看。但这也让我相信也许我采取了错误的方法并且需要重组数据库本身?
【问题讨论】:
你在parent_id
的正确轨道上,你可能会在网上找到一个树生成器,或者你可以让你的函数递归。即,检查当前元素是否有父元素,将父元素添加到数组中并在父元素上运行相同的函数(这将一直迭代到树上)。
mikehillyer.com/articles/managing-hierarchical-data-in-mysql
parent_id 是将数据存储在类别表中的理想方式,但如果您需要避免递归,您将希望索引类别路径以执行您正在执行的操作。您可以将此信息存储在 Yii 的缓存中,或者,如果您需要 SQL 查询中可用的路径索引,您可以创建一个存储类别路径的表,并随着树结构的变化更新此表。
【参考方案1】:
Bill 我想我已经在 YII2 -> Models 中解决了这个问题。
下面是我的代码。
public static function getSubCategories($parent_id = NULL, $level = 0)
// Get the Category from table
// Here you can use caching Yii::$app->cache->get to avoid multiple queries
$categories = Category::find()->select(['id', 'parent_id', 'name'])->where(['parent_id' => $parent_id])->asArray()->all();
// Logic of Nth level to return
self::$max_down_level += 1;
if($level != 0 && self::$max_down_level > $level) return $categories;
// Now for each sub categories find and return chidren as Array
foreach($categories as $key => $category)
$categories[$key]['children'] = self::getSubCategories($category['id'], $level);
return $categories;
不要忘记在你的模型类中声明public static $max_down_level = 0;
变量。现在调用如下函数。
-
获取父类
self::getSubCategories(NULL)
的所有子类
让所有孩子升到第二级self::getSubCategories(NULL, 2)
同样的方式你可以声明递归函数来获取父类别。
public static function getParentCategories($parent_id, $level = 0)
// Get the Category from table
// Here you can use caching Yii::$app->cache->get to avoid multiple queries
$categories = Category::find()->select(['id', 'parent_id', 'name'])->where(['id' => $parent_id])->asArray()->all();
// Logic of Nth level to return
self::$max_up_level += 1;
if($level != 0 && self::$max_up_level > $level) return $categories;
foreach($categories as $key => $category)
$categories[$key]['parent'] = self::getParentCategories($category['parent_id'], $level);
return $categories;
不要忘记在模型类中声明public static $max_up_level = 0;
变量。现在调用如下函数。
-
获取父类self::getParentCategories(16, 0)的所有子类
让所有孩子升到第二级 self::getParentCategories(16, 2)
你可以使用自己的类名代替self
希望这会有所帮助。
【讨论】:
以上是关于MySQL / PHP - 多层类别结构的主要内容,如果未能解决你的问题,请参考以下文章
使用php在单个mysql数据库表中的表中显示子类别及其父类别