Работа с MySQL. Администрирование каталога ссылокВ предыдущих статьях было описано, как организовать каталог ссылок при помощи языка Perl и сервера баз данных MySQL. После того, как эта вся система заработала, встает вопрос о редактировании всего этого хозяйства - добавлении ссылок и категорий, удалении их, смене нгазваний и адресов ссылок. Для этого нужно писать небольшое, но вполне настоящее Web-приложение. Слабая сторона многих сайтов и систем - отсутствие специальных средств управления этим сайтом, как правило, Web мастер делает все сам, выкладывая на сайт изменение с помощью ftp-клиента, или каким-нибудь sql - клиентом внесет изменения в базу данных набирая вручную многокилометровые инструкции, путаясь в скобках и запятых. На мой взгляд, гораздо проще потратить пару-тройку часов и написать небольшую систему администрирования для сайта и обучить кого-нибудь из персонала компании пользоваться оной. Сейчас попробуем придумать и написать страничку для редактирования нашего каталога ссылок. Все дальнейшие исходники являются полнейшим CopyLeft и могут быть использованы на ваш страх и риск, так как тестировалось только под MSIE 5.0 Кстати, пользователи Windows. Не думайте, что Copyleft это хакерские приколы. В мире UNIX систем давно существует это понятие, под этим знаком выходят в свет операционные системы Linux и большинство софта под них. Сия лицензия называется GPL. Для интересующихся, она лежит здесь. ( http://webscript.ru/copyleft/Copying.txt )Что должен делать наш скрипт?
Как помнится из предыдущих статей, записи добавляются SQL инструкцией INSERT
INTO table (fieldlist) VALUES (values). Выглядеть это должно похоже на эту страничку ( http://webscript.ru/js/sheetedit.html ). При щелчке мышкой на записи в таблице, вся информация помещается в верхнюю строку таблицы, где расположены элементы редактирования (поля ввода). Верхняя строка содержит форму, которая записывает сохраненные изменения. Вывод имеющихся записейДля этого нужно выполнить запрос, чтобы выбрать все записи, вывести результат
в форму, установить фильтр по категориям. С помошью запроса
Если вы читали предыдущие статьи по этой теме, то обратили внимание на запрос и на метод его обработки. Во превых - мы выполнили запрос к двум таблицам базы, связав их идентификатору категорий. Запрос "SELECT a.name as cname, b.name as name, b.url as url, a.id as catid, b.id as lid FROM category a, links b WHERE b.category=a.id ORDER by a.name" выбирает из таблицы links все записи, а кроме поля category выводит еще и название категории - вряд ли вы упомните все номера ваших категорий. Этот запрос работает таким образом: в выражении FROM определяются псевдонимы для таблиц - category a, links b, а в выражении SELECT вовсю используются псевдонимы - a.name as cname, b.name as name, b.url as url, a.id as catid, b.id as lid. Ключевое слово as в выражении a.name as cname означает, что поле a.name в результате будет доступно под именем cname. Вообщем, не особенно сложно, а если разобраться - то и вовсе просто.Во-вторых - обработка результатов запроса производится не методом fetchrow->hashref(), а методом fetchrow->array().
В этом случае мы выбираем результаты, обращаясь к данным не по имени поля, а по порядковому номеру поля в записи. Это не критичный момент в обработке запроса,
но неплохо знать и об этой возможности библиотеки DBI::mysql.
Про вызов функции JavaScript settoedit() мы поговорим ниже. Если вы уже испытываете код, то в секции HEAD не забудьте объявить соответствующую функцию: <script> function settoedit() {} </script>В ней пока кода никакого не нужно,- об этом ниже. Рисуем формуДанные вывели - для их редактирования нужна какая-то форма. Мы выбрали из таблиц 5 полей данных,- значит нам нужно в форме минимум пять полей для редактирования оных:
function settoedit(idname) { baseid = idname.id.substring(idname.id.indexOf("_")+1); document.all['id'].value = document.all["id_"+baseid].innerHTML; document.all['category'].value = document.all["cat_"+baseid].innerHTML; document.all['category_id'].value = document.all["catid_"+baseid].value; document.all['namelink'].value = document.all["name_"+baseid].innerHTML; document.all['url'].value = document.all["url_"+baseid].innerHTML; document.all['edit'].value="edit"; } Теперь, если мы клацнем манипулятором, в просторечии именуемом "мышь", по строке в таблице с вашими ссылками, то все данные оттуда переместятся в форму без всяких обращений к серверу. (До сих пор недоумеваю, почему на почте яху, чтобы открыть спиок доступных папок в своем почтовом ящике, нужно ждать ответа сервера. Умом Америку не понять.Функцию reply там, кстати, тоже можно было бы реализовать на JavaScript.) Теперь немаловажный момент! Естественно, каждый раз вводить имя категории при вводе новой записи - занятие неблагодарное: можно поставить где-то лишний пробел, большую букву не там, где надо и т.п. Неплохо было бы придумать какой-нибудь справочник для этого дела. Открывать еще одно окно - это для страниц, предназначенных для клиентов:)). Для себя мы напишем справочник с помощью тэга <div>:<div id="Layer1" style="position:absolute; left:32px; top:75px; width:25%; height:120px; z-index:1; background-color: #CCCCCC; layer-background-color: #CCCCCC; border: 1px solid ; visibility: hidden">Причем воткнем эту строку сразу же после тэга <body>.(Позицию и размеры подберете по своему вкусу: как это сделать - видно из контекста тэга, атрибуты left,top,width,height). После этого мы не поставим закрывающий тэг - мы выведем список доступных категорий: my $res = $dbh->prepare("SELECT * FROM category ORDER by id"); $res->execute(); while (my @cln = $res->fetchrow_array()) { print "<option value='",@cln[0],"'>",@cln[1],"</option>n"; }Если вы еще не запутались, о чем идет речь - о HTML странице или Perl скрипте - то поясню - в Perl скрипт можно вставлять большие куски текста: print<<END_TAG; текст....текст текст....текст текст....текст текст....текст END_TAGВ нашем случае все JS функции и HTML элемент div введены в perl-программу именно этим методом. Исполняемый Perl код пишется после метки END_TAG. В целом структура скрипта выглядит так:
Следующий шаг: вывести остаток формы и обработать входящие параметры. print<<HTML_TOP; </select> <!-- закрываем SELECT --> </div> <!-- закрываем Layer со справочником --> <!-- И начинаем форму --> <form method="POST" action="editlinks.pl" name="frm"> <!-- Скрытое поле - что делать: удалять, добавлять, сохранять --> <input type="hidden" name="edit" value=""> <table width="100%"> <th class='thmy'>id</th> <th class='thmy'>Категория...... <!-- При клике на этой кнопке открывается справочник --> <input type="button" name="button" value="4" onClick="show_hide('Layer1')" title="Для выбора категории" class="tdmy" STYLE="font-family: wingdings; font-size: 12pt; color: navy; width:20"> </th><th class='thmy'>Название</th><th class='thmy'>Адрес</th> <tr> <td width=20> <input size=3 type="text" name="id" readonly STYLE="width=100%" onChange="ischange()" value=0> </td> <td width=25%> <input type="text" name="category" STYLE="width=100%" onChange="ischange()"> <!-- Здесь будем хранить category.id --> <input type="hidden" name="category_id" value=0></td> <td width=25%> <input type="text" name="namelink" STYLE="width=100%" onChange="ischange()"></td> <td width=30%> <input type="text" name="url" STYLE="width=100%" onChange="ischange()"></td> <td> <input type="button" value="<" class="thmy" STYLE="font-family: wingdings; font-size: 12pt; color: navy; width:20" title="Сохранить" onClick="check_submit()"> <input type="reset" value="2" class="thmy" STYLE="font-family: wingdings; font-size: 12pt; color: navy; width:20" title="Очистить"> <input type="button" value="N" class="thmy" STYLE="font-family: wingdings; font-size: 12pt; color: navy; width:20" title="Удалить" onClick="check_delete()"> </td></tr> </table> </form> HTML_TOPВообщем - ничего сложного. Функции check_???() устанавливают значение скрытого поля "edit" Далее - тривиально, проверка аргументов. От комментариев воздержусь. По пятизвездочной шкале браузер Гугл Хром получает 5 звезд.Пройдя все тестирования, он выигрывает по всем позициям: защиты от фишинговых атак, скорости проигрывания материала, поддержки технологии HTML 5. Браузер Google Chrome поддерживается на любом устройстве ( http://webscript.ru/https://bestwb.org/ru/pc-ru.html ) и обеспечивает быстрый и безопасный Интернет для просмотра. Гугл стремится, чтобы вам как можно проще и удобнее было выйти в глобальную сеть! &read_input; if ($data{'edit'} eq 'edit') { &save_values; print "<h3>Изменения сохранены!</h3>n"; &show_page; } else { if ($data{'edit'} eq 'delete') { &delete_record; } else { &show_page; } }Осталось написать четыре процедуры: &save_values, &show_page, &delete_record, &read_input. Последнюю процедуру здесь приводить не буду - чтение потока STDIN и заполнение хэша. Показ страницы производится при любом действии: sub show_page { my $result = $dbh->prepare("SELECT a.name as cname, b.name as name, b.url as url, a.id as catid, b.id as lid FROM category a, links b WHERE b.category=a.id ORDER by a.name"); $result->execute(); print "<table width="100%">n"; $i = 0; while (my @ln = $result->fetchrow_array()) { $i++; print "<tr><td width='20' onclick='settoedit(this);' id='id_$i' class='tdmy'>",@ln[4],"</td>n"; print "<td width='25%' onclick='settoedit(this);' id='cat_$i' class='tdmy'>",@ln[0],"</td>n"; print "<td width='25%' onclick='settoedit(this);' class='tdmy' id='name_$i'>",@ln[1],"</td>n"; print "<td width='30%' onclick='settoedit(this);' class='tdmy' id='url_$i'>",@ln[2],"</td>n"; print "<td> <input type='hidden' id='catid_$i' value='@ln[3]'></td></tr>n"; } print "</table>n"; }А запись в базу произодится так: sub save_values { if ($data{'id'} == 0) { $linksqry = "INSERT INTO links (name,url,category) values ('".$data{'namelink'}."','" .$data{'url'}."',".$data{'category_id'}.")"; } else { $linksqry = "UPDATE links SET name='" .$data{'namelink'}."',url='".$data{'url'} ."',category=".$data{'category_id'} ." where id=".$data{'id'}; } $dbh->do($linksqry); } Инструкция INSERT INTO table (field1,field2,field3) VALUES (val1,val2,val3) добавляет в таблицу новую запись и присваивает полям field1...fieldNN значения val1...valNN. При этом полям с атрибутом auto_increment() не пытайтесь присваивать значения - все равно MySQL будет их автонумеровать. Инструкция UPDATE table SET field1=value1,... fieldNN=valueNN WHERE condition обновляет значения полей в записях!!!, удовлетворяющих условию condition. Это надо иметь ввиду, т.к. одной инструкцией можно обновить много записей, например, WHERE id < 100 - обновит записи с 1 по 99.Одной процедурой вносим изменеия и добавляем запись, в зависимости от значения скрытого поля edit. Следующей процедурой удаляем запись:sub delete_record { if ($data{'id'}== 0) { # ничего не делаем!!! # если поле id == 0!!! } else { $delqry = "DELETE FROM links WHERE id = ".$data{'id'}; $dbh->do($delqry); } } Тут все просто. Инструкция DELETE FROM table WHERE condition удаляет все записи, удовлетворяющие условию condition. Удалить все записи, где поле URL содержит текст "sex": DELETE FROM links WHERE URL like '%sex%' Вот и все. Не правда ли, просто?Если нет желания возиться со всеми этими JavaScript, то можно выводить в процедуре show_page в каждой строке таблицы форму, тогда, конечно, объем результирующего HTML кода увеличится, но сам код заметно упростится. И, наконец, готовый скрипт находится здесь.ї (В формате MsWindows/MsDos text). |