1. Описание рабочей среды выполнения проекта

Проектирование начинается с установки и настройки рабочей среды программиста. Для создания WEB-приложения будет использована связка PHP+MySQL, поэтому на локальном компьютере требуется установить WEB-сервер и сервер баз данных. Комплексным решением является установочный пакет XAMPP, включающий в себя WEB-сервер Apache, интерпретатор PHP, сервер баз данных MySQL. Пакет включает также и другие приложения, однако указанного набора достаточно для моделирования работы WEB-проекта на локальном компьютере. Процесс разработки включает в себя написание кода и проверку его исполнения. Для написания кода проще всего использовать текстовый редактор Notepad++, который поддерживает множество форматов текстовых файлов, выполняет подстветку служебных слов в коде приложения. Однако при этом исполнение реализуется во внешнем браузере. Другим решением является использование специальных сред разработки, к которым относятся NetBeans и Eclipse. Оба пакета разработчика бесплатны. Достаточно скачать и установить на локальной машине. Существуют и другие более развитые среды, такие как Adobe Dreamweaver или phpDesigner. Но они платные. При написании кода примерного приложения использовался комплекс XAMPP и среда Eclipse. Новую версию комплексного пакета можно найти здесь, а последнюю версию среды написания кода Eclipse найдете здесь. После установки комплекса XAMPP на рабочем столе обычно появляется соответствующий ярлык панели управления северами. Панель управления запускается в режиме администратора. В результате запуска появляется управляющее окно.



Для работы с проектом требуется запустить WEB-сервер и сервер баз данных MySQL, как это показано на данном рисунке. Файлы исходных кодов проекта располагаются в папке htdocs установочного каталога XAMPP. Сам установочный каталог лучше всего разместить где-то на системном разделе диска. Например, так, как это показано на следующем рисунке.



Доступ к исполнению приложения реализуется либо через внутренний браузер среды Eclipse, либо через внешний браузер. Для проекта, конечно, должна быть предусмотрена в каталоге htdocs отдельная папка. Название папки пишется на латинице. Хорошо, если оно будет осмыленным. Тогда самому же разработчику будет легче ориентироваться в собственных проектах. В данном пояснении будет реализована система обработки учебной информации "Деканат". Вот и назовем папку проекта decanat, разместив ее в каталоге htdocs. В этой папке будут находиться все файлы проекта. Стартовый файл должен иметь имя index.php и находиться в папке decanat. Теперь для вызова стартового файла из браузера достаточно написать в его адресной строке команду http://localhost/decanat/. Имя и расширение стартового файла указывать не обязательно. По умолчанию имя всегда будет здесь index.php.

2. База данных

На первом этапе проектирования создается макет структуры базы, где будут хранится данные, доступные обработке в системе. Эта работа не поддается формализации. Структура базы целиком и полностью зависит от рассматриваемой предметной области и уровня квалификации разработчиков. Можно лишь посоветовать выделить в предметной области обособленные объекты и связывающие их процессы. Каждый такой объект или процесс формально описывается таблицей в базе. Таблица обязательно имеет первичный ключ. Так поддерживается внутрення целостность данных. Таблица может иметь внешние ключи, связывающие ее с другими таблицами. Это уже внешняя целостность данных. Макет структуры можно создавать в любой предназначенной для этого среде. Чаще всего для простых баз данных используется Microsoft Access. Среда простая и интуитивно понятная.



На рисунке представлена структура информационной среды "Деканат". Она состоит из таблиц, каждая из которых свою информационную нагрузку. Таблица "Специальность" считается здесь ведущей. В ней находятся коды и названия учебных специальностей, по которым в данном учебном заведении реализуется образовательный процесс. Объекты "Дисциплина" и "Студент" берут информацию от объекта "Специальность", то есть они уже являются зависимыми, подчиненными объекту "Специальность". Нет студента без специальности, которой он учится. И нет дициплины вне специальности. У дисциплин с одинаковыми названиями на разных специальностях своя специфика, свое число часов, свои рабочие программы. Объект "Форма контроля знаний" независим. Это подтверждается тем, что во всех учебных заведениях эти формы одинаковы. Везде есть зачеты, экзамены, курсовые работы, проекты и пр. И вот, наконец, главное, что делается в деканате. Фиксируется успеваемость студентов. Таблица успеваемости подчинена всем. Она берет информацию от таблицы "Дисциплина", "Студент", "Форма контроля знаний". Успеваемость - это процесс. Таблица "Успеваемость" постоянно дополняется новыми строками, каждая из которых есть фиксация оценки студента по той или иной дисциплине, в той или иной форме. Конечно, информационную среду "Деканат" можно расширять. Можно, скажем, ввести новую таблицу "Преподаватель", которая будет содержать инофрмацию о преподавателях учебного заведения. Однако такое дополнение потянет за собой следующие объкты и процессы. База данных выйдет за рамки своего первичного предназначения. Надо где-то ограничиться.

