
- •Краматорськ 2012
- •Содержание
- •Введение
- •Лабораторная работа №1 Проектирование Web-приложений
- •Краткие теоретические сведения
- •Пример технического задания:
- •Лабораторная работа №2 cms Joomla. Панель управления
- •Лабораторная работа №3 cms Joomla. Наполнение материалом
- •Лабораторная работа №4 cms Joomla. Подключение расширений. Добавление форума
- •Лабораторная работа №5 cms Joomla. Социальная сеть
- •Лабораторная работа №6 cms Joomla. Ведение блога
- •Лабораторная работа №7 Управление интернет - магазином VirtueMart на основе cms Joomla
- •Лабораторная работа №8 Разработка приложений с помощью php
- •Функция in_array
- •Функция array_search
- •Лабораторная работа №9 Разработка приложений бд на cервере MySql с помощью php
- •Установка соединения
- •Выбор базы данных
- •Получение списка полей таблицы
- •Отображение списка полей в html-форму
- •Запись данных в базу данных
- •Лабораторная работа №10 Разработка модулей с использованием mvc фреймворка
- •Краткие теоретические сведения mvc Фреймворк
- •Класс Router
- •Представление
- •Лабораторная работа №11 Разработка компонент для cms Joomla. Разработка простого компонента для пользовательской части
- •Лабораторная работа №12 Разработка компонент для cms Joomla. Разработка компонента с использованием базы данных
- •Лабораторная работа №13 Разработка компонент для cms Joomla. Разработка компонента с административной частью
- •Список рекомендованной литературы
- •7/2005. Підп. До друку Формат 60х84/16.
- •84313, М. Краматорськ, вул. Шкадінова, 72
Лабораторная работа №10 Разработка модулей с использованием mvc фреймворка
Цель работы: получить практические разработки приложений с использованием MVC фреймворка.
Краткие теоретические сведения mvc Фреймворк
Схема взаимодействия в Model-view-controller (паттерн модель-представление-контроллер) приведена на рисунке 10.1. В 1979 году его описал Тригве Реенскауг в своей работе «Разработка приложений на Smalltalk-80: как использовать Модель-представление-контроллер». С тех пор паттерн зарекомендовал себя как очень удачная архитектура программного обеспечения.
Рисунок 10.1 – Паттерн модель-представление-контроллер
Пользователь, работая с интерфейсом, управляет контроллером, который перехватывает действия пользователя. Далее контроллер уведомляет модель о действиях пользователя, тем самым изменяя состояние модели. Контроллер также уведомляет представление. Представление, используя текущее состояние модели, строит пользовательский интерфейс. Основой паттерна является отделение модели данных приложения, его логики и представления данных друг от друга. Таким образом, следуя правилу «разделяй и властвуй», удается строить стройное программное обеспечение, в котором, во-первых, модель не зависит от представления и логики, а во-вторых, пользовательский интерфейс надежно отделен от управляющей логики.
На данный момент паттерн MVC реализован в том или ином виде для большинства языков программирования используемых для разработки web-приложений. Самое большое количество реализаций имеет PHP, но и для Java, Perl, Python, Ruby есть свои варианты.
«M» или модель – часть MVC-системы, которая отвечает за запросы к базе данных (или другому внешнему источнику) и предоставление информации контроллеру. Можно было бы загружать необходимую модель в зависимости от запроса, но возможно немного стереть границы между моделью и контроллером, т.е. контроллер работает с БД непосредственно через библиотеку взаимодействия с БД, нежели чем через отдельную модель.
Например, нужно написать код, необходимый для установки соединения с БД и поместить его в index.php. Существует множество библиотек для работы с БД, но в PHP 5 уже есть такая библиотека – PDO.
Вставим следующий код в файл index.php (после подключения файла инициализации):
# Соединяемся с БД
$db = new PDO('mysql:host=localhost;dbname=demo', '[user]', '[password]');
$registry->set ('db', $db);
В этом примере сначала создаём новый экземпляр библиотеки PDO и соединяемся с БД MySQL. Потом создаем переменную $db доступной глобально при помощи класса Registry.
Модельная компонента системы готова, поэтому перейдём к написанию контроллера.
Написание контроллера подразумевает также и написание класса Router, ответственного за загрузку нужного контроллера в зависимости от запроса (в index.php через URL передаётся переменная $route).
Класс Router
Класс Router будет разбирать запрос, а потом загружать требуемый контроллер. Создадим «скелет» класса:
<?php
Class Router {
private $registry;
private $path;
private $args = array();
function __construct($registry) {
$this->registry = $registry;
}
}
?>
Затем добавим следующие строки в index.php:
# Загружаем router
$router = new Router($registry);
$registry->set ('router', $router);
Мы добавили класс Router в нашу MVC-систему, но он пока ничего не делает, поэтому добавим в него методы, необходимые для работы. Первая вещь, которую напишем, это метод setPath() для установки директории, где будут лежать все контроллеры. Метод выглядит следующим образом и должен быть добавлен в класс Router:
function setPath($path) {
$path = trim($path, '/\\');
$path .= DIRSEP;
if (is_dir($path) == false) {
throw new Exception ('Invalid controller path: `' . $path . '`');
}
$this->path = $path;
}
Потом добавим следующие строки в index.php:
$router->setPath (site_path . 'controllers');
Теперь, когда установили путь к контроллерам, напишем сам метод, ответственный за загрузку контроллера. Этот метод будет называться delegate(), он и будет анализировать запрос. Первый кусочек этого метода такой:
function delegate() {
// Анализируем путь
$this->getController($file, $controller, $action, $args);
Он использует ещё один метод, getController(), чтобы получить название контроллера и несколько других переменных. Этот метод выглядит так:
private function getController(&$file, &$controller, &$action, &$args) {
$route = (empty($_GET['route'])) ? '' : $_GET['route'];
if (empty($route)) { $route = 'index'; }
// Получаем раздельные части
$route = trim($route, '/\\');
$parts = explode('/', $route);
// Находим правильный контроллер
$cmd_path = $this->path;
foreach ($parts as $part) {
$fullpath = $cmd_path . $part;
// Есть ли папка с таким путём?
if (is_dir($fullpath)) {
$cmd_path .= $part . DIRSEP;
array_shift($parts);
continue;
}
// Находим файл
if (is_file($fullpath . '.php')) {
$controller = $part;
array_shift($parts);
break;
}
}
if (empty($controller)) { $controller = 'index'; };
// Получаем действие
$action = array_shift($parts);
if (empty($action)) { $action = 'index'; }
$file = $cmd_path . $controller . '.php';
$args = $parts;
}
Разберем подробно этот метод. Сначала он берёт значение переменной $route из запроса, потом разбивает его на части с помощь функции explode(). Например, запрос «members/view» преобразуется в такой массив: array(‘members’, ‘view’).
Потом при помощи цикла foreach он проходит по каждой части и проверяет, является ли эта часть директорией. Если является, то он приписывает её к пути до файла и проверяет следующую часть. Это позволяет поместить контроллеры в поддиректориях и, таким образом, получить иерархию контроллеров. Если же текущая часть запроса не является директорией, но является файлом, она сохраняется в переменную $controller, и выходим из цикла, так как нашёлся контроллер, который нам нужен.
После цикла проверяем переменную с именем контроллера. Если она пустая, то используем контроллер «index», который будет контроллером по умолчанию. Потом метод определяет действие, которое необходимо выполнить. Контроллер – это класс, который состоит из нескольких методов. Действие же указывает на конкретный метод. Если действие не указано, будем использовать «index» — действие по умолчанию.
И, наконец, получаем полный путь до файла контроллера, объединяя три переменные: путь, имя контроллера и расширение «php».
Теперь, когда проанализировали запрос, пора вызывать метод delegate() для загрузки контроллера и выполнения действия. Полностью метод delegate() выглядит так:
function delegate() {
// Анализируем путь
$this->getController($file, $controller, $action, $args);
// Файл доступен?
if (is_readable($file) == false) {
die ('404 Not Found');
}
// Подключаем файл
include ($file);
// Создаём экземпляр контроллера
$class = 'Controller_' . $controller;
$controller = new $class($this->registry);
// Действие доступно?
if (is_callable(array($controller, $action)) == false) {
die ('404 Not Found');
}
// Выполняем действие
$controller->$action();
}
Проанализировав запрос при помощи метода getController(), проверяем, существует ли в действительности файл, и, если нет, то возвращаем простое сообщение об ошибке. После этого подключаем файл с контроллером и создаём экземпляр его класса, называться который должен «Controller_[имя]». Потом мы проверяем, есть ли указанное действие (т.е. метод) и возможно ли к нему обратиться (используем для этого функцию is_callable()).
Написав полностью метод delegate(), добавим следующую строчку в файл index.php:
$router->delegate();
Если попробовать сейчас запустить систему, то мы увидим следующую ошибку (разумеется, если директории controllers ещё нет):
Fatal error: Uncaught exception 'Exception' with message 'Invalid controller path: `g:\Projects\PHPit\content\simple mvc php5\demo\controllers\`' in g:\Projects\PHPit\content\simple mvc php5\demo\classes\router.php:18 Stack trace: #0 g:\Projects\PHPit\content\simple mvc php5\demo\index.php(13): Router->setPath('g:\Projects\PHP...') #1 {main} thrown in g:\Projects\PHPit\content\simple mvc php5\demo\classes\router.php on line 18
Или же увидим ошибку «404 Not Found», так как ещё нет ни одного контроллера.
Контроллер
Контроллеры в MVC-системе будут достаточно простыми и потребуют совсем немного времени. Во-первых, удостоверимся, что директория controllers существует. Создадим файл controller_base.php в директории classes и вставим в него следующий код:
<?php
Abstract Class Controller_Base {
protected $registry;
function __construct($registry) {
$this->registry = $registry;
}
abstract function index();
}
?>
Этот абстрактный класс будет родительским классом для всех наших контроллеров. Он будет делать всего лишь две вещи: сохранять локальную копию класса Registry и при помощи абстрактного метода index() заставлять все дочерние контроллеры реализовывать этот метод.
Напишем первый контроллер. Создадим файл index.php в директории controllers и вставим в него такой код:
<?php
Class Controller_Index Extends Controller_Base {
function index() {
echo 'Hello from my MVC system';
}
}
?>
Напишем ещё один контроллер, который будет соответствовать запросу «members/view». Создадим файл members.php в директории контроллеров и вставим в него такой код:
<?php
Class Controller_Members Extends Controller_Base {
function index() {
echo 'Default index of the `members` controllers';
}
function view() {
echo 'You are viewing the members/view request';
}
}
?>
Только лишь написанием нового контроллера и добавлением в него метода, мы смогли создать новую страницу, и ничего не пришлось менять в самой системе. Кроме того, нашим контроллерам не нужно подключать файл global.php или делать что-нибудь в таком роде. Теперь, когда у нас есть контроллеры, осталась лишь одна вещь: «V» или «View» («Отображение»).