Главная страница статей --> Советы по фотошопу, графике и хитрости в построении php кода

Скрипт управления деревом

Источник: realcoding.net

В предыдущих статьях, мы рассмотрели теорию хранения и управления древовидных структур данных, а так же реализовали Perl модуль для облегчения управления ими. Теперь напишем небольшой скрипт упраления (администрирования). Идея скрипта проста - требуется легко и непринужденно, с помощью скрипта, управлять деревом каталогов.

Возьмем стандартную таблицу в которой будет хранится наше дерево каталогов, в ней мы будем хранить только одно дерево, реализацию принципа работы, при котором количество деревьев неограничено, я рассмотрю в следующих статьях. Итак, наша таблица:

CREATE TABLE
my_tree
(
id INT(11) NOT NULL AUTO_INCREMENT,
left_key INT(11) NOT NULL DEFAULT 0,
right_key INT(11) NOT NULL DEFAULT 0,
level INT(11) NOT NULL DEFAULT 1,
name VARCHAR(150) NOT NULL,
PRIMARY KEY
id
(id),
INDEX
left_key
(left_key, right_key, level)
);

Конечно, количество дополнительных полей (одно из них - name) может быть неограничено.
Концепция

Для начала определим, какие функции должен выполнять наш скрипт:

* создание узла;
* редактирование узла (с возможностью изменения подчиненности);
* удаление узла;
* перемещение узла на уровень вверх;
* перемещение узла на уровень вниз;
* перемещение узла на порядок вверх (в пределах подчиненности);
* перемещение узла на порядок вниз (в пределах подчиеннности);

Ограничение доступа - вообще не учитывал, то есть авторизация скрипта, проверка доступа - просто отсутсвуют. Оставлю это на Вашей совести. А вообще, проще всего, просто запаролировать директирию скрипта .htaccess и все...

HTML шаблон*, я все-таки вынес из скрипта - терпеть не могу править HTML в скрипте, и Вам того не советую. Шаблон состоит из трех частей:

* верхняя часть (header.html) - заголовки и прочая до момента вывода списка категорий (начало таблицы);
* строка списка категорий (row.html) - одна строка таблицы списка категорий;
* нижняя часть (footer.html) - конец таблицы вывода списка категорий, форма создания, редактирования категории;

* Эта структура шаблонов была придумана "на ходу", поэтому не будем заострять внимание на её правильности, не это важно.
HTML-код шаблонов:

header.html

<html><head>
<
title>Скрипт управления деревом каталогов</title>
<
meta http-equiv=Content-Type content=text/html; charset=windows-1251>
<
script language=javascript>
function
EditCat (IdCat, NameCat, ParentCat) {
document.getElementById(TitleForm).innerHTML = ИЗМЕНИТЬ КАТЕГОРИЮ;
document.getElementById(buttonForm).value = Изменить;
document.FormCategory.id.value = IdCat;
document.FormCategory.name.value = NameCat;
document.FormCategory.parent.options[ParentCat].selected = true;
document.FormCategory.doing.value = edit;
}
function
ClearFormEdit () {
document.getElementById(TitleForm).innerHTML = ДОБАВИТЬ КАТЕГОРИЮ;
document.getElementById(buttonForm).value = Добавить;
document.FormCategory.id.value = xx;
document.FormCategory.name.value = Новая категория;
document.FormCategory.doing.value = new;
}
</script>
</head>
<body>
<h1>Скрипт управления деревом каталогов</h1>
<h2>Список категорий фирм</h2>
<table width=100% border=0 cellpadding=0 cellspacing=0>

row.html

<tr>
<td>[$prefix$] [$name$]</td>
<td width=80>
<a href=#form onClick=javascript: EditCat ([$id$],[$name$],[$par$]);>
изменить
</a>
</td>
<td width=80><a href=?ac=[$ac$]&doing=delete&id=[$id$]>удалить</a></td>
<td width=80><a href=?ac=[$ac$]&doing=level_up&id=[$id$]>влево</a></td>
<td width=80><a href=?ac=[$ac$]&doing=level_down&id=[$id$]>вправо</a></td>
<td width=80><a href=?ac=[$ac$]&doing=order_up&id=[$id$]>вверх</a></td>
<td width=80><a href=?ac=[$ac$]&doing=order_down&id=[$id$]>вниз</a></td>
</tr>

