|
||||||||||||||||||
Основы web-программирования для школьного “сайтостроительства”. Лекция 7.Соображаем на троих: MySQL + PHP + JavascriptЗдравствуйте, уважаемые коллеги! Сегодня нам предстоит пройти непростой, но, надеюсь, интересный путь. В реальных проектах чаще всего приходится иметь дело не с одной технологией, а с целым комплексом. Некий опыт такой интеграции мы уже имеем. Вспомните: начинали мы с HTML+PHP. В пятой лекции была задействована СУБД MySQL. Сегодня же нам потребуется использовать возможности Javascript. Скажу сразу: знакомство с Javascript не входит в программу нашего курса. Желающим углубить свои познания в технологиях клиентского программирования на Javascript могу еще раз посоветовать (я уже делал это в первой лекции) познакомиться с материалами А.А. Дуванова. Это лучшее, что можно порекомендовать учителю. (Уж поверьте: что касается материалов по web-программированию, я читал все или почти все.) Ну, начнем… Начнем мы с того, на чем закончили предыдующую лекцию, — с визуализации страницы журнала на web-странице. Помните? Рис. 1 Учебный план
Во второй контрольной работе вам было предложено дописать код для вывода правой таблицы — правого “разворота” журнала. Надеюсь, вы с этой задачей успешно справились. Вы, конечно, помните, что базу данных этого журнала мы заполняли “руками”, посредством phpMyAdmin. Для целей отладки это было вполне приемлемо, но нельзя же ожидать, что учителя — пользователи нашего журнала будут использовать его так же. Тогда уж лучше по-старинке, на бумаге! Наша задача — создать для них удобный интерфейс для выполнения типичных операций в журнале. К таковым можно отнести две — запись уроков и заполнение клеточек журнала. Можно было, конечно, начать с записи уроков, но… Честно говоря, я, конечно, реализовал обе задачи. И понял, что разобрать две в рамках лекции не получится из соображений объема, а содержательность задачи заполнения клеточек журнала существенно выше (правда, и сложность тоже…). Поэтому мы рассмотрим именно операцию заполнения клеточек журнала. Что значит удобный интерфейс? Ох…
я перечитал на эту тему массу книг и многое из них
почерпнул. Ключевая идея: возьмем привычную визуализацию журнала и в каждую клеточку поместим кнопку. Вот так:
Рис. 2 Для заполнения клеточки журнала оператор (учитель) должен нажать на кнопку в этой клеточке (фактически на саму клеточку). При этом открывается отдельная страница редактирования содержимого данной клеточки. Нажмем, например, на клеточку “2/3” (Грейпфрут Гарик, урок 3/09).
Рис. 3 Вы видите, что на этой странице можно отметить пропуск в разделе “Был/не был”, а также отредактировать оценки — поставить новую и удалить существующую. Важно, что поставить оценку можно лишь в том случае, если ученик присутствовал на уроке. Если мы отметим пункт “Пропустил урок”, страница немедленно перезагрузится и станет такой:
Рис. 4 При этом для обеспечения непротиворечивости базы данных будут удалены и все оценки, полученные учеником за данный урок (если они есть). Поэтому, если мы снова отметим, что Гарик был на данном уроке, оценок у него за этот урок уже не будет.
Рис. 5 Я попросил нескольких коллег-учителей “поиграть” с этим интерфейсом, и они оценили его как вполне приемлемый. Приступим к реализации! Взаимодействие скриптовСпроектированный интерфейс состоит из двух файлов. На рис. 2 показан результат выполнения скрипта edit.php. Фактически это та же визуализация журнала, которой мы закончили предыдущую лекцию и с которой начали эту, только с активными кнопочками в клетках. При нажатии на каждую кнопочку (что бы на ней не было написано — ничего, буква “н” или оценки) мы переходим на страницу редактирования клеточки, которая реализована скриптом cell.php. При этом в скрипт cell.php передаются два параметра, определяющих конкретную клеточку, — номер ученика и номер урока. Прежде всего скопируйте скрипт, рассмотренный в предыдущей лекции (он наверняка у вас есть — вы обязательно должны были набрать его, если не при изучении лекции, то при выполнении контрольной работы), в файл с именем edit.php, модификацией которого мы сейчас займемся. Узнай, где у него кнопка! Где кнопка… где кнопка… узнать бы, где он сам! “Приключения Электроника” Для вывода ячейки — клеточки журнала в скрипте, рассмотренном на предыдущем занятии, использовался простой код: … //И, наконец, выведем, что у нас накопилось в $td echo "<td align='center'>$td</td>"; … Для вывода в этом месте кнопки мы заменим этот оператор на следующий: echo "<td align='center'> <input type='button' value='$td' onclick='document.location=\"cell.php?student_id=$st_id&lesson_id=$l_id\"'></td>"; Здесь вместо одного строкового значения переменной $td в ячейку таблицы помещается кнопка, кодируемая тегом input c параметром type='button'. Надпись на кнопке задается параметром value='$td', но самым важным является то, что при нажатии на кнопку срабатывает обработчик события onclick и посредством короткого кода на Javascript производится переход на страницу cell.php с параметрами student_id=$st_id и lesson_id=$l_id. Здесь мне пришлось использовать один технический прием, который часто применяется в PHP: экранирование кавычки внутри строки. Суть его в следующем: если внутрь строки, ограниченной, например, двойными кавычками, требуется поместить двойную кавычку, то ее необходимо экранировать символом “слеш”. Вот так, например, "Курс \"Основы web-программирования\"". На этом изменения в файле edit.php закончены. Далее мы перейдем к рассмотрению файла cell.php — основного скрипта этой лекции, но сначала необходимо познакомиться с теми средствами MySQL и Javascript, которые нам понадобятся. Их довольно много, но среди них нет ни сложных, ни экзотических. Напротив: я постарался собрать в этом примере те дополнительные средства, которые на практике чаще всего бывают полезны. Джентльменский набор операторов SQL: SELECT+INSERT+DELETE+UPDATEПомните, в прошлой лекции мы дали пользователю webuser права выполнять в базе данных page операции SELECT, INSERT, DELETE и UPDATE? Не помните? Обязательно освежите в памяти соответствующий фрагмент лекции 6. А я сейчас расскажу, зачем пользователю webuser такие права. Какие типичные операции приходится чаще всего выполнять в базе данных? Наиглавнейшая операция (по частоте использования), конечно, выборка. В языке SQL для этого есть команда SELECT. Но, чтобы было что выбирать, надо сначала данные добавить. Мы это делали “руками”, но даже в этом случае для добавления данных использовалась команда INSERT. Наконец, время от времени данные приходится удалять. Это можно сделать посредством команды DELETE. В принципе этими командами можно, наверное, было и ограничиться, но нередко возникает потребность в изменении данных. Изменять данные, каждый раз удаляя старые и добавляя новые, — занятие, мягко говоря, неэффективное. Поэтому для этого есть специальная команда UPDATE. Перечисленные команды INSERT, DELETE и UPDATE имеют различные синтаксические формы, но я в каждом случае ограничусь рассмотрением одной — наиболее наглядной. Команда INSERTНаиболее наглядный (на мой вкус) синтаксис команды INSERT следующий: INSERT INTO имя_таблицы SET имя_поля=значение, имя_поля=значение,… Например, если нам захочется добавить еще одного ученика в таблицу student, это можно сделать посредством следующей команды:
Рис. 6 С другим синтаксисом команды INSERT вы можете познакомиться, например, заглянув в файл sampdb.sql, который использовался в лекции 5. Команда DELETEКоманда DELETE — страшная штука! С ее помощью можно, в частности, “снести” все данные в таблице и глазом не моргнуть. Вот так, например (НЕ ДЕЛАЙТЕ ЭТОГО!): DELETE FROM student Как правило, удалять приходится все же не все данные в таблице, а конкретную запись/записи. Поэтому чаще всего команда DELETE используется с условием WHERE. Вот так:
Рис. 7 Вы, наверное, поняли, что мы удалили из таблицы student только что добавленного Васю Пупкина. Команда UPDATEЕсли вы заполнили таблицу lesson, основываясь на моем примере, домашнее задание после первого урока в ней выглядело, как “затычка”: “Параграф такой-то, задание такое-то”. Давайте изменим его на более пристойное посредством команды UPDATE:
Рис. 8 Как и команда DELETE, UPDATE чаще всего используется с условием WHERE. Без этого условия она модифицирует все строки таблицы (что иногда даже хуже, чем DELETE!). Полезный ключик AUTO-INCREMENTВернемся к команде INSERT и добавим в таблицу grade еще одну оценку. Допустим, поставим Гарику (student_id=4) пятерку за второй урок (lesson_id=2). Для этого нам сначала надо выяснить идентификатор последней оценки в таблице grade:
Рис. 9 И теперь, зная идентификатор последней оценки, можно добавить новую (используя следующий идентификатор):
Рис. 10 В ряде случаев нам действительно нужно знать идентификатор добавляемой записи. Например, номер ученика в журнале — важный параметр, и при добавлении нового ученика его хочется задавать явно. Но вот номер оценки… Зачем нам эта лишняя головная боль — смотреть номер последней оценки, высчитывать следующую… Было проще просто добавить оценку, а какой у нее должен быть номер, пусть решает сама база данных. Для этого у ключевого поля можно указать специальное свойство AUTO_INCREMENT (русскоязычный Access называет это “счетчик”). Вот, смотрите, что и как нужно сделать. Первое: надо кликнуть по таблице grade и нажать на кнопку “Изменить” (карандаш) в поле grade_id.
Рис. 11 Второе: в разделе “Дополнительно” надо выбрать пункт auto_increment и нажать на кнопку “Сохранить”.
Рис. 12 Третье: все сделано!
Рис. 13 Теперь для добавления новой оценки мы можем указывать лишь номер ученика, номер урока и саму оценку:
Рис. 14 Шапка-невидимка: поля hidden в формахЕще один важный вспомогательный вопрос, который нам надо рассмотреть, — поля hidden в формах. Вспомним материалы лекции 3, в которой мы рассматривали различные типы элементов управления. Среди них не было элемента управления input с параметром type=hidden, поскольку в тот момент я не мог привести наглядного и полезного примера, в котором бы такие элементы понадобились. Теперь, наконец, мы добрались до соответствующего материала. Поля типа hidden, как правило, имеют следующий вид (я сразу привожу пример, применительно к нашей задаче): <input type='hidden' name='student_id' value='1'> Особенность этих полей заключается в том, что они никак не визуализируются браузером и не видны пользователю, но данные из них передаются вместе со всеми данными формы. Нам эти поля понадобятся для формы добавления новой оценки известному нам ученику за известный нам урок. И снова шапка-невидимка: параметр display в языке CSSЭто короткий и чисто технический вопрос, который я хочу напомнить перед рассмотрением кода скрипта cell.php. Посредством CSS можно спрятать или показать блок на HTML-странице. При этом в CSS имеются два похожих свойства: visibility и display. Посредством первого можно только прятать блок (место для него при этом резервируется), посредством второго — вообще временно убрать блок со страницы. Я использовал свойство display (в данном случае это дело вкуса). Если свойство display имеет значение block, блок виден, если значение none — не виден, убран со страницы. Нам это свойство понадобится для решения следующей задачи: если ученик был на уроке, то блок с его оценками должен быть виден. Если же урок был пропущен, то и оценок за него быть не может, следовательно, и соответствующий блок надо спрятать. “Граждане, прошедшие регистрацию, приглашаются на посадку через зону спецконтроля”Переводим: данные из заполненных элементов формы отправляются на сервер через функцию onsubmit. Обработчик onsubmit в реальных проектах играет важную роль при взаимодействии клиента и сервера. Простой пример: вы случайно поставили ученику за урок оценку 0 (я допускаю, что бывают и такие дети, но, формально говоря, нули все же ставить нельзя). Конечно, можно в серверном скрипте, получив такую оценку, не ставить ее, а выдать пользователю соответствующее сообщение. Но еще разумнее просто не отправлять на сервер данные, которые являются заведомо неправильными, и этот факт может быть установлен на стороне клиента. Для этого и используется обработчик onsubmit. Он вызывается до отправки данных формы на сервер и может делать/проверять что угодно, но обязан вернуть логическое значение true или false. Если onsubmit вернет true, данные будут отправлены, если false — не будут. Проверить допустимость оценки (она должна быть от 2 до 5) мы способны и на стороне клиента, для этого не нужно отправлять данные на сервер. Это мы и будем делать в нашем примере. Код скрипта cell.php — главного скрипта этой лекции<?php //Соединимся с базой данных (имя и пароль мы задали в прошлой лекции) mysql_connect("localhost", "webuser", "123456789"); mysql_select_db("page");
//В переменной $present могут быть переданы значения 0 или 1 // 0 -- ученик пропустил данный урок // 1 -- ученик был на данном уроке if (isset($present)) { //Если ученик был на данном уроке, //уберем отметку о пропуске из таблицы absence if ($present) mysql_query("delete from absence where student_id=$student_id and lesson_id=$lesson_id"); else { //Если же ученик пропустил урок... // ... уберем все его оценки за данный урок из таблицы grade mysql_query("delete from grade where student_id=$student_id and lesson_id=$lesson_id"); // ... добавим отметку о пропуске в таблицу absence mysql_query("insert into absence set student_id=$student_id, lesson_id=$lesson_id"); } } if (isset($grade)) { //Переменная $grade будет определена в том случае, //если мы ставим ученику оценку за урок. В этом случае добавим //новую запись в таблицу grade mysql_query("insert into grade set grade=$grade, student_id=$student_id, lesson_id=$lesson_id"); } //Переменная $delete будет определена в том случае, //если мы удаляем оценку ученика за данный урок if (isset($delete)) { mysql_query("delete from grade where grade_id=$delete"); } //Функция DayMonth использовалась в предыдущей лекции. //Она преобразует вид даты к более привычному function DayMonth($dt) { return substr($dt,8,2)."/".substr($dt,5,2); } ?> <html> <head> <meta http-equiv="content-type" content="text/html; charset=windows-1251"> <title>Редактирование клеточки страницы классного журнала</title> <style> h1,h2 {color:gray;} </style> <script type="text/javascript"> //Функция check() используется в обработчике onsubmit для //проверки допустимости оценки function check() { if ((document.forms["fgrade"].grade.value>="2")&& (document.forms["fgrade"].grade.value<="5")) return true; else { alert("В качестве оценки допустимы только цифры от 2 до 5"); return false; } } </script> </head> <body> <h1>Редактирование клеточки страницы классного журнала</h1> <?php $result=mysql_query("select student_id,name,surname from student where student_id=$student_id"); $student=mysql_fetch_assoc($result); $result=mysql_query("select lesson_id,lesson_date,subject from lesson where lesson_id=$lesson_id"); $lesson=mysql_fetch_assoc($result); echo "<p>Ученик: <b>".$student['name']." ".$student['surname']. "</b> (№ ".$student['student_id']." в журнале)"; echo "<p>Урок: <b>".DayMonth($lesson['lesson_date']). "</b> по теме <i>".$lesson['subject']."</i>"; ?> <h2>Был/не был</h2> <?php $result=mysql_query("select * from absence where student_id=$student_id and lesson_id=$lesson_id"); if (mysql_fetch_assoc($result)) { $wasnt="checked";$was=""; //Эти переменные используются, чтобы //отметить соответствующую радиокнопку $grade_display="none"; //Эта переменная определяет видимость //блока с оценками } else { $was="checked";$wasnt=""; $grade_display="block"; } echo "<p><input type='radio' name='absence' value='0' $was onclick='document.location=\"cell.php?present=1& student_id=$student_id&lesson_id=$lesson_id\"'> Был на уроке"; echo "<p><input type='radio' name='absence' value='0' $wasnt onclick='document.location=\"cell.php?present=0& student_id=$student_id&lesson_id=$lesson_id\"'> Пропустил урок";
//Ниже -- блок с оценками. Он может быть виден или не виден echo "<div id='grades' style='display:$grade_display'>"; ?> <h2>Оценки за урок</h2> <form name="fgrade" action="cell.php" onsubmit="return check();"> <?php //Два спрятанных поля, которые не видит пользователь echo "<input type='hidden' name='student_id' value='$student_id'>"; echo "<input type='hidden' name='lesson_id' value='$lesson_id'>"; ?> <table border="1"> <?php $result=mysql_query(«select grade_id,grade from grade where student_id=$student_id and lesson_id=$lesson_id"); while ($grade=mysql_fetch_assoc($result)) { echo "<tr>"; echo "<td>".$grade['grade']."</td><td><input type='button' value='Удалить' onclick='document.location=\"cell.php?delete=". $grade['grade_id']."&student_id=$student_id&lesson_id=$lesson_id\"'> </td>"; echo "</tr>"; } ?> <tr><td><input type='text' name='grade' size='2'></td><td> <input type='submit' name='sent' value='Поставить'></td></tr> </table > </div> <p><a href="edit.php">На страницу журнала</a> </div> </form> </body> </html> Вопросы и задания1. Лекции у нас получаются очень насыщенными. Поэтому, как и ранее, я настоятельно прошу вас выполнить в обязательном порядке только одно, зато самое важное задание. Пожалуйста, скачайте на странице курса в разделе “Учебные материалы” комплект файлов, рассмотренных в лекциях 6 и 7. (Обратите внимание на то, что часть, отвечающая за визуализацию правого разворота журнала, в них отсутствует, поскольку еще не вышел срок для отправки второй контрольной работы.) Установите у себя скрипты и тщательно разберите их. 2*. Второе задание к этой лекции “со звездочкой”. В начале лекции я упомянул о двух типичных операциях, которые приходится выполнять учителю: записывать уроки и выставлять оценки. Со вторым мы разобрались. А с первым вы можете попробовать разобраться самостоятельно. Спроектируйте web-интерфейс для записи уроков в наш журнал. Весь технический инструментарий для этого у вас имеется. Се. Ль. Островский | ||||||||||||||||||