Неформальная составляющая работы с базой данных заканчивается, когда макет структуры базы готов. Теперь настала пора создать реальную структуру базы в системе MySQL. Для этого в текстовом редакторе пишется SQL-запрос на создание базы данных и ее таблиц. Вот пример такого запроса.

	/* создание новой базы данных "Деканат"                        */
    create database `Деканат` default character set 'utf8' collate 'utf8_unicode_ci';
    /* активизация базы данных "Деканат"                           */
    use `Деканат`;
    /* со здание таблицы "Специальность" в базе данных "Деканат"   */
    create table `Специальность` (
	   `Код специальности`		varchar(15),
	   `Название специальности`	varchar(100),
	   primary key			(`Код специальности`)
    ) engine InnoDB;
    /* создание таблицы "Форма контроля знаний" в базе "Деканат"   */
    create table `Форма контроля знаний` (
	   `Код формы контроля`		tinyint,
	   `Название формы контроля`	varchar(20),
	   primary key			(`Код формы контроля`)
    ) engine InnoDB;
    /* создание таблицы "Студент" в базе данных "Деканат"          */
    create table `Студент` (
	    `Номер зачетной книжки`		varchar(10),
	    `Фамилия`			varchar(25),
	    `Имя`				varchar(20),
	    `Отчество`			varchar(20),
	    `Дата рождения`			date,
	    `Место проживания`		varchar(40),
	    `Код специальности`		varchar(15),
	    `Год зачисления`		smallint,
	    `Код группы`			varchar(10),
	    primary key			(`Номер зачетной книжки`),
	    foreign key			(`Код специальности`)
	    				references `Специальность` (`Код специальности`)
		    			on delete cascade
			    		on update cascade
    ) engine InnoDB;
    /* создание таблицы "Дисциплина" в базе данных "Деканат"       */
    create table `Дисциплина` (
	    `Код дисциплины`		varchar(15),
	    `Код специальности`		varchar(15),
	    `Название дисциплины`		varchar(50),
	    `Количество часов`		smallint,
	    primary key			(`Код дисциплины`),
	    foreign key			(`Код специальности`)
		    			references `Специальность` (`Код специальности`)
			    		on delete cascade
				    	on update cascade
    ) engine InnoDB;
    /* создание таблицы "Успеваемость" в базе данных "Деканат"     */
    create table `Успеваемость` (
	    `Время записи`			timestamp	default CURRENT_TIMESTAMP,
	    `Номер зачетной книжки`		varchar(10),
	    `Код дисциплины`		varchar(15),
	    `Форма контроля`		tinyint,
	    `Номер семестра`		tinyint,
	    `Оценка`			tinyint,
	    primary key			(`Время записи`),
	    foreign key			(`Номер зачетной книжки`)
	    				references `Студент` (`Номер зачетной книжки`)
		    			on delete cascade
			    		on update cascade,
	    foreign key			(`Код дисциплины`)
		    			references `Дисциплина` (`Код дисциплины`)
			    		on delete cascade
				    	on update cascade,
	    foreign key			(`Форма контроля`)
		    			references `Форма контроля знаний` (`Код формы контроля`)
			    		on delete cascade
				    	on update cascade
    ) engine InnoDB;
	

Здесь создается база данных "Деканат", соответствующая макету, выполненному в среде MS Access. Для реализации работы запроса воспользуемся менеджером баз данных phpMyAdmin, приложенным к комплексному установочному пакету XAMPP. Набираем адрес http://localhost/phpmyadmin в строке браузера. В окне браузера появляется примерно такое окно.