footer.html

</table>
<a name=form></a>
<table align=center width=95% border=0 cellpadding=0 cellspacing=0>
<form action=? method=post name=FormCategory>
<tr><td colspan=2><h1 id=TitleForm>ДОБАВИТЬ КАТЕГОРИЮ</h1></td></tr>
<tr>
<td>Название категории</td>
<td><input type=text value=Новая категория name=name size=60></td>
</tr>
<tr>
<td>Подчинение категории</td>
<td><select name=parent>
<option value=root>-- Без подчинения --</option>
[$list_select$]
</select></td>
</tr>
<tr>
<td colspan=2>&nbsp;
<input type=hidden name=id value=xx>
<input type=hidden name=doing value=new>
<input type=hidden name=ac value=[$ac$]>
</td>
</tr>
<tr>
<td colspan=2 align=center>
<input type=submit name=buttonForm id=buttonForm value=Добавить>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<input type=reset value=Вернуть onClick=javascript: ClearFormEdit ();>
</td>
</tr>
</form>
</table>
</body></html>

Теперь поясню отдельные моменты:

* В первом файле включен JavaSript, так как форма редактирования и создания одна, то при нажатии на ссылку "изменить" нужно внести соответствующие данные в форму. По кнопке "Вернуть" формы, требуется очистить форму от данных редактируемого узла;
* текст заключенный в квадратные скобки и знак доллара ([$текст$]), то что будет динамически заменяться нашим скриптом, где:
o [$id$] - идентификатор узла;
o [$name$] - поле name узла, или имя узла;
o [$prefix$] - отступ на который смещается имя узла (зависит от уровня узла);
o [$par$] - порядковый номер родительского узла в select формы редактирования (не путать с id родительского узла!);
o [$ac$] - случайный набор символов, я буду использовать текущее время (против кеширования страниц);

Код скрипта


Для начала определим где какие файлы у нас будут лежать:

* cgi-bin/admin_tree/
o lib/
+
MP/
# NestedSets.pm
o template/
+
header.html
+ row.html
+ footer.html
o admin
.pl

Что за файл NestedSets.pm, я думаю, объяснять не нужно (это модуль описанный в предыдущих статьях), с .html файлами - тоже понятно, остался только один файл - admin.pl, его мы как раз и опишем. Итак, код скрипта:

#!/usr/bin/perl
# Подключение основных модулей
use strict;
use
CGI;
use
DBI;
use
vars $query,
$dbh, # объект подключения в базе данных
$nested, # объект работы с деревои NestedSets
%user_vars; # Глобальные пользовательские переменные

# Подключаем модуль для работы с деревои NestedSets
use lib lib/;
use Global::
NestedSets;
# Указываем переменные пользовательские переменные
$user_vars{table} = my_tree; # Имя таблицы БД
# Коннект к базе
$dbh = DBI->connect(DBI:mysql:database=mybase:host=localhost:port=3306,
user, password) die $DBI::errstr;
# Выбираем переданные данные
$query = new CGI;
$user_vars{id} = $query->param(id) undef; # Идентификатор узла
$user_vars{doing} = $query->param(doing) undef; # Производимое действие
# Определяем объект Global::NestedSets
$nested = new Global::NestedSets {DBI=>$dbh, table=>$user_vars{table}};

