Перепечатка от Джой Мураками, я уже читал эту статью, и она объяснена довольно ясно.
Мы столкнемся с этой проблемой во многих местах, таких как классификация продуктов, многоуровневые форумы с древовидной структурой, списки рассылки и т. д.: Как хранить многоуровневые структурированные данные?
В приложениях PHP внутреннее хранилище данных обычно представляет собой реляционную базу данных, которая может сохранять большие объемы данных и предоставлять эффективные услуги поиска и обновления данных. Однако основной формой реляционных данных является перекрестная таблица, представляющая собой плоскую структуру. Если вы хотите сохранить многоуровневую древовидную структуру в реляционной базе данных, вам необходимо выполнить разумную работу по преобразованию. Далее я обсужу с вами то, что я видел и слышал, а также некоторый практический опыт.
Существует два основных метода проектирования хранения иерархических данных в плоских базах данных:
модель списка смежности.
Модифицированный алгоритм обхода дерева предзаказов
Я не разбираюсь в компьютерах и ничего не знаю о структурах данных, поэтому я перевел эти два имени буквально. Пожалуйста, дайте мне знать, если я ошибаюсь.
Эти две вещи могут показаться пугающими, но на самом деле их очень легко понять. Здесь я использую простой каталог продуктов питания в качестве примера данных. Наша структура данных такая:
Еда
|
|---Фрукты
|
|---Красный
|
|--Вишня
|
|---Желтый
|
|--Банан
|
|---Мясо
|
|--Говядина
|
|--Свинина
Чтобы позаботиться о тех энтузиастах PHP, у которых беспорядок с английской
едой: Еда
Фрукты: фрукты
Красный: красный
Вишня: вишня
Желтый: желтый
Банан:банан
Мясо: Мясо
Говядина:говядина
Свинина:
Модель списка смежности
свинины— это модель, которую мы часто используем, и она была представлена во многих учебниках и книгах. Мы описываем всю древовидную структуру через плоскую таблицу, добавляя к каждому узлу атрибут родительский, представляющий родительский узел этого узла. По этому принципу данные в примере можно преобразовать в следующую таблицу:
+-----------------------+
| родитель | имя |
+-----------------------+
| | Еда |
Еда |
| Фрукты |
Зеленый |
Фрукты | Красный |
| Красный |
Фрукты | Желтый |
| Желтый |
Мясо |
Мясо |
Мясо |
+-----------------------+
Мы видим, что Груша — дочерний узел Зеленого, а Зеленый — дочерний узел Фрукта. Корневой узел «Еда» не имеет родительского узла. Чтобы упростить описание этой проблемы, в этом примере для обозначения записи используется только имя. В реальной базе данных вам необходимо использовать числовой идентификатор для идентификации каждого узла. Структура таблицы базы данных, вероятно, должна выглядеть следующим образом: id, родительский_ид, имя, описание. С помощью такой таблицы мы можем сохранить всю многоуровневую древовидную структуру через базу данных.
Отображение многоуровневого дерева. Если нам нужно отобразить такую многоуровневую структуру, нам понадобится рекурсивная функция.
<?php
// $parent — родительский элемент дочерних элементов, которых мы хотим видеть
// $level увеличивается, когда мы углубляемся в дерево,
// используется для отображения красивого дерева с отступом
функция display_children($parent, $level)
{
// Получаем все дочерние узлы родительского узла $parent
$result = mysql_query('ВЫБРАТЬ имя ИЗ дерева'.
'WHERE родитель="'.$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);
Почти используя тот же метод, мы можем узнать путь от корневого узла; в любой узел. Например, путь Черри — «Еда > Фрукты > Красный». Чтобы получить такой путь, нам нужно начать с самого глубокого уровня «Вишня», запросить его родительский узел «Red» и добавить его в путь, а затем мы запросить родительский узел Red и добавить его в путь. и так далее до верхнего уровня «Еда»
<?php
// $node — самый глубокий узел
функция get_path($node)
{
// Запрашиваем родительский узел этого узла
$result = mysql_query('ВЫБРАТЬ родительский элемент ИЗ дерева'.
'WHERE name="'.$node.'";');
$row = mysql_fetch_array($result);
// Используйте массив для сохранения пути
$path = array();
// Если это не корневой узел, продолжаем запрос вверх
// (Корневой узел не имеет родительского узла)
если ($row['parent']!='')
{
// последняя часть пути к $node — это имя
// родителя $node
$path[] = $row['parent']
// мы должны добавить путь к родителю этого узла
// путь
$path = array_merge(get_path($row['parent']), $path);
}
// возвращаем путь
вернуть $путь;
}
?>
Если вы используете эту функцию для «Вишни»: print_r(get_path('Cherry')), вы получите такой массив:
Множество
(
[0] => Еда
[1] => Фрукты
[2] => Красный
)
Как распечатать его в нужном вам формате – решать вам.
Недостатки: Этот метод очень прост, понятен и удобен в использовании. Но есть некоторые недостатки. Главным образом потому, что скорость работы очень низкая, поскольку каждый узел требует запроса к базе данных, а когда объем данных велик, для завершения дерева требуется много запросов. Кроме того, из-за необходимости рекурсивных операций каждый уровень рекурсии должен занимать некоторый объем памяти, поэтому эффективность использования пространства относительно низкая.
Теперь давайте посмотрим на другой метод, который не использует рекурсивные вычисления и является более быстрым. Это модифицированный алгоритм обхода дерева предварительного заказа. Этот метод может быть вам менее известен, и он не похож на приведенный выше, когда вы его используете. Метод легко понять с первого раза, но поскольку этот метод не использует алгоритмы рекурсивных запросов, он имеет более высокую эффективность запросов.
Сначала мы рисуем многоуровневые данные на бумаге следующим образом: пишем 1 слева от корневого узла Еда, затем продолжаем движение вниз по дереву, пишем 2 слева от Фрукта, а затем продолжаем движение по всему дереву. Ребра помечают каждый узел цифрами слева и справа. Последнее число — 18, отмечено справа от еды. На картинке ниже вы можете увидеть всю многоуровневую структуру, отмеченную цифрами. (Не понимаете? Укажите на цифры пальцами и посчитайте от 1 до 18, и вы поймете. Если вы все еще не понимаете, посчитайте еще раз и будьте осторожны, двигая пальцами).
Эти числа указывают на взаимосвязь между каждым узлом. Числа «Красного» — 3 и 6, которые являются потомками узлов «Еда» 1–18. Аналогичным образом мы видим, что все узлы с левым значением больше 2 и правым значением меньше 11 являются потомками «Фрукта» 2-11.
1 Еда 18
|
+---------------------------------------------+
|
2 Фрукты 11 12 Мясо 17
|
+---------------------+ +---------------------+
|
3 Красный 6 7 Желтый 10 13 Говядина 14 15 Свинина 16
|
4 Вишня 5 8 Банан 9
Таким образом, вся древовидная структура может быть сохранена в базе данных через левые и правые значения. Прежде чем продолжить, давайте взглянем на таблицу скомпилированных данных ниже.
+-----------------------+-----+-----+
| родитель | имя | лфт |
+-----------------------+-----+-----+
| | Еда | 1 |
| Еда | Фрукты | 2 |
| Фрукты | Красный 3 |
| Красный | Вишня 4 |
| Фрукты | Желтый |
| Желтый |
| Продукты питания | 12 |
| Мясо | Говядина | 13 |
| Мясо | 15 |
+-----------------------+-----+-----+
Примечание. Поскольку слова «left» и «right» имеют в SQL особое значение, нам нужно использовать «lft» и «rgt» для представления левого и правого полей. Кроме того, в этой структуре больше не требуется поле «родитель» для представления древовидной структуры. Другими словами, следующей структуры таблицы достаточно.
+------------+-----+-----+
| имя | лфт |
+------------+-----+-----+
| Еда | 1 |
| Фрукты | 2 |
| Красный | 3 |
| Вишня | 4 |
| Желтый | 7 |
| Банан 8 |
| Мясо | 12 |
| Говядина 13 |
| Свинина | 15 |
+------------+-----+-----+
Хорошо, теперь мы можем получить данные из базы данных. Например, если нам нужно получить все узлы в элементе «Фрукты», мы можем написать оператор запроса следующим образом: SELECT * FROM Tree WHERE lft BETWEEN 2 AND 11; запрос дал следующие результаты.
+------------+-----+-----+
| имя | лфт |
+------------+-----+-----+
| Фрукты | 2 |
| Красный | 3 |
| Вишня | 4 |
| Желтый | 7 |
| Банан 8 |
+------------+-----+-----+
Видите ли, вы можете получить все эти узлы всего одним запросом. Чтобы иметь возможность отображать всю древовидную структуру, как рекурсивная функция выше, нам также необходимо отсортировать такой запрос. Сортировка по значению l узла:
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('ВЫБРАТЬ имя, lft, rgt ИЗ дерева '.
'WHERE lft BETWEEN '.$row['lft'].' И '.
$row['rgt'].' ORDER BY lft ASC;');
// Отображение каждой строки
в то время как ($row = mysql_fetch_array($result))
{
// проверяем стек, только если он есть
если (count($right)>0)
{
// Проверяем, следует ли нам удалить узел из стека
while ($right[count($right)-1]<$row['rgt'])
{
array_pop ($ правильно);
}
}
// Отступ в имени узла.
echo str_repeat(' ',count($right)).$row['name']."n"
// Добавляем этот узел в стек
$right[] = $row['rgt'];
}
}
?>
Если вы запустите вышеуказанную функцию, вы получите тот же результат, что и рекурсивная функция. Просто наша новая функция может быть быстрее, потому что к базе данных всего 2 запроса. Легче узнать путь узла. Если мы хотим узнать путь Cherry, мы используем его левое и правое значения 4 и 5 для выполнения запроса.
ВЫБЕРИТЕ имя ИЗ дерева ГДЕ lft < 4 И rgt > 5 ПОРЯДОК ПО lft ASC;
Это даст вам следующий результат:
+----------------+
| имя |
+----------------+
| Еда |
| Фрукты |
| Красный |
+----------------+
Итак, сколько узлов-потомков имеет определенный узел? Все очень просто, общее количество потомков = (rvalue – левое значение – 1)/2 потомков = (правое – левое – 1)/2 Не верите? Посчитайте сами. Используя эту простую формулу, мы можем быстро подсчитать, что узел «Фрукт 2-11» имеет 4 узла-потомка, а узел «Банан 8-9» не имеет узлов-потомков, а это значит, что он не является родительским узлом.
Удивительно, правда? Хотя я использовал этот метод много раз, каждый раз, когда я это делаю, я все равно чувствую себя потрясающе.
Это действительно хороший метод, но есть ли способ помочь нам создать такую таблицу данных с левыми и правыми значениями? Представляем вам еще одну функцию. Эта функция может автоматически конвертировать таблицу с именем и родительскими структурами в таблицу данных с левым и правым значениями.
<?php
функция rebuild_tree($parent, $left) {
// правое значение этого узла равно левому значению + 1
$right = $left+1
// получаем всех дочерних элементов этого узла;
$result = mysql_query('ВЫБРАТЬ имя ИЗ дерева'.
'ГДЕ родитель="'.$parent.'";');
while ($row = mysql_fetch_array($result)) {
// рекурсивное выполнение этой функции для каждого
// дочерний элемент этого узла
// $right — текущее правильное значение, т.е.
// увеличивается функцией rebuild_tree
$right = rebuild_tree($row['name'], $right);
}
// у нас есть левое значение, и теперь, когда мы обработали
// дочерним узлам этого узла мы также знаем правильное значение
mysql_query('UPDATE Tree SET lft='.$left.', rgt='.
$right.' WHERE name="'.$parent.'";');
// возвращаем правильное значение этого узла + 1
вернуть $вправо+1;
}
?>
Конечно, эта функция является рекурсивной. Нам нужно запустить эту функцию из корневого узла, чтобы перестроить дерево с левым и правым значениями
rebuild_tree('Food',1);
Эта функция выглядит немного сложной, но ее функция аналогична нумерации таблицы вручную, то есть преобразовать трехмерную многослойную структуру в таблицу данных с левым и правым значениями.
Итак, как нам добавить, обновить и удалить узел такой структуры? Обычно существует два способа добавления узла:
сохранить исходное имя и родительскую структуру, использовать старый метод для добавления данных к данным и использовать функцию rebuild_tree для изменения нумерации всей структуры после добавления каждого фрагмента данных.
Более эффективный подход — изменить все значения справа от нового узла. Например: мы хотим добавить новый фрукт «Клубника», который станет последним дочерним узлом «Красного». Сначала нам нужно освободить для него место. Правое значение «Красного» должно быть изменено с 6 на 8, а левое и правое значение «Желтого 7-10» должно быть изменено на 9-12. По аналогии мы можем знать, что если вы хотите освободить место для новых значений, вам нужно добавить 2 ко всем узлам с левым и правым значениями больше 5 (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 =. «Клубника»;
Давайте сделаем еще один запрос и посмотрим! Как насчет этого? Скоро.
Хорошо, теперь вы можете спроектировать многоуровневую структуру базы данных двумя разными способами. Какой метод вы используете, полностью зависит от вашего личного суждения, но для структур со многими уровнями и большим количеством я предпочитаю второй метод. Первый метод проще, если объем запросов невелик, но данные необходимо часто добавлять и обновлять.
Кроме того, если база данных поддерживает это, вы также можете написать rebuild_tree() и операцию освобождения пространства в качестве триггерной функции на стороне базы данных и выполнять ее автоматически во время вставки и обновления. Это может повысить эффективность работы, и вы можете. добавлять новые узлы операторы SQL станут проще.
Рекурсивный метод класса
Написал гость, 31 мая 2004 г., 9:18.
Я написал программу, использующую квазирекурсивный метод, который не совсем совпадает с рекурсией в статье, и готовлюсь пересадить ее в xoops:
http://dev.xoops.org/modules/xfmod/project/?ulink
столкнулся с переполнением памяти, но я планирую продолжать использовать рекурсивный метод, мне просто нужно продолжать совершенствоваться,
я надеюсь, что у меня будет возможность обсудить. смс с вами.
» ответить на этот комментарий
Или сравнение двух методов?
Написал гость, 17 марта 2004 г., 20:30.
Я внимательно изучил эту статью и почувствовал, что она очень полезна, но потом снова задумался и почувствовал, что в этом есть проблема (для памяти я называю режим соседнего каталога рекурсивным методом, а обход предварительной сортировки Алгоритм дерева я называю методом дерева предварительной сортировки):
1. Самая большая разница между этими двумя методами заключается в том, что рекурсия требует использования стека при запросе, тогда как дерево предварительной сортировки требует половины узлов (имеется в виду вторая половина вставленный узел) при обновлении узлов обновлений. Хотя вы также говорили, что если узлов много и частые обновления, то эффективность предварительно отсортированного дерева снизится, а рекурсия будет лучше. Если уровней узлов много, то, во-первых, рекурсия вызовет переполнение стека. кроме того, сама рекурсия не очень эффективна, плюс каждый уровень рекурсии требует работы с базой данных, общий эффект не будет идеальным. Мой текущий подход состоит в том, чтобы извлечь все данные сразу, а затем выполнить рекурсивные операции над массивом, что будет лучше, если его можно будет улучшить, к каждой строке записей можно будет добавить КОРНЕВОЙ корневой узел (только на данный момент); соседние родительские узлы записываются), так что эффективность при поиске по дереву ветвей будет выше, а также это будет очень удобно при обновлении дерева, что должно быть лучше.
2. Улучшить рекурсивный метод. В статье при вычислении левого и правого значений предварительно отсортированных узлов дерева фактически используется метод обхода. Стек заменяется массивом, а push и pop. реализуются вручную; если на этот метод есть ссылка в рекурсивном алгоритме, если при выполнении рекурсии использовать массив вместо стека, можно также повысить эффективность рекурсии.
3. Параллелизм. Если учитывать параллелизм, особенно при обновлении дерева, метод обновления информации об узлах на большой площади предварительно отсортированного дерева требует дополнительного внимания к использованию механизмов блокировки и транзакций для обеспечения. согласованность данных.
4. В случае нескольких корневых узлов или нескольких родительских узлов в этом случае это, очевидно, не стандартное двоичное дерево или дерево с несколькими разветвлениями. Алгоритм предварительно отсортированного дерева необходимо значительно улучшить для адаптации, а также рекурсивный метод. применяется свободно, поэтому в этом случае рекурсия более адаптивна. Это, конечно, потому, что рекурсивный метод представляет собой форму связанного списка. Деревья и графики могут быть выражены с помощью связанных списков, и, конечно же, он легко адаптируется.
5. Интуитивно понятный. Если непосредственно наблюдать за данными, хранящимися в базе данных, без использования программы, то очевидно, что данные, хранящиеся в рекурсивном режиме, более интуитивно понятны, тогда как данные в предварительно отсортированном дереве трудно читать напрямую (для иерархического). отношения). Это важно для обмена данными. Будет ли это иметь какое-либо влияние?
Вообще говоря, я лично предпочитаю использовать рекурсивные методы, но меня всегда беспокоило влияние рекурсии на эффективность. К счастью, мне не приходилось сталкиваться с крупномасштабными уровнями классификации. Использование рекурсивных массивов вместо стеков было бы лучшим улучшением. метод. Предварительно отсортированное дерево — это эффективный метод решения простых деревьев. Как только вы к нему привыкнете, оно будет очень хорошим, особенно его обратный поиск от листового узла к корневому узлу очень удобен.
Фволк
www.fwolf.com
» ответить на этот комментарий
Очень рад видеть ваш ответ
Написал shuke, 18 марта 2004 г., 5:47.
Я очень рад, что вы так внимательно прочитали эту статью. Эта статья изначально была опубликована на сайте sitepoint.com. Я перевел ее, надеясь познакомить с некоторыми методами друзей, которые хотят начать работу. Ваш метод тоже очень хорош, если будет возможность, попробую. (Если вам интересно, почему бы не написать свой метод и конкретный код реализации в виде учебного пособия на основе приведенного выше примера, чтобы каждый мог подражать ему на более практических примерах) Если у вас есть вопросы по сохранению многоуровневых структур в базе данных Если вы заинтересованы в исследованиях, вот еще две хорошие ссылки, которые можно использовать в качестве справочных:
Знакомство с четырьмя распространенными методами одноразового запроса и сценарием сортировки массива. Я думаю, ваш сценарий должен быть лучше этого.
Кроме того, я видел, что вы также используете Drupal. Он также имеет расширенную функцию, называемую распределенной системой аутентификации пользователей. Пока вы регистрируетесь на любом сайте Drupal, вы можете войти в систему для доступа к другим сайтам Drupal. Довольно интересно.
С наилучшими пожеланиями!
» ответить на этот комментарий
Реализовано построение деревьев с помощью циклов.
Написал гость, 25 марта 2004 г., 22:10.
Я прочитал всю информацию, которую вы предоставили в прошлый раз, но, честно говоря, в первой статье не так много нового. Возможно, я не очень хорошо ее понял. Вторая статья вообще-то написана на PHP3, и структура программы. не было подробно описано. Видите ли, используется слишком много пересечений функций.
Так уж получилось, что мне понадобилось использовать иерархические роли пользователей в системе, поэтому я записал обход, исходя из идеи массива, времени разбираться не было, поэтому выложу сюда. База данных представляет собой ADODB, и программа извлекается непосредственно из системы. Надеюсь, ее можно описать ясно. В основном она использует мощные операции с массивами PHP и циклы для выполнения рекурсии. Комментарий — аналогичный метод, но сроки обработки результатов другие.
<?php
/**
* Показать список
* @доступ к общедоступному
*/
функция ДиспЛист()
{
//Режим отображения без отступов
// $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('list');
//
// $this->SetQueryTable(array($this->mTableUserRole));
//
// //Порядок запроса
// $this->SetQueryOrder('asc', $this->mTableUserRole, 'sequence');
//
// $this->Query('list');
// Parent::DispList();
// //Другой метод отображения, использующий массив в качестве стека, A: сохраняет роль при отправке в стек и удаляет источник после отправки.
// $this->CheckProperty('mrDb');
// $this->CheckProperty('mrSql');
// $this->mrSql->Select('role, title, родительский');
// $this->mrSql->From($this->mTableUserRole);
// $this->mrSql->Orderby('родитель, последовательность');
// $this->mRs = $this->mrDb->Execute($this->mrSql->Sql());
// если (0 < count($this->mRs))
// {
// $source = & $this->mRs->GetArray(); //Числовой индекс
// $стек = массив(''); //стек
// $stacki = array(-1); //Соответствует стеку, записывает уровень данных в стеке в дереве
// $target = массив();
// пока (0 < count($stack))
// {
// $item = array_shift($stack);
// $lev = array_shift($stacki);
// если (!пустой($item))
// {
// //Помещаем сюда обработанные данные в целевой массив
// array_push($target, str_repeat(' ', $lev) . $item);
// //$s1 = str_repeat(' ', $lev) .
// }
// $del = array(); //Узел, который нужно удалить из $source
// $ar = array(); //Узлы, которые необходимо добавить в стек
// foreach ($source как $key=>$val)
// {
// //Находим соответствующие дочерние узлы
// если (пусто($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)
// {
// unset($source[$val]);
// }
// echo(implode(', ', $stack) . '<br />' . implode(', ', $stacki) . '<br />' . implode(', ', $target) . '< бр /><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(); //числовой индекс
$стек = массив(-1); //стек
$stacki = array(-1); //Соответствует стеку, записывает уровень данных в стеке в дереве
$цель = массив();
в то время как (0 <счет ($ стек))
{
$item = array_shift($stack);
$lev = array_shift($stacki);
если (-1 != $элемент)
{
//Здесь помещаем обработанные данные в целевой массив
$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)
{
//Находим соответствующие дочерние узлы
если (-1 == $элемент)
{
$find = пустой($source[$key]['parent']);
}
еще
{
$find = ($source[$item]['role'] == $source[$key]['parent']);
}
если($найти)
{
array_unshift($ar, $key);
}
}
foreach ($ar как $val)
{
array_unshift($stack, $val);
array_unshift($stacki, $lev + 1);
}
//Удалить из источника
unset($источник[$item]);
//echo(implode(', ', $stack) . '<br />' . implode(', ', $stacki) . '<br />' . implode(', ', $target) . '< бр /><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 = false;
$this->mrLt->Disp();
}
еще
{
echo('<center>Данные не получены</center>');
}
} // конец функции DispList
?>