Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
web-пр_МВ_ДЗ_ЛР_1.doc
Скачиваний:
18
Добавлен:
13.11.2019
Размер:
5.4 Mб
Скачать

Лабораторная работа №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» («Отображение»).