我正在开发一个接收这样的网址的CMS系统:
/ parent1 / parent2 /儿童/
现在很容易只检查孩子,但在我看来,你也应该检查父母是否正确并且顺序正确。问题是我不确定如何做到这一点。
我正在使用mysql。这就是该表的外观:
CREATE TABLE IF NOT EXISTS `pages` (
`id` int(11) NOT NULL auto_increment,
`parent` int(11) NOT NULL default '0',
`title` varchar(255) NOT NULL,
`deleted` tinyint(1) NOT NULL default '0',
PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
父字段保留在父字段中将用作父级的其他页面ID。
答案 0 :(得分:1)
最好的方法是在一个查询中检索整个表并构建一个嵌套数组。使用php中的整个树结构,检查它们是否正确更容易。
在这篇博客上,有关于仅使用一个查询格式化多级菜单的信息:http://crisp.tweakblogs.net/blog/317/formatting-a-multi-level-menu-using-only-one-query.html
它背后的想法是你在php中递归地构建菜单。如果您能够更改数据库结构,还可以查看MPTT或嵌套集。使用此机制,可以更轻松地跟踪树中的父/子关系。缺点是插入或更新节点时MPTT较慢。更多信息:http://articles.sitepoint.com/article/hierarchical-data-database
答案 1 :(得分:1)
您可以更改SQL表结构以使用树的嵌套集模型;它可以更容易地测试包含可能深深嵌套在特定父级下的子项。
This page对邻接列表模型和嵌套集进行了很好的描述和比较。
您可能会发现嵌套设置问题的以下答案也很有用:Help with writing a SQL query for Nested Sets
拿起Joe Celko's Trees and Hierarchies in SQL for Smarties的副本。我一直推荐这本书,因为当我使用嵌套集在SQL中构建树结构时,它给了我极大的帮助。
答案 2 :(得分:0)
如果我理解你的要求你可以做这样的事情(只打电话给DB,而不是全部!)
可在此处找到完整脚本:http://pastie.org/1250062
希望它有帮助...:)
示例存储过程调用
call page_parents(5);
call page_parents(7);
示例PHP脚本
<?php
function hasValidParents($conn, $urls, $pageID){
$parents = array();
$valid = true;
//needs additional validation
$sproc = sprintf("call page_parents(%d)", $pageID);
$result = $conn->query($sproc);
while($row = $result->fetch_assoc()) $parents[] = $row["page_id"];
$result->close();
foreach($urls as $url)
if($url && !in_array($url,$parents)){ $valid=false; break; }
return $valid;
}
$urls = explode("/", "1/3/5"); // trim leading /
$conn = new mysqli("localhost", "foo_dbo", "pass", "foo_db", 3306);
echo hasValidParents($conn, $urls, $urls[count($urls)-1]) ? "true" : "false";
$conn->close();
?>
<强> SQL 强>
-- TABLES
drop table if exists pages;
create table pages
(
page_id smallint unsigned not null auto_increment primary key,
title varchar(255) not null,
parent_page_id smallint unsigned null,
key (parent_page_id)
)
engine = innodb;
-- TEST DATA
insert into pages (title, parent_page_id) values
('Page 1',null),
('Page 2',null),
('Page 1-2',1),
('Page 1-2-1',3),
('Page 1-2-2',3),
('Page 2-1',2),
('Page 2-2',2);
-- STORED PROCEDURES
drop procedure if exists page_parents;
delimiter #
create procedure page_parents
(
in p_page_id smallint unsigned
)
begin
declare v_done tinyint unsigned default 0;
declare v_depth smallint unsigned default 0;
create temporary table hier(
parent_page_id smallint unsigned,
page_id smallint unsigned,
depth smallint unsigned default 0
)engine = memory;
insert into hier select parent_page_id, page_id, v_depth from pages where page_id = p_page_id;
/* http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html */
create temporary table tmp engine=memory select * from hier;
while not v_done do
if exists( select 1 from pages pg inner join hier on pg.page_id = hier.parent_page_id and hier.depth = v_depth) then
insert into hier
select pg.parent_page_id, pg.page_id, v_depth + 1 from pages pg
inner join tmp on pg.page_id = tmp.parent_page_id and tmp.depth = v_depth;
set v_depth = v_depth + 1;
truncate table tmp;
insert into tmp select * from hier where depth = v_depth;
else
set v_done = 1;
end if;
end while;
select
pg.page_id,
pg.title as page_title,
b.page_id as parent_page_id,
b.title as parent_page_title,
hier.depth
from
hier
inner join pages pg on hier.page_id = pg.page_id
left outer join pages b on hier.parent_page_id = b.page_id
order by
hier.depth, hier.page_id;
drop temporary table if exists hier;
drop temporary table if exists tmp;
end #
delimiter ;
-- TESTING (call this stored procedure from php)
call page_parents(5);
call page_parents(7);
答案 3 :(得分:0)
好的,我制定了自己的方法,请不要使用kohana,所以我正在使用kohana的查询构建器:
这段代码构建了我想要使用的数组。
public function build_array($parent = 0, $data = null)
{
if(!$data)
{
$result = db::select('*')
->from($this->_table_name)
->as_assoc()
->execute($this->_db);
foreach($result as $page)
{
$data['items'][$page['id']] = $page;
$data['parents'][$page['parent']][] = $page['id'];
}
}
if (isset($data['parents'][$parent]))
{
$array = array();
foreach ($data['parents'][$parent] as $item)
{
$array[$data['items'][$item]['slug']] = array(
'id' => $data['items'][$item]['id'],
'subitems' => $this->build_array($item, $data)
);
}
return $array;
}
}
如果父母错了,这段代码会通过数组运行url:
public function get_id($page, $parents)
{
$array = $this->build_array();
if(!empty($parents[0]))
{
foreach($parents as $parent)
{
$array = $array[$parent]['subitems'];
}
}
return $array[$page]['id'];
}
注意:您需要发送到此功能的数据是:
$page = 'child';
$parent = 'parent1/parent2';