我正在尝试使用带有层次结构的类别表来构建导航系统。通常,该表定义如下:
id (int) - Primary key
name (varchar) - Name of the Category
parentid (int) - Parent ID of this Category referenced to same table (Self Join)
但问题是,我要求一个类别可以是多个父类别的子类。就像Has和Belbe to Many(HABTM)关系一样。
我知道如果有两个表,类别和&项目,我们使用连接表categories_items列出HABTM关系。但在这里,我没有两张桌子,只有桌子,但应该以某种方式显示HABTM关系。这是可以使用单个表吗?如果是,怎么样?如果不可能,在创建附加连接表时应该遵循哪些规则(表命名,字段)?
我正在尝试使用CakePHP来实现这一点,如果有人可以为这个问题提供CakePHP解决方案,那就太棒了。即使这是不可能的,任何关于创建连接表的解决方案都是值得赞赏的。谢谢你的时间。
- 编辑 - 我的问题似乎有点令人困惑,所以我正在努力重申我正在寻找的东西。 在传统的自引用(自联接)父子关系中,每个项目只能有一个父项。我正在寻找的是模拟HABTM关系,即每个项目的多个父母。
分类&项目 - 要定义HABTM,我们使用categories_items连接表。
如果在类别中我需要HABTM,我该怎么办?
答案 0 :(得分:3)
我希望第二次回答第一次误解这个问题是不错的形式。以下基本上是 pinkgothic 的答案的CakePHP实现。
新HABTM联接表:
CREATE TABLE `categories_parent_categories` (
`category_id` int(10) unsigned NOT NULL,
`parent_category_id` int(10) unsigned default NULL,
`order` int(10) unsigned NOT NULL default '0'
);
模型中的关联:
class Category extends AppModel
{
var $hasAndBelongsToMany = array(
'ParentCategory' => array(
'className' => 'Category',
'joinTable' => 'categories_parent_categories',
'foreignKey' => 'category_id',
'associationForeignKey' => 'parent_category_id',
'order' => 'CategoriesParentCategory.order'
)
);
}
答案 1 :(得分:2)
尝试将n:m关系(HABTM)压缩为1:n的关系并不是一种好的做法,如果干净利落的话,你会遇到你不会遇到的限制,但这就是你如何做到的(通用PHP,而不是CakePHP特定的):
您可以在表中创建一个列,将所有父ID存储在以逗号分隔的列表中。您可以使用...
来读取各个ID$ids = explode(',', $idsFromColumn);
...并使用...
将它们写回专栏$idsForColumn = implode(',', $ids);
数据库的实际读写将分别在这些片段之前/之后发生。
如果你想要正确地做,你希望你的主表看起来像这样:
id (int) - Primary key
name (varchar) - Name of the Category
你的n:m关系表看起来像这样:
id (int) - child
parentid (int) - parent
您可以这样查询:
SELECT ...
FROM
main_table AS m
[LEFT OUTER|INNER] JOIN
relationship_table AS r
ON r.id=m.id
[LEFT OUTER|INNER] JOIN
main_table AS n
ON r.parentid=n.id
WHERE ...
您想要的正确 WHERE , SELECT 将取决于您希望实现的目标。至于您是想要 LEFT OUTER JOIN 还是 INNER JOIN ,这取决于您是否要返回m。*中没有在relationship_table中有条目的类别(=没有任何父母)。如果您是新手加入语法,请查看this Wiki article on joins。
答案 2 :(得分:1)
这几乎就是Tree behaviour的设计目标。该行为建立在MPTT (Modified Preorder Tree Traversal)之上。你可以这样配置它:
将以下字段添加到您的表格中:
`parent_id` int(10) unsigned default NULL
`lft` int(10) unsigned default NULL
`rght` int(10) unsigned default NULL
型号:
class Category extends AppModel
{
var $actsAs = array('Tree');
}
然后,您将在您的类别修改表单中构建一个parent_id <select>
,树行为将处理其余部分。我想您可以手动处理类别层次结构层中的类别重新排序,但您可能最好使用扩展了Tree行为的模型中可用的moveUp
和moveDown
方法。
这里也是一个有用的Tree Helper,用于将树列表转换为视图中的有序/无序列表。
答案 3 :(得分:0)
你想要实现的并不是一种真正的蛋糕方法。您应该使用两个表之间的连接表。 Cake的格言是'约定优于配置'所以你应该真正使用标准的蛋糕方式。
要创建HABTM,您将需要三个表。
items
categories
categories_items
项目和类别正如您所期望的那样。您的连接表应该只包含连接表的两个id,如下所示,
category_id
item_id
如果您愿意,这将允许您在多个类别中显示一个导航项。
可以在书中找到更多信息,http://book.cakephp.org/view/1044/hasAndBelongsToMany-HABTM
答案 4 :(得分:0)
终于明白了。
Naviitems表:
CREATE TABLE IF NOT EXISTS `naviitems` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`linkurl` varchar(250) NOT NULL,
PRIMARY KEY (`id`)
);
自我加入表:
CREATE TABLE IF NOT EXISTS `naviitems_parents` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`naviitem_id` int(11) NOT NULL,
`parent_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
);
Naviitems模型:
<?php
class Naviitem extends AppModel {
var $name = 'Naviitem';
//The Associations below have been created with all possible keys, those that are not needed can be removed
var $hasAndBelongsToMany = array(
'Parent' => array(
'className' => 'Naviitem',
'joinTable' => 'naviitems_parents',
'foreignKey' => 'naviitem_id',
'associationForeignKey' => 'parent_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
}
?>
我使用Cake Bake shell生成了Controller和Views。现在工作正常。感谢您贡献的所有想法,他们给了我很多帮助。
答案 5 :(得分:0)
您可以使用递归来构建父/子无限制树。 更多信息可以在以下网址找到。 Get Unlimited parent and child tree in php