В левой колонке отображены существующие в системе базы данных по умолчанию. Это системные базы, не нужно пока к ним обращаться, тем более их удалять. Верхняя строка - основное меню менеджера. Есть и дополнительные пункты меню, которые не уместились в строке. Они, эти пункты прячутся под интригующим словом "еще". Из всего дополнительного набора выбирается пункт "Импорт".



Переходя к этому пункту, открываем окно импорта. Оказывается, импортировать базу данных можно различными способами. Можно посмотреть выпадающий список "Формат" при прокрутке окна. Однако пока интересен только вариант импорта через текстовый SQL-файл.



Кнопка "Обзор" позволяет выбрать нужный SQL-файл на диске. Однако перед выбором следует решить вопрос с кодировкой текста. Кодировка, принятая на сервере UTF-8. Именно в этой кодировке и надо создавать свой SQL-файл запросов. В противном случае в самом начале текста SQL-файла требуется команда set names(...), указывающая тип кодировки текстового содержимого файла. Выбрав созданный для системы "Деканат" SQL-файл, следует выполнить прокрутку окна и нажать кнопку выполнения запроса "Вперед".



Если при выполнении запроса "красные окна" не возникали, то запрос выполнен и база данных создана. Выбор пункта главного меню менеджера "Базы данных" открывает список баз. Выбор вновь созданной базы данных позволяет проверить ее структуру. Результат выбора как раз и показан на последнем рисунке. База данных пуста. Заполнять ее не надо. Вся работа с данными будет проводиться в дальнейшем через WEB-интерфейс создаваемого приложения. Структуру базы можно проверить и с помощью дизайнера, также имеющегося в менеджере phpMyAdmin. Правда, в некоторых последних версиях дизайнер не показывает связи между таблицами.

3. Контроллер

Контроллером в обиходе WEB-программирования называют основную часть приложения, предназначенную для взаимодействия между пользователями и данными на сервере. Пользователь, конечно, обращается к данным через WEB-интерфейс, но большую часть работы по передаче данных выполняет именно контроллер. Пишут контроллеры на различных языках программирования. Если требования к быстродействию приложения высокие, то приходится писать на C/C++. Однако при небольшом объеме трафика можно выполнить контролер на PHP или другом языке-интерпретаторе. В последнее время часто используется язык-интерпретатор JAVA. Здесь будет представлен контроллер системы обработки данных "Деканат", выполненный на языке PHP.

Программа контроллера в PHP имеет "матрешечный" вид. Если кто не помнит, матрешка - это деревянная игрушка, похожая на фигурный бочонок. Она разрисована под русскую бабу. Открываешь такой бочонок, а там следующая матрешка. Только меньших размеров. И так далее до самой маленькой матрешки. Точно также устроен и контроллер на PHP. Программа может состоять из множества файлов или, как их называют, скриптов. Стартовый скрипт, конечно, называется index.php, но с помощью команд включения require_once() в него встраиваются другие скрипты. В них также могут находиться команды включения следующих скриптов. Получается даже не матрешка, а целое дерево включений.



Главная задача всякого контроллера - получать данные от сервера баз данных и отправлять их пользователю в удобном для чтения виде. Поэтому начинать надо с того, чтобы получить доступ к данным. Параметрами доступа являются логин и пароль, которые принимает сервер баз данных. Он же и предоставляет доступ по этим параметрам. Чтобы в каждом сеансе связи с сервером не вводить параметры, удобно записать их в специальный скрипт. Скажем, login.php. Его можно включить в скрипт более высокого уровня, чтобы параметры вводились каждый раз автоматически. Вот пример такого скрипта.

	// идентификация при подключении к базе:
	// название хоста;
	$db_hostname = "localhost";
	// название базы данных;
	$db_database = "Деканат";
	// имя пользователя;
	$db_username = "root";
	// пароль пользователя;
	$db_password = "";
	

Подключение к серверу баз данных реализовано в следующем скрипте connect.php, который формирует переменную-дескриптор подключения $db_connect. Здесь же выполняется проверка подключения. Если переменная $db_connect нулевая, значит, подключения нет. Выполнение всей программы остановлено.

	// включение в скрипт пользовательских данных;
	require_once 'login.php';
	// подключение к базе данных;
	$db_server = mysqli_connect($db_hostname, $db_username, $db_password);
	// если подключение не состоялось, то вывести сообщение об ошибке;
	if(!$db_server) exit("Ошибка: ".mysqli_error($db_server));
	