# Если производится какое-либо действие
if ($user_vars{doing}) {
# Действие - поднять узел на уровень вверх
if ($user_vars{doing} eq level_up) {
$nested->set_unit_level(unit=>$user_vars{id}, move=>up);
# Действие - опустить узел на уровень вниз
} elsif ($user_vars{doing} eq level_down) {
$nested->set_unit_level(unit=>$user_vars{id}, move=>down);
# Действие - поднять узел на порядок вверх
} elsif ($user_vars{doing} eq order_up) {
$nested->set_unit_order(unit=>$user_vars{id}, move=>up);
# Действие - опустить узел на порядок вниз
} elsif ($user_vars{doing} eq order_down) {
$nested->set_unit_order(unit=>$user_vars{id}, move=>down);
# Действие - удалить узел
} elsif ($user_vars{doing} eq delete) {
$nested->delete_unit(unit=>$user_vars{id});
# Действие - создать узел
} elsif ($user_vars{doing} eq new) {
# Выбираем данные формы
$user_vars{name} = $query->param(name) Новая;
$user_vars{parent} = $query->param(parent) root;
# Создаем узел в дереве и получаем его ID
$user_vars{id} = $nested->insert_unit(under=>$user_vars{parent});
# Обновляем дополнительные поля узла
$dbh->do(UPDATE .$user_vars{table}.
SET name = .$user_vars{name}.
WHERE id =
.$user_vars{id}) die $DBI::errstr;
# Действие - отредактировать
} elsif ($user_vars{doing} eq edit) {
# Выбираем данные формы
$user_vars{name} = $query->param(name) Новая;
$user_vars{parent} = $query->param(parent) root;
# Выбираем ID родителя редактируемого узла
my $check = ($nested->get_parent_id(unit=>$user_vars{id}))->[0];
# Если меняется родительский узел, то производим перемещение
if ($check ne $user_vars{parent}) {
$nested->set_unit_under(unit => $user_vars{id},
under => $user_vars{parent})
}
# Обновляем дополнительные поля узла
$dbh->do(UPDATE .$user_vars{table}.
SET name = .$user_vars{name}.
WHERE id =
.$user_vars{id}) die $DBI::errstr;
}
}

# Выдаем заголовок браузеру
print Content-type: text/html; charset=windows-1251nn;
# Открываем шаблон верхней части страницы и выводим его на экран
open (HTML, ./template/header.html) die Can not open file header.html!;
print <
HTML>;
close HTML;

# Открываем шаблон строки списка и заносим его в переменную
open (HTML, ./template/row.html) die Can not open file row.html!;
my $line = join(, <HTML>);
close HTML;

# Выбираем полностью все дерево и сортируем по левому ключу
my $sql = SELECT id, name, level
FROM
.$user_vars{table}.
ORDER BY left_key
;
my $sth = $dbh->prepare($sql); $sth->execute() die $DBI::errstr;
# Объявляем хеш и переменную (счетчик) с помощью которого будем определять
# порядок родительского узла в списке select формы
my %par = (0 => 0, root => 0); my $i = 1;
# Объявляем переменную для формирования списка select формы
my $list_select;
while (
my $row = $sth->fetchrow_hashref()) {
# Копируем шаблон строки во временную переменную
my $temp_line = $line;
# Формируем переменную для антикеша
$$row{ac} = time;
# Формируем отступ перед названием узла
$$row{prefix} = &nbsp;&nbsp;&nbsp;&nbsp; x ($$row{level} - 1);
# Определяем порядок родительского узла в списке select формы
$$row{par} = $par{($nested->get_parent_id(unit=>$$row{id}))->[0]};
$par{$$row{id}} = $i; $i++;
# Обрабатываем строку заменяя соотвествующие
$temp_line =~s /[$(w+)$]/$$row{$1}/g;
print
$temp_line;
$list_select .= <option value=.$$row{id}.>.
$
$row{prefix}.$$row{name}.</option>;
}
$sth->finish();

# Открываем шаблон нижней части страницы и записываем его в переменную
open (HTML, ./template/footer.html) die Can not open file footer.html!;
my $footer = join(, <HTML>);
close HTML;
# Вносиим в шаблон список select формы
$footer =~s /[$list_select$]/$list_select/g;
# ... и выводим на экран
print $footer;
# Все...
exit;
1;

Вот собственно и все. Как видно, никаких сложностей нет, сам скрипт размером менее чем сто строк благодаря использованию модуля. Конечно, нужно еще проверить данные формы, может быть, некоторые операции...



Похожие статьи:
- Сокращение времени загрузки веб-страниц с помощью CSS
- Совет дня на JavaScript
- Использование фонового изображения для замены текста
- Как совместить пиксел к пикселу фон и содержимое во всех браузерах
- Мета-поиск - лучший друг
- Формат и синтаксис Cookie
- Работа с ссылками - Построении ссылок с помощью JavaScript
- Создание файлов при помощи JavaScript и VBScript
- Web браузер как средство доступа к БД
- Использование метаданных (HTTP-EQUIV, NAME, REL, REV, BASE) при создании HTML документов
- Из опыта Web-мастера: переползаем на Python
- Сценарий и обработка событий в JavaScript
- Конвертор кирилличного текста в Unicode на PHP


Оглавление | Обсудить на форуме | Главная страница сайта | Карта сайта |

Контакты
Редакция:
[0.002]