Главная страница «Первого сентября»Главная страница журнала «Информатика»Содержание №22/2008


Педагогический университет

Основы web-програмирования для школьного "сайтостроительства". Лекция 6.

Свои журналы ближе к телу

Здравствуйте, уважаемые коллеги, слушатели Педагогического университета и читатели “Информатики”!

Шестая лекция нашего курса будет посвящена проектированию (в данном случае под словом “проектирование” понимается полный цикл — от задумки до реализации) базы данных “Страница школьного журнала”. Я постарался подобрать этот пример таким образом, чтобы он, с одной стороны, идейно продолжал материал пятой лекции, в которой рассматривался демонстрационный вариант базы данных для учета успеваемости, а с другой — был ближе к нашим родным российским реалиям и, следовательно, имел большую практическую ценность.

 

Учебный план

№ газеты

ЛЕКЦИЯ

17/2008

Лекция 1. “Пролетая над миром web-программирования”. Границы возможностей статического HTML. Два мира, две системы: программирование на стороне клиента и программирование на стороне сервера. Идем от реальности: текущие предложения хостинг-провайдеров. Инструментарий: пакет Denwer, установка. Первая программа на PHP “Здравствуй, мир web-программирования”.

18/2008

Лекция 2. Пример задачи автоматизации: доска объявлений школьного сайта. SSI, основные возможности и директивы. SSI-версия школьной доски объявлений. PHP-версия доски объявлений. Совершенству нет предела: выводим все объявления из каталога, помечаем важные. Передача параметров в программы на PHP. Обзор синтаксиса PHP: типы данных, операции, основные алгоритмические конструкции.

19/2008

Лекция 3. Обработка форм на стороне сервера. Формы и элементы управления HTML: однострочное и многострочное поля ввода, флажки, радиокнопки, списки. Методы GET и POST, кодирование URL. Обзор синтаксиса PHP: функции, массивы.

20/2008

Лекция 4. Усовершенствованная доска объявлений с разделом администратора. Обзор синтаксиса PHP: файлы. Законченный мини-проект: административный интерфейс для доски объявлений на файловом “движке”.

Контрольная работа № 1. Разработка теста с обработкой результатов тестирования на стороне сервера.

21/2008

Лекция 5. Введение в использование баз данных в задачах web-программирования. Зачем нужна СУБД? Теория реляционных баз данных: основные термины. SELECT — “главная команда” SQL. Что такое MySQL? Взаимодействие с сервером MySQL из программ на PHP.

22/2008

Лекция 6. База данных “Страница школьного журнала”: от проектирования до визуализации. Практическое применение базы данных для автоматизации школьного сайта и школьной жизни.

Контрольная работа № 2. Доработка базы данных “Страница школьного журнала”.

23/2008

Лекция 7. “На троих”. Задействуем трех основных “игроков”: MySQL+PHP+Javascript. Проверка данных форм на стороне клиента перед отправкой на сервер.

24/2008

Лекция 8. Рисование средствами PHP. Генерирование графических данных “на лету”. Построение графиков и диаграмм. Графическая визуализация данных школьного журнала.

Итоговая работа

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

Пример с журналом удобен тем, что в российских школах используется одна и та же утвержденная типовая форма журнала, поэтому мы с вами, взяв с полки в учительской любой журнал и открыв его на типичной странице, увидим примерно одно и то же. Так что же мы увидим?

Проектируем структуру базы данных

В подобной ситуации обычно оказывается программист-проектировщик, приступая к знакомству с предметной областью, когда ему необходимо положить сложившийся и всем привычный документооборот на музыку реляционной базы данных. Вообще говоря, конечно, проектирование — вопрос серьезный. В соответствующей главе “Энциклопедии учителя информатики” (см. № 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="&nbsp;"; //Предположим, что очередная ячейка пустая...

$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 :)>

А это — ваша вторая контрольная работа :)!

Се. Ль. Островский

TopList