Заметим, что параметры подключения $db_hostname, $db_username, $db_password не формируются в текущем скрипте connecnt.php. Они берутся из файла login.php, который включен в текущий скрипт командой require_once(). Если никаких ошибок нет, если правильно указаны параметры подключения, то контроллер подключен к серверу MySQL и может получать данные. Но на сервере существует множество баз данных. Надо выбрать ту, которая относится к нашей учебной системе, которая заранее сформирована, имеет известное нам имя "Деканат" и собственные параметры доступа. Выбор базы отображает следующий скрипт selectbase.php.

	require_once 'connect.php';
	// выбор имеющейся базы данных;
	mysqli_query($db_server, "use `Деканат`;") or die("Ошибка: ".mysqli_error($db_server));
	

Здесь выполняется всего один запрос на подключение к базе данных. Все параметры и переменные берутся из включенных ранее скриптов. Конечно, можно было бы все приведенные команды включить в один скрипт. Это зависит от вкуса разработчика. Столь мелкие разбиения удобны, если требуется изменить какие-либо параметры подключения к серверу или базе. Теперь, когда выбрана база данных, можно рассмотреть главную распределительную станцию нашего контроллера. Это скрипт index.php. Вот его основная часть.

	//------------------------------------------------------
	// если от клиента по почте пришел элемент массива menu, тогда...
	if(isset($_GET["menu"]) && !empty($_GET["menu"])) {
		// из элемента массива создаем переменную $menu
		$menu = $_GET["menu"];
		// в зависимости от номера пункта выбор соответствующего
		// скрипта для работы с таблицей
		switch($menu) {
			// подключение к таблице специальностей
			case '1': require_once 'speciality.php';  break;
			// подключение к таблице студентов
			case '2': require_once 'student.php';     break;
			// подключение к таблице предметов
			case '3': require_once 'discipline.php';  break;
			// подключение к таблице форм контроля
			case '4': require_once 'controlform.php'; break;
			// поключение к таблице успеваемости
			case '5': require_once 'results.php';     break;
		}
	}
	// если по почте ничего не пришло, например, при первом
	// запуске скрипта, то печатаем исходную таблицу меню
	else {
		$tablemenu = _<<<TABLEMENU
	<table border="0" cellspacing="2" cellpadding="3">
	<tr>
	<td class="hcells"><a href="./index.php?menu=1">Специальности</a></td>
	<td class="hcells"><a href="./index.php?menu=2">Студенты</a></td>
	<td class="hcells"><a href="./index.php?menu=3">Предметы</a></td>
	<td class="hcells"><a href="./index.php?menu=4">Формы</a></td>
	<td class="hcells"><a href="./index.php?menu=5">Успеваемость</a></td>
	</tr>
	</table>
	_TABLEMENU;
		// печать исходной таблицы меню
		echo $tablemenu;
	}
	


Не рассматривая стилевые особенности вывода страницы, обратим внимание на то, что задачей нашей станции является распределение дальнейшей работы между таблицами базы. Для этого на странице показано меню. Она, страница появляется при первом запуске. Если же выбран один из пунктов меню, то на сервер приходит значение переменной $menu, в соответствии с которым выбирается тот или иной объект системы, та или иная таблица. И, соответствено, включается один из подчиненных скриптов, работающих с таблицами. Конечно, стартовую страницу можно разукрасить. Добавить картинки, изменить стиль. Однако смысл работы станции останется тем же. Смысл в том, чтобы распределять дальнейшую работу с таблицами. Надо только помнить, что существуют ведущие и ведомые, зависимые таблицы. Если база пуста, то заполнение начинается с ведущих таблиц, со справочников. Например, открытие страницы "Студент" приведет к сообщению о том, что таблица "Специальность" пуста. Надо бы ее сначала заполнить. Студента без специальности не бывает. Таким образом, двигаясь от ведущих таблиц, приходим к таблице "Успеваемость", где ставим оценки студентам по заданным дисциплинам в заданной форме.

4. Обработка данных

Если выбран пункт меню "Специальность", то команда require_once() выполняет вставку скрипта speciality.php в индексный скрипт. Тогда в браузере появляется следующее окно.



Текст скрипта speciality.php представлен ниже.

	// определение пути к корневому каталогу web-сервера;
	$path = $_SERVER["DOCUMENT_ROOT"];
	// подключение библиотеки Smarty;
	require_once $path.'/Smarty/Smarty.class.php';
	//------------------------------------------------------
	// создание нового объекта шаблона;
	$smarty = new Smarty();
	// определение рабочих каталогов Smarty;
	$smarty->template_dir =$path."/decanat/smarty/templates";
	$smarty->compile_dir =$path."/decanat/smarty/compiles";
	$smarty->cache_dir =$path."/decanat/smarty/cache";
	$smarty->config_dir =$path."/decanat/smarty/config";
		
	// подключение к базе данных "Деканат";
	require_once 'selectbase.php';
	//------------------------------------------------------
	// проверка пришедших по почте значений;
	if(isset($_POST["speciality_code"])) $code = $_POST["speciality_code"];
	if(isset($_POST["speciality_name"])) $name = $_POST["speciality_name"]; else $name = "";
	//------------------------------------------------------
	// если пришла команда на вставку данных, то записать данные в таблицу;
	if(isset($_POST["insert"]) && isset($code)) {
		$query = "insert into `Специальность` values('$code', '$name');";
		if(!mysqli_query($db_server, $query)) exit("Ошибка: ".mysqli_error($db_server));
	}
	// если пришла команда на удаление данных, то удалить запись из таблицы;
	if(isset($_POST["delete"]) && isset($code)) {
		$query = "delete from `Специальность` where `Код специальности`='$code';";
		if(!mysqli_query($db_server, $query)) exit("Ошибка: ".mysqli_error($db_server));
	}
	//------------------------------------------------------
	// создание списка специальностей и запись их в массив;
	$query = "select * from `Специальность`;";
	$reslt = mysqli_query($db_server, $query);
	// создание пустого массива $data;
	$data = array();
	// если указатель на набор данных не пустой, то записать данные в массив;
	if($reslt) while($row = mysqli_fetch_array($reslt)) $data[] = $row;
	//------------------------------------------------------
	// передача данных в шаблон;
	$smarty->assign("data", $data);
	// представление шаблона ввода специальностей;
	$smarty->display($path."/decanat/smarty/templates/speciality.tpl");
	// закрытие подключения к серверу баз данных;
	mysqli_close($db_server);
	

Заполнение текстовых полей и выбор кнопки "Добавить" приводит к появлению в окне браузера информации о некоторых специальностях. Например, так.



Каждая строка специальности снабжена кнопкой "Удалить". Нажатие кнопки приводит к удалению строки в таблице "Специальность" и к обновлению представления данных таблицы.



Рассмотрим работу скрипта speciality.php. Первые его строки предназначены для подключения специальной библиотеки Smarty, предназначенной для представления данных на странице. Той же командой require_once() подключается стартовый файл библиотеки и создается переменная-объект $smarty. Эта переменная распоряжается директориями, компиляцией и обменом данных между текущим скриптом и создаваемой страницей представления. Далее подключается база данных "Деканат", проверяются пришедшие данные. В соответствии со структурой таблицы это код специальности и ее название. Оба значения записываются в переменные $code и $name. Теперь вопрос: пришли данные для добавления или для удаления. Почта принесла значение insert. Обе переменные $code и $name записываются в таблицу "Специальность". В таблице появляется новая строка. Или по-другому. Почта принесла значение delete. Тогда выполняется другой запрос на удаление строки из таблицы с заданным кодом специальности. Если все необходимые изменения проведены, то выполняется вывод таблицы. Сначала выполняется запрос на ее чтение, затем данные, полученные по запросу записываются в специальный массив $data. Следующий набор команд будет использоваться постоянно.

	// создание пустого массива $data;
	$data = array();
	// если указатель на набор данных не пустой, то записать данные в массив;
	if($reslt) while($row = mysqli_fetch_array($reslt)) $data[] = $row;
	

Здесь сначала создается пустая переменная-массив. Потом функция mysqli_fetch_array() по дексриптору запроса $reslt вынимает данные в массив построчно. Наконец, массив $data заполнен. Теперь созданная ранее переменная $smarty отправляет массив в шаблон speciality.tpl для показа на странице в браузере.