Joy Murakami가 다시 게시한 글입니다. 이전에 이 기사를 읽었으며 매우 명확하게 설명되어 있습니다.
우리는 제품 분류, 다단계 트리 구조 포럼, 메일링 리스트 등 여러 곳에서 이 문제에 직면하게 됩니다. 다단계 구조 데이터를 저장하는 방법은 무엇입니까?
PHP 애플리케이션에서 백엔드 데이터 저장소는 일반적으로 많은 양의 데이터를 저장하고 효율적인 데이터 검색 및 업데이트 서비스를 제공할 수 있는 관계형 데이터베이스입니다. 그러나 관계형 데이터의 기본 형태는 평면 구조인 교차 테이블입니다. 관계형 데이터베이스에 다단계 트리 구조를 저장하려면 합리적인 변환 작업을 수행해야 합니다. 다음에는 제가 보고 들은 것과 몇 가지 실제 경험을 여러분과 이야기해 보겠습니다.
기본적으로 플랫 데이터베이스에 계층적 데이터를 저장하는 두 가지 일반적인 설계 방법이 있습니다.
인접 목록 모델
수정된 선주문 트리 탐색 알고리즘
저는 컴퓨터 전공도 아니고, 데이터 구조에 대해 배운 적도 없어서 이 두 이름을 문자 그대로 번역했습니다. 틀린 부분이 있으면 알려주시기 바랍니다.
이 두 가지는 무섭게 들릴 수도 있지만 실제로는 매우 이해하기 쉽습니다. 여기서는 예제 데이터로 간단한 음식 디렉토리를 사용합니다. 우리의 데이터 구조는 다음과 같습니다:
음식
|
|---과일
|
|---레드
|
|--체리
|
|---노란색
|
|--바나나
|
|---고기
|
|--쇠고기
|
|--돼지고기
English Food에 푹 빠져 있는 PHP 매니아들을 돌보기 위해
: Food
과일: 과일
빨간색: 빨간색
체리:체리
노란색: 노란색
바나나:바나나
고기 : 고기
쇠고기:쇠고기
돼지고기: 돼지고기
인접 목록 모델은
우리가 자주 사용하는 모델이며 많은 튜토리얼과 책에 소개되었습니다. 이 노드의 부모 노드를 나타내기 위해 각 노드에 부모 속성을 추가하여 플랫 테이블을 통해 전체 트리 구조를 설명합니다. 이 원리에 따라 예제의 데이터는 다음 표로 변환될 수 있습니다.
+------------+
| 부모 이름 |
+------------+
| 음식 |
식품 |
과일 |
그린 |
과일 |
레드 |
과일 |
바나나 |
식품 |
쇠고기 |
고기 |
+------------+
Pear는 Green의 하위 노드이고 Green은 Fruit의 하위 노드임을 알 수 있습니다. 루트 노드 'Food'에는 상위 노드가 없습니다. 이 문제를 간단하게 설명하기 위해 이 예에서는 레코드를 나타내는 데 이름만 사용됩니다. 실제 데이터베이스에서는 각 노드를 식별하기 위해 숫자 ID를 사용해야 합니다. 데이터베이스 테이블 구조는 아마도 id, parent_id, name, Description과 같아야 합니다. 이러한 테이블을 사용하면 데이터베이스를 통해 전체 다단계 트리 구조를 저장할 수 있습니다.
다중 레벨 트리 표시 이러한 다중 레벨 구조를 표시하려면 재귀 함수가 필요합니다.
<?php
// $parent는 우리가 보고 싶은 자식의 부모입니다.
// $level은 트리에 더 깊이 들어갈수록 증가합니다.
// 멋진 들여쓰기 트리
함수를 표시하는 데 사용됩니다. display_children($parent, $level)
{
// 상위 노드 $parent의 모든 하위 노드를 가져옵니다.
$result = mysql_query('트리에서 이름 선택'.
'WHERE parent="'.$parent.'";')
// 각 하위 노드 표시
동안($row = mysql_fetch_array($result))
{
//노드 이름 들여쓰기
echo str_repeat(' ',$level).$row['name']."n";
//하위 노드의 하위 노드를 표시하려면 이 함수를 다시 호출하십시오.
display_children($row['name'], $level+ 1);
}
}
?>
전체 구조의 루트 노드(Food)에서 이 함수를 사용하면 전체 다중 레벨 트리 구조를 인쇄할 수 있습니다. Food가 루트 노드이고 해당 상위 노드가 비어 있으므로, display_children('',0)을 호출하세요. 전체 트리의 내용을 표시합니다.
음식
과일
빨간색
벚나무
노란색
바나나
고기
소고기
돼지고기
과일 부분과 같이 전체 구조의 일부만 표시하려면 다음과 같이 호출하면 됩니다.
display_children('Fruit',0);
거의 동일한 방법을 사용하면 루트 노드에서 경로를 알 수 있습니다. 어떤 노드에도. 예를 들어 Cherry의 경로는 "Food > Fruit > Red"입니다. 이러한 경로를 얻으려면 가장 깊은 수준인 "Cherry"에서 시작하여 부모 노드 "Red"를 가져오기 위해 쿼리하고 이를 경로에 추가한 다음 Red의 부모 노드를 쿼리하여 경로에 추가해야 합니다. , 그리고 최상위 수준 "Food"
<?php
까지 계속됩니다.
// $node는 가장 깊은 노드입니다.
함수 get_path($node)
{
// 이 노드의 부모 노드를 쿼리합니다.
$result = mysql_query('SELECT parent FROM tree'.
'WHERE 이름="'.$node.'";');
$row = mysql_fetch_array($result);
// 경로를 저장하려면 배열을 사용하세요.
$path = array();
// 루트 노드가 아닌 경우 위쪽으로 계속 쿼리
// (루트 노드에는 부모 노드가 없습니다)
if ($row['부모']!='')
{
// $node 경로의 마지막 부분은 이름입니다.
// $node의 부모
$path[] = $row['parent'];
// 이 노드의 부모에 경로를 추가해야 합니다.
// 경로로
$path = array_merge(get_path($row['parent']), $path);
}
// 경로를 반환합니다.
$ 경로를 반환;
}
?>
"Cherry": print_r(get_path('Cherry'))에 대해 이 함수를 사용하면 다음과 같은 배열을 얻게 됩니다.
정렬
(
[0] => 음식
[1] => 과일
[2] => 빨간색
)
원하는 형식으로 인쇄하는 방법은 귀하에게 달려 있습니다.
단점: 이 방법은 매우 간단하고 이해하기 쉽고 사용하기 쉽습니다. 그러나 몇 가지 단점이 있습니다. 주로 실행 속도가 매우 느리기 때문에 각 노드마다 데이터베이스 쿼리가 필요하고 데이터 양이 많을 경우 트리를 완성하는 데 많은 쿼리가 필요하기 때문입니다. 또한, 재귀 작업이 필요하기 때문에 각 재귀 수준마다 일정량의 메모리를 점유해야 하므로 공간 활용 효율성이 상대적으로 낮습니다.
이제 재귀 계산을 사용하지 않고 더 빠른 다른 방법을 살펴보겠습니다. 이는 수정된 선주문 트리 탐색 알고리즘입니다. 이 방법을 사용하면 위의 방법과 같지 않습니다. 처음에는 이 방법이 이해하기 쉽지만 이 방법은 재귀 쿼리 알고리즘을 사용하지 않기 때문에 쿼리 효율성이 더 높습니다.
먼저 다음과 같은 방법으로 종이에 다단계 데이터를 그립니다. 루트 노드 Food의 왼쪽에 1을 쓴 다음 트리를 계속 아래로 내리고 Fruit의 왼쪽에 2를 쓴 다음 전체 트리를 따라 계속 이동합니다. 모서리는 각 노드에 왼쪽과 오른쪽에 숫자를 붙입니다. 마지막 숫자는 Food 오른쪽에 표시된 18입니다. 아래 그림에서 숫자로 표시된 전체 다층 구조를 볼 수 있습니다. (모르겠어요? 손가락으로 숫자를 가리키며 1부터 18까지 세어보면 이해가 됩니다. 그래도 모르면 다시 세면서 조심스럽게 손가락을 움직여 보세요.)
이 숫자는 각 노드 사이의 관계를 나타냅니다. "Red"의 숫자는 3과 6이며, 이는 "Food" 1~18의 하위 노드입니다. 마찬가지로 왼쪽 값이 2보다 크고 오른쪽 값이 11보다 작은 모든 노드는 "Fruit" 2-11의 자손임을 알 수 있습니다.
1 음식 18
|
+-------------------+
|
2 과일 11 12 고기 17
|
+---------+ +---------+
|
3 빨간색 6 7 노란색 10 13 쇠고기 14 15 돼지고기 16
|
4 Cherry 5 8 Banana 9
이런 식으로 왼쪽과 오른쪽 값을 통해 전체 트리 구조를 데이터베이스에 저장할 수 있습니다. 계속하기 전에 아래의 컴파일된 데이터 테이블을 살펴보겠습니다.
+------------+------+-----+
| 상위 이름 | 왼쪽 |
+------------+------+-----+
|음식 1 |
| 과일 |
| 과일 | 3 |
레드 | 4 |
| 과일 | 10 |
바나나 8 |
음식 | 고기 12 |
쇠고기 |
돼지고기 |
+------------+------+-----+
참고: "왼쪽"과 "오른쪽"은 SQL에서 특별한 의미를 가지므로 왼쪽과 오른쪽 필드를 나타내려면 "lft"와 "rgt"를 사용해야 합니다. 또한 이 구조에서는 트리 구조를 나타내기 위해 "상위" 필드가 더 이상 필요하지 않습니다. 즉, 다음과 같은 테이블 구조로 충분합니다.
+------------+------+-----+
| 이름 | 오른쪽 |
+------------+------+-----+
음식 1 |
| 과일 2 |
레드 3 |
체리 4 |
노란색 | 10 |
바나나 8 |
고기 12 |
쇠고기 13 |
돼지고기 16 |
+------------+------+-----+
이제 데이터베이스에서 데이터를 가져올 수 있습니다. 예를 들어 "Fruit" 항목 아래의 모든 노드를 가져와야 하는 경우 다음과 같은 쿼리 문을 작성할 수 있습니다. SELECT * FROM tree WHERE lft BETWEEN 2 AND 11; 쿼리는 다음과 같은 결과를 얻었습니다.
+------------+------+-----+
| 이름 | 오른쪽 |
+------------+------+-----+
| 과일 2 |
레드 3 |
체리 4 |
노란색 | 10 |
바나나 8 |
+------------+------+-----+
단 하나의 쿼리로 이러한 모든 노드를 얻을 수 있습니다. 위의 재귀 함수처럼 전체 트리 구조를 표시하려면 이러한 쿼리도 정렬해야 합니다. 노드의 lvalue를 기준으로 정렬합니다.
SELECT * FROM tree WHERE lft BETWEEN 2 AND 11 ORDER BY lft ASC;
남은 질문은 계층적 들여쓰기를 어떻게 표시하느냐이다.
<?php
함수 display_tree($root)
{
//루트 노드의 왼쪽 및 오른쪽 값을 가져옵니다.
$result = mysql_query('SELECT lft, rgt FROM tree '.'WHERE name="'.$root.'";');
$row = mysql_fetch_array($result);
// 빈 rvalue 스택을 준비합니다.
$right = array();
// 루트 포인트의 모든 하위 노드를 가져옵니다.
$result = mysql_query('SELECT name, lft, rgt FROM tree '.
''.$row['lft']와 ' 사이의 lft'.
$row['rgt'].' ORDER BY lft ASC;')
// 각 행 표시
동안($row = mysql_fetch_array($result))
{
// 스택이 있을 경우에만 확인
if (count($right)>0)
{
// 노드를 스택 밖으로 이동해야 하는지 확인합니다.
while ($right[count($right)-1]<$row['rgt'])
{
array_pop($right);
}
}
// 노드 이름을 들여씁니다.
echo str_repeat(' ',count($right)).$row['name']."n"
// 이 노드를 스택에 추가합니다.
$right[] = $row['rgt'];
}
}
?>
위 함수를 실행하면 재귀 함수와 동일한 결과를 얻게 됩니다. 데이터베이스 쿼리가 2개뿐이므로 새 기능이 더 빨라질 수 있습니다. 노드의 경로를 아는 것이 더 쉽습니다. Cherry의 경로를 알고 싶다면 왼쪽 및 오른쪽 값인 4와 5를 사용하여 쿼리합니다.
SELECT 이름 FROM 트리 WHERE lft < 4 AND rgt > 5 ORDER BY lft ASC;
그러면 다음과 같은 결과가 나옵니다:
+----------------+
| 이름 |
+----------------+
음식 |
과일 |
레드 |
+----------------+
그렇다면 특정 노드에는 몇 개의 자손 노드가 있습니까? 아주 간단합니다. 총 자손 수 = (rvalue - 왼쪽 값 - 1)/2 자손 = (오른쪽 - 왼쪽 - 1) / 2 믿을 수 없나요? 직접 계산해 보세요. 이 간단한 공식을 사용하면 "Fruit 2-11" 노드에는 4개의 자손 노드가 있고 "Banana 8-9" 노드에는 자손 노드가 없으므로 부모 노드가 아니라는 것을 빠르게 계산할 수 있습니다.
놀랍죠? 이 방법을 여러 번 사용해 봤지만 여전히 할 때마다 놀라운 느낌이 듭니다.
이것은 정말 좋은 방법이지만 왼쪽 값과 오른쪽 값이 있는 데이터 테이블을 만드는 데 도움이 되는 방법이 있습니까? 다음은 소개할 또 다른 기능입니다. 이 기능은 이름과 상위 구조가 있는 테이블을 왼쪽 및 오른쪽 값이 있는 데이터 테이블로 자동 변환할 수 있습니다.
<?php
함수 다시 빌드_트리($parent, $left) {
// 이 노드의 오른쪽 값은 왼쪽 값 + 1입니다.
$right = $left+1;
// 이 노드의 모든 자식을 얻습니다.
$result = mysql_query('트리에서 이름 선택'.
'WHERE parent="'.$parent.'";');
while ($row = mysql_fetch_array($result)) {
// 각각에 대해 이 함수를 재귀적으로 실행합니다.
// 이 노드의 자식
// $right는 현재 오른쪽 값입니다.
//build_tree 함수에 의해 증가됨
$right = 재구축_트리($row['name'], $right);
}
// 왼쪽 값을 얻었고 이제 처리가 완료되었습니다.
// 이 노드의 자식도 올바른 값을 알고 있습니다.
mysql_query('UPDATE 트리 SET lft='.$left.', rgt='.
$right.' WHERE name="'.$parent.'";')
// 이 노드의 올바른 값 + 1을 반환합니다.
$오른쪽+1을 반환합니다.
}
?>
물론 이 함수는 재귀 함수입니다. 왼쪽 및 오른쪽 값으로 트리를 다시 작성하려면 루트 노드에서 이 함수를 실행해야 합니다.
rebuild_tree('Food',1);
이 기능은 다소 복잡해 보이지만, 그 기능은 3차원 다층 구조를 왼쪽과 오른쪽 값이 있는 데이터 테이블로 변환하는 테이블을 수동으로 넘버링하는 것과 동일합니다.
그렇다면 그러한 구조에 대한 노드를 어떻게 추가, 업데이트 및 삭제합니까? 일반적으로 노드를 추가하는 방법에는 두 가지가 있습니다.
원래 이름과 상위 구조를 유지하고, 이전 방법을 사용하여 데이터에 데이터를 추가하고,build_tree 함수를 사용하여 각 데이터 조각이 추가된 후 전체 구조의 번호를 다시 매깁니다.
보다 효율적인 접근 방식은 모든 값을 새 노드의 오른쪽으로 변경하는 것입니다. 예를 들어, "Red" 노드의 마지막 자식 노드가 될 새로운 과일 "Strawberry"를 추가하려고 합니다. 먼저 이를 위한 공간을 확보해야 합니다. "Red"의 오른쪽 값을 6에서 8로 변경하고, "Yellow 7-10"의 왼쪽 및 오른쪽 값을 9-12로 변경해야 합니다. 비유적으로 새 값을 위한 공간을 만들려면 왼쪽 및 오른쪽 값이 5보다 큰 모든 노드에 2를 추가해야 함을 알 수 있습니다(5는 "Red"의 마지막 하위 노드의 오른쪽 값입니다) ). 따라서 우리는 다음과 같은 데이터베이스 작업을 수행합니다:
UPDATE tree SET rgt=rgt+2 WHERE rgt>5;
업데이트 트리 SET lft=lft+2 WHERE lft>5;
그러면 새로 삽입된 값을 위한 공간이 확보됩니다. 이제 확보된 공간에 새 데이터 노드를 생성할 수 있습니다. 해당 노드의 왼쪽 및 오른쪽 값은 각각 6과 7입니다.
INSERT INTO tree SET lft=6, rgt=7, name = '딸기';
또 다른 쿼리를 수행해 보겠습니다. 어때요? 곧.
좋아, 이제 두 가지 다른 방법으로 다중 레벨 데이터베이스 구조를 설계할 수 있습니다. 어떤 방법을 사용하는지는 전적으로 개인 판단에 달려 있지만, 레벨이 많고 숫자가 많은 구조의 경우 두 번째 방법을 선호합니다. 쿼리 볼륨은 작지만 데이터를 자주 추가하고 업데이트해야 하는 경우 첫 번째 방법이 더 쉽습니다.
또한 데이터베이스가 지원하는 경우 데이터베이스 측에서 다시 작성_tree() 및 공간 비우기 작업을 트리거 함수로 작성하고 삽입 및 업데이트 중에 자동으로 실행할 수도 있습니다. 이를 통해 더 나은 작업 효율성을 얻을 수 있으며, 새 노드를 추가하면 SQL 문이 더 간단해집니다.
클래스 재귀적 방법
2004년 5월 31일 - 9:18am에 손님이 게시했습니다.
저는 기사에 나온 재귀와 정확히 일치하지 않는 준재귀 방법을 사용하여 프로그램을 작성했으며 이를 xoops에 이식하려고 준비 중입니다.
http://dev.xoops.org/modules/xfmod/project/?ulink에서
메모리 오버플로를 경험했지만 계속해서 재귀적 방법을 사용할 계획이므로 계속해서 개선해 나가면 좋겠습니다
. 당신과 함께 cms.
» 이 댓글에 답글 달기
아니면 두 가지 방법을 비교하는 것인가요?
2004년 3월 17일 - 오후 8시 30분에 손님이 게시했습니다.
이 글을 꼼꼼히 읽어보고 매우 유익하다고 느꼈으나 다시 생각해보니 문제가 있다는 생각이 들었습니다(기억상 인접 디렉토리 모드를 재귀적 방식, 사전 정렬 순회 방식이라고 부릅니다) 트리 알고리즘은 사전 정렬 트리 방법이라고 합니다):
1. 두 방법의 가장 큰 차이점은 재귀에는 쿼리할 때 스택을 사용해야 하는 반면, 사전 정렬 트리에는 노드의 절반이 필요하다는 것입니다(하반부 참조). 삽입된 노드) 업데이트 노드를 업데이트할 때. 노드가 많고 업데이트가 자주 발생하면 미리 정렬된 트리의 효율성이 떨어지고, 노드 수준이 많으면 우선 재귀로 인해 스택 오버플로가 발생한다고 말씀하셨는데, 게다가 재귀 자체는 그리 효율적이지 않으며 각 재귀 수준에서는 데이터베이스를 작동해야 하므로 전체적인 효과가 이상적이지 않습니다. 현재 접근 방식은 모든 데이터를 한 번에 꺼낸 다음 배열에서 재귀 작업을 수행하는 것입니다. 더 개선될 수 있다면 ROOT 루트 노드를 각 레코드 행에 추가할 수 있습니다. 인접 상위 노드가 기록됨) 브랜치 트리를 검색할 때 효율성이 높아지고 트리를 업데이트할 때도 매우 편리하므로 더 나은 방법이 될 것입니다.
2. 재귀적 방법을 개선합니다. 기사에서는 미리 정렬된 트리 노드의 왼쪽 및 오른쪽 값을 계산할 때 실제로 스택을 배열로 대체하고 푸시 및 팝을 사용합니다. 재귀 알고리즘에서 이 메서드를 참조하면 재귀를 수행할 때 스택 대신 배열을 사용하면 재귀의 효율성도 높일 수 있습니다.
3. 동시성. 특히 트리를 업데이트할 때 동시성을 고려하는 경우, 미리 정렬된 트리의 넓은 영역에서 노드 정보를 업데이트하는 방법은 잠금 및 트랜잭션 메커니즘 사용에 특별한 주의가 필요합니다. 데이터 일관성.
4. 다중 루트 노드 또는 다중 상위 노드의 경우, 이 경우에는 분명히 표준 이진 트리 또는 다중 포크 트리가 아니며 사전 정렬된 트리 알고리즘을 크게 개선하여 적응해야 합니다. 자유롭게 적용되므로 이 경우 재귀의 적응성이 더 높습니다. 물론 재귀적 방법은 연결리스트(Linked List)의 한 형태이기 때문에 연결리스트로 트리와 그래프를 표현할 수 있고, 물론 적응력도 뛰어나다.
5. 직관적. 프로그램 조작 없이 데이터베이스에 저장된 데이터를 직접 관찰해 보면 재귀 모드로 저장된 데이터가 더 직관적인 반면, 미리 정렬된 트리의 데이터는 직접 읽기가 어렵습니다(계층적). 관계). 이는 데이터 교환에 중요합니다.
일반적으로 저는 개인적으로 재귀적인 방법을 선호하지만 재귀가 효율성에 미치는 영향에 대해 항상 걱정했습니다. 다행히도 스택 대신 배열을 사용하는 것이 더 나은 개선이 될 것입니다. 방법. 사전 정렬된 트리는 간단한 트리를 해결하는 효율적인 방법입니다. 일단 익숙해지면 매우 좋을 것입니다. 특히 리프 노드에서 루트 노드까지의 역검색이 매우 편리합니다.
프울프
www.fwolf.com
» 이 댓글에 답글 달기
귀하의 답변을 보니 매우 기쁩니다.
게시자: shuke, 2004년 3월 18일 - 오전 5시 47분.
이 글을 이렇게 세심하게 읽어주셔서 정말 기쁩니다. 이 기사는 실제로 처음에 sitepoint.com에 게시되었습니다. 시작하려는 친구들에게 몇 가지 방법을 소개하기 위해 번역했습니다. 방법도 너무 좋으시네요 기회되면 시도해보겠습니다. (관심이 있으시면 위의 예를 기반으로 튜토리얼로 메소드와 특정 구현 코드를 작성하여 모든 사람이 보다 실용적인 예를 통해 따라할 수 있도록 하십시오.) 데이터베이스에 다단계 구조를 저장하는 방법에 대해 궁금한 점이 있는 경우 연구에 관심이 있는 경우 참조로 사용할 수 있는 다른 두 가지 좋은 링크는 다음과 같습니다.
일회성 쿼리와 배열 정렬 스크립트의 일반적인 네 가지 방법을 소개합니다. 귀하의 스크립트는 이보다 더 좋을 것이라고 생각합니다.
게다가 드루팔(drupal)을 사용하시는 걸로 봤는데, 분산 사용자 인증 시스템이라는 고급 기능도 있어서 어떤 드루팔 사이트에든 등록만 하면 다른 드루팔 사이트에 접속할 수 있어요. 꽤 흥미롭습니다.
최고의 소원!
» 이 댓글에 답글 달기
루프를 사용하여 트리 구축이 구현되었습니다.
2004년 3월 25일 - 오후 10시 10분에 손님이 게시했습니다.
지난번에 제공해 주신 내용은 다 읽었으나, 솔직히 첫 번째 글에는 별로 새로운 내용이 없네요. 어쩌면 두 번째 글은 실제로 PHP3로 작성되었고, 프로그램 구조도 잘 이해가 안 됐던 것 같습니다. 자세히 설명되지 않았습니다. 함수 교차점이 너무 많이 사용되었습니다.
마침 시스템에서 계층적 사용자 역할을 사용해야 했기 때문에 배열이라는 아이디어를 바탕으로 순회를 적어두었는데, 정리할 시간이 없어서 여기에 넣겠습니다. 데이터베이스는 ADODB이며, 프로그램은 시스템에서 직접 추출됩니다. 주로 PHP의 강력한 배열 연산을 사용하고 반복을 수행합니다. 댓글도 비슷한 방식이지만 결과를 처리하는 시점이 다릅니다.
<?php
/**
* 쇼 목록
* @접속 공개
*/
함수 DispList()
{
//들여쓰기 없이 표시 모드
// $this->mIsDispListIndex = true;
// echo('<p align="right"><a href="?action=new&part=role">새 역할 추가</a> </p>') _fcksavedurl=""?action=new&part=role ">새 역할 추가</a> </p>');"
//
// $this->mListTitle = '사용자 역할 목록';
// $this->SetDataOption('목록');
//
// $this->SetQueryTable( array($this->mTableUserRole) );
//
// //쿼리 순서
// $this->SetQueryOrder( 'asc', $this->mTableUserRole, 'sequence' );
//
// $this->Query('목록');
// parent::DispList();
// //배열을 스택으로 사용하는 또 다른 표시 방법, A: 스택에 푸시할 때 역할을 저장하고 푸시한 후에 소스를 삭제합니다.
// $this->CheckProperty('mrDb');
// $this->CheckProperty('mrSql');
// $this->mrSql->Select('역할, 직함, 부모');
// $this->mrSql->From($this->mTableUserRole);
// $this->mrSql->Orderby('부모, 시퀀스');
// $this->mRs = $this->mrDb->Execute($this->mrSql->Sql());
// if (0 < count($this->mRs))
// {
// $source = & $this->mRs->GetArray() //숫자 인덱스
// $stack = 배열('') //스택
// $stacki = array(-1); //스택에 해당하며, 스택에 있는 데이터의 레벨을 트리에 기록합니다.
// $target = 배열();
// 동안(0 < 개수($stack))
// {
// $item = array_shift($stack);
// $lev = array_shift($stacki);
// if (!empty($item))
// {
// //여기서 대상 배열에 처리된 데이터를 넣습니다.
// array_push($target, str_repeat(' ', $lev) . $item);
//$s1 = str_repeat(' ', $lev) .
// }
// $del = array(); //$source에서 삭제할 노드
// $ar = array(); //스택에 추가해야 하는 노드
// foreach ($source를 $key=>$val로)
// {
// //일치하는 자식 노드 찾기
// if (빈($item))
// {
// $find = 비어있음($source[$key]['parent']);
// }
//또 다른
// {
// $find = ($item == $source[$key]['parent']);
// }
// 만약 ($찾기)
// {
// array_unshift($ar, $source[$key]['role']);
// $del[] = $key;
// }
// }
// foreach($ar를 $val로)
// {
//array_unshift($stack, $val);
//array_unshift($stacki, $lev + 1);
// }
// foreach($del을 $val로)
// {
// 설정 해제($source[$val]);
// }
// echo(implode(', ', $stack) . '<br />' . implode(', ', $stacki) . '<br />' . implode(', ', $target) . '< br /><br />');
// }
//debug_array();
// }
//또 다른
// {
// echo('<center>검색된 데이터가 없습니다</center>');
// }
//배열을 스택으로 사용하는 또 다른 표시 방법 B: 스택을 푸시할 때 배열 인덱스를 저장하고 스택에서 팝한 다음 사용 후 소스를 삭제합니다.
$this->CheckProperty('mrDb');
$this->CheckProperty('mrSql');
$this->mrSql->Select('역할, 직함, 부모');
$this->mrSql->From($this->mTableUserRole);
$this->mrSql->Orderby('부모, 시퀀스');
$this->mRs = $this->mrDb->Execute($this->mrSql->Sql());
if (!empty($this->mRs) && !$this->mRs->EOF)
{
$source = & $this->mRs->GetArray() //숫자 인덱스
$stack = 배열(-1); //스택
$stacki = array(-1); //스택에 해당하며, 스택에 있는 데이터의 레벨을 트리에 기록합니다.
$대상 = 배열();
while (0 < 개수($stack))
{
$item = array_shift($stack);
$lev = array_shift($stacki);
if (-1 != $item)
{
//여기서 처리된 데이터를 대상 배열에 넣습니다.
$s1 = str_repeat(' ', $lev) . '<a href="?action=disp&part=role&role=' . $source[$item]['role'] . '">' . ['제목'] .'</a>';
$s2 = '<a href="?action=edit&part=role&role=' . $source[$item]['role'] . '">수정</a> <a href="?action=delete&part=role&role= ' . $source[$item]['role'] . '">삭제</a>';
array_push($target, array($s1, $s2));
}
$del = array(); //$source에서 삭제할 노드
$ar = array(); //스택에 추가해야 하는 노드
foreach($source를 $key=>$val로)
{
//일치하는 자식 노드 찾기
if (-1 == $item)
{
$find = 비어 있음($source[$key]['부모']);
}
또 다른
{
$find = ($source[$item]['role'] == $source[$key]['parent']);
}
if($찾기)
{
array_unshift($ar, $key);
}
}
foreach($ar를 $val로)
{
array_unshift($stack, $val);
array_unshift($stacki, $lev + 1);
}
//소스에서 삭제
unset($source[$item]);
//echo(implode(', ', $stack) . '<br />' . implode(', ', $stacki) . '<br />' . implode(', ', $target) . '< br /><br />');
}
//산출
echo('<p align="right"><a href="?action=new&part=role">새 역할 추가</a> </p>');
array_unshift($target, array('역할', '작업'));
$this->CheckProperty('mrLt');
$this->mrLt->SetData($target);
$this->mrLt->mListTitle = '사용자 역할 목록';
$this->mrLt->mIsDispIndex = 거짓;
$this->mrLt->Disp();
}
또 다른
{
echo('<center>검색된 데이터가 없습니다</center>');
}
} // DispList 함수 끝
?>