|
||||||||||||||||||
Основы web-програмирования для школьного "сайтостроительства". Лекция 6.Свои журналы ближе к телуЗдравствуйте, уважаемые коллеги, слушатели Педагогического университета и читатели “Информатики”! Шестая лекция нашего курса будет посвящена проектированию (в данном случае под словом “проектирование” понимается полный цикл — от задумки до реализации) базы данных “Страница школьного журнала”. Я постарался подобрать этот пример таким образом, чтобы он, с одной стороны, идейно продолжал материал пятой лекции, в которой рассматривался демонстрационный вариант базы данных для учета успеваемости, а с другой — был ближе к нашим родным российским реалиям и, следовательно, имел большую практическую ценность.
Учебный план
Конечно, было бы заманчиво реализовать
базу данных для ведения настоящего электронного
журнала целиком. Пример с журналом удобен тем, что в российских школах используется одна и та же утвержденная типовая форма журнала, поэтому мы с вами, взяв с полки в учительской любой журнал и открыв его на типичной странице, увидим примерно одно и то же. Так что же мы увидим? Проектируем структуру базы данныхВ подобной ситуации обычно оказывается программист-проектировщик, приступая к знакомству с предметной областью, когда ему необходимо положить сложившийся и всем привычный документооборот на музыку реляционной базы данных. Вообще говоря, конечно, проектирование — вопрос серьезный. В соответствующей главе “Энциклопедии учителя информатики” (см. № 16/2007) я кратко описал наиболее существенные этапы проектирования, но сейчас я попробую сделать это еще более сжато и исключительно с позиции “практикующего разработчика”. С указанной точки зрения работа проектировщика обычно состоит из трех этапов. Этап 1. Выделение сущностей (объектов) в предметной области. Применительно к нашей задаче “обычный человек” видит на странице журнала даты, темы, домашние задания, фамилии учеников и т.д. Программист же видит здесь всего две сущности — ученик и урок. Каждая сущность станет затем отдельной таблицей. Этап 2. Определение свойств сущностей. Под этим мы понимаем как выделение собственно набора характеристик сущностей, так и типов этих характеристик — числа, даты, строки и т.п. Каждое свойство станет полем соответствующей таблицы. Этап 3. Определение связей между сущностями и типов этих связей (“один к одному”, “один ко многим”, “многие ко многим”). Для реализации связей вида “многие ко многим” в базе данных потребуется завести таблицы. Применим описанный алгоритм к нашей задаче, объединив первые два этапа (поскольку база данных совсем крошечная, это вполне допустимо). Итак, в нашей предметной области имеются две сущности: ученик и урок. Опишем структуру соответствующих таблиц. (Понятно, что типы данных зависят от используемой СУБД. Но поскольку никаких хитрых типов нам не требуется, можно быть практически уверенным, что уж целые числа и строки всегда будут в нашем распоряжении.) Вы наверняка догадались, что подчеркиванием выделены названия ключевых полей. Обратите, пожалуйста, внимание, что в таблице “Уроки” мы ввели ключевое поле “Номер урока”, которого нет в бумажной версии журнала. Программист должен сразу увидеть то, что “обычные люди”, как правило, не принимают во внимание, — дата урока в общем случае не может являться ключом. Почему? Потому что (и это можно понять лишь зная структуру предметной области — но мы ее, к счастью, знаем) в один день может быть проведено несколько уроков. Теперь давайте разберемся с пропусками. Это не слишком сложно, поскольку в предыдущей лекции мы имели дело с похожим примером. Правда, в нем была, на мой взгляд, допущена явная ошибка проектирования — пропуск был привязан к дню, а не к уроку. Правильнее же отмечать пропуски именно уроков, так как в один и тот же день ученик вполне может пропустить один урок и быть на другом. С точки зрения структуры базы данных пропуски представляют собой связь вида “многие ко многим” между сущностями “ученик” и “урок”. Ведь один ученик может пропустить много уроков и один урок могут пропустить много учеников. Для реализации подобной связи требуется завести таблицу. Например, такую: Обратите внимание на то, что эта таблица имеет составной ключ. Ни номер ученика, ни номер урока по отдельности не являются ключом, но уникальной является именно их комбинация! Теперь давайте разберемся с оценками. Что такое оценка? Это тоже (как и пропуск) связь между учеником и уроком. Если бы за каждый урок ученик мог получить не более одной оценки, то для реализации этой связи можно было бы завести таблицу, похожую по структуре на таблицу “Пропуск”: Но… К сожалению, не все так просто. Ведь в журналах очень часто встречаются как минимум двойные оценки вида 2/5. Да и тройные я тоже как-то видел. Поэтому придется для оценок завести чуть более сложную таблицу, в которой каждая оценка тоже будет иметь свой уникальный номер. Поле “Описание оценки” я завел для обеспечения дополнительной функциональности. Оно позволяет, в частности, в оценках вида 2/5 пояснять, за что именно получен каждый балл: 2 за грамотность, 5 за содержание и т.п. ОцифровкаТеперь мы на бумаге имеем структуру нашей базы данных. Пора заняться ее “оцифровкой”. Пожалуйста, запустите Denwer и перейдите на страницу phpMyAdmin. В поле “Создать базу данных” введите имя создаваемой базы — например, page (см. рис. 1). Рис. 1 Обратите, пожалуйста, внимание на то, что phpMyAdmin лишь предоставляет удобный интерфейс для выполнения некоторых операций. Создать базу данных можно было бы и “руками”, посредством команды SQL CREATE DATABASE page (см. рис. 2). На том же рис. 2 показано следующее действие: необходимо ввести имя создаваемой таблицы (student) и количество полей в ней (3). Разумеется, количество полей в дальнейшем можно менять, здесь оно введено только для удобства. Рис. 2 На следующей вкладке нам потребуется задать имена и типы полей таблицы student. Пожалуйста, обратите внимание на то, что на рис. 3 поле student_id помечено как ключевое (радиокнопка под пиктограммой с ключом в правой части рисунка). Для справки: тип VARCHAR — это практически то же самое, что в Паскале string. В качестве максимальных длин для имени и фамилии я указал 50 символов — надеюсь, всем хватит. Рис. 3 Результат операции создания таблицы показан на рис. 4. С сожалением должен обратить внимание на один “баг” в используемой нами версии phpMyAdmin. Он проявляется только в этой версии, так что нам с вами не повезло. Дело в том, что хотя все поля были при создании отмечены как “не пустые” (NOT NULL), на рис. 4 мы видим слово “Да” в столбце “Ноль”. Это — ошибка phpMyAdmin. Бывает… хорошо еще, что ошибка касается именно визуализации, сами команды SQL, как мы видим, выполняются правильно.
Рис. 4 Чтобы перейти к созданию следующей таблицы, надо кликнуть на имя базы данных (pаge). Мы попадем на страницу, показанную на рис. 5. Здесь можно ввести имя очередной таблицы.
Рис. 5 На следующих рисунках показаны структуры всех оставшихся таблиц нашей базы данных. Я привожу их для того, чтобы мы с вами использовали одинаковые имена и типы полей — это понадобится в дальнейшем в скриптах.
Рис. 6
Рис. 7
Рис. 8 Если вы все сделали правильно (я уверен, что это так!), то в нашей базе данных теперь содержится четыре пустые таблицы (см. рис. 9).
Рис. 9 Неплохо бы их чем-нибудь заполнить. Хотя бы той информацией, которая приведена в первом примере журнала в этой лекции. Займемся этим! Кликните, например, на таблицу student и в верхнем меню выберите пункт “Вставить”. Откроется страница, показанная на рис. 10.
Рис. 10 Нам предстоит вставить в таблицу student четыре записи. За один раз (на одном экране) можно вставить две. Введите данные в поля (см. рис. 11).
Рис. 11 Пожалуйста, обратите внимание на команду языка SQL, посредством которой выполняется добавление данных в таблицу (см. команду INSERT на рис. 12). К этой команде мы еще вернемся в следующей лекции.
Рис. 12 Введите в эту таблицу еще двух учеников и заполните другие таблицы базы данных в соответствии с примером, с которого мы начали лекцию. На рис. 13 показан пример заполнения таблицы absence. Остальные скриншоты я приводить не буду — они аналогичны.
Рис. 13 После заполнения всех таблиц можно попробовать выполнить на нашей базе данных ряд запросов в режиме “ручного управления” (ручного ввода команд SQL). Для этого перейдем на вкладку SQL (в верхнем меню) и получим, например, все оценки Гарика за второй урок (см. рис. 14).
Рис. 14 Результат этого запроса (ожидаемый, разумеется!) показан на рис. 15.
Рис. 15 Далее мы займемся работой с созданной базой данных из скриптов на PHP. Но сначала давайте дадим пользователю webuser (помните, мы создали его в предыдущей лекции), права на операции с базой данных page. Механизм делегирования прав был рассмотрен в лекции 5. Тогда мы предоставили пользователю webuser право на выполнение команды SELECT в базе данных sampdb. Теперь же нам нужно (“про запас” — нам это понадобится в следующей лекции) дать webuser право выполнять в базе данных page четыре операции: SELECT, INSERT, UPDATE и DELETE. Обратитесь при необходимости к материалу предыдущей лекции, чтобы добиться картинки, показанной на рис. 16.
Рис. 16 ВизуализацияНа рис. 17 показана визуализация нашей “Страницы классного журнала” на web-странице. Я постарался практически буквально воспроизвести пример, приведенный в начале этой лекции. Соответствующий скрипт (подробно прокомментированный) приведен ниже, но перед тем, как с ним разбираться, прошу вас вспомнить некоторые вопросы, рассмотренные в предыдущих лекциях.
Рис. 17 Вспомнить всеПожалуйста, вспомните материал лекции 3 — то, что касается работы с массивами. В третьей лекции мы рассматривали много примеров на эту тему. Вам необходимо освежить в памяти несколько фактов: 1. Массивы могут индексироваться строками (т.е. строки могут быть ключами). 2. При присваивании значения элементу массива без явного указания значения ключа (вот так: $arr[]=1) создается новый элемент массива со “следующим” значением ключа. 3. Для перебора элементов массива имеется специальный цикл foreach. Также, пожалуйста, вспомните материал предыдущей лекции, который касался функций PHP для взаимодействия с MySQL. Речь идет о следующих функциях: 1. mysql_connect 2. mysq_select_db 3. mysql_query 4. mysql_fetch_assoc Скрипт для получения рис. 17 Для удобства рис. 17 получен следующим образом: левый и правый “развороты” страницы выводятся различными таблицами. Одна из них выравнивается влево, вторая — вправо. <html> <head> <meta http-equiv="content-type" content="text/html; charset=windows-1251"> <title>Страница классного журнала</title> </head> <body> <h2>Страница классного журнала</h2> <?php function DayMonth($dt) { //Преобразует строку yyyy-mm-dd -> dd/mm //Используется функция substr, которая получает подстроку из строки //Формат substr: (строка, начиная с, количество символов) //Символы в строке индексируются с нуля return substr($dt,8,2)."/".substr($dt,5,2); } mysql_connect("localhost", "webuser", "123456789"); mysql_select_db("page"); $result=mysql_query("select student_id,name,surname from student order by surname, name");
//Запомним в массиве $students данные всех учеников while ($arr=mysql_fetch_assoc($result)) $students[]=$arr;
$result=mysql_query("select lesson_id,lesson_date,subject,hometask from lesson order by lesson_date");
//Запомним в массиве $lessons данные всех уроков while ($arr=mysql_fetch_assoc($result)) $lessons[]=$arr;
//Выведем левую таблицу echo "<table border='1' align='left'><tr>"; echo "<th>№</th><th>Фамилия, имя</th>";
//Выведем "шапку" таблицы -- даты уроков foreach ($lessons as $lesson) echo "<th>".DayMonth($lesson[‘lesson_date'])."</th>"; echo "</tr>";
//Выведем столбцы с номерами и фамилиями учеников foreach ($students as $student) { echo "<tr><td>".$student[‘student_id']."</td>"; echo "<td><i>".$student[‘surname']." ".$student[‘name']."</i></td>"; foreach ($lessons as $lesson) { $st_id=$student[‘student_id']; $l_id=$lesson[‘lesson_id']; $td=" "; //Предположим, что очередная ячейка пустая... $result=mysql_query("select * from absence where student_id=$st_id and lesson_id=$l_id"); //Если в таблице absence есть запись о пропуске -- поменяем значение $td if (mysql_fetch_assoc($result)) $td="н"; else { //Посмотрим, есть ли у данного ученика оценки за данный урок... $result=mysql_query("select grade from grade where student_id=$st_id and lesson_id=$l_id"); $delimit=""; while ($grade=mysql_fetch_assoc($result)) { //Если оценки есть, накопим их в переменной $td $td=$td.$delimit.$grade[‘grade']; $delimit="/"; } } //И, наконец, выведем, что у нас накопилось в $td echo "<td align='center'>$td</td>"; } echo "</tr>"; } echo "</table>";
//Выведем правую таблицу echo "<table border='1' bgcolor='#EEEEEE'>"; echo "<tr><th>Дата</th><th>Тема урока</th><th>Домашнее задание</th></tr>"; ******* ********* ** ******** **** ********************************************************* **************************************************************** echo "</table>"; ?> </body> </html> Что это?! Трам-тарам-пам-пам… <skiped :)> Се. Ль. Островский | ||||||||||||||||||