Простая MVC модель. (Оценка: +2)

Печать / RSS-лента
Статью писал для своего сайта, но по некоторым причинам решил все свои статьи перезалить сюда (что бы не утерять)!

Model View Controller позволяет разделить данные, представление и обработку действий пользователя на три отдельных компонента.

Модель (Model). Модель предоставляет данные (обычно для View), а также реагирует на запросы (обычно от контроллера), изменяя своё состояние.
Представление (View). Отвечает за отображение информации (пользовательский интерфейс).
Поведение (Controller). Интерпретирует данные, введённые пользователем, и информирует модель и представление о необходимости соответствующей реакции.
---------------------------------------------------------------------------------------------------
Как-то задался вопросом о работе MVC, и не имея представления о реализации, я искал в гугле решение своего вопроса!
Гугл привел меня к вот этой статье http://habrahabr.ru/blogs/php/31270/
Я поглядел на "это" все, и решил попробовать! Особого удовлетворения от работы с данной моделью я не ощущал, и решил проблему по своему...

Вот так выглядит структура моей модели:

|- /includes/
|- /includes/classes/
|- /includes/classes/MVC_BaseController.class.php
|- /includes/classes/MVC_Registry.class.php
|- /includes/classes/MVC_Router.class.php
|- /includes/classes/TestClass.class.php
|- /includes/controllers/
|- /includes/controllers/home/
|- /includes/controllers/home/index.cont.php
|- /includes/setting/
|- /includes/setting/core.inc.php
|- /.htaccess
|- /index.php


Приступим к .htaccess

# Указываем индексный файл.
DirectoryIndex index.php
Options -Indexes
# Указываем кодировку.
AddDefaultCharset UTF-8

RewriteEngine on
# modDir: Узнаем папку к модели
# modFile: Узнаем файл модели.
# modVar: Узнаем переменные.
RewriteRule ^([a-z]{3,10})($|/)($|[a-zA-Z0-9]{3,10})($|/)($|[a-z0-9;:_]{3,30})? index.php?modDir=$1&modFile=$3&modVar=$5 [L,QSA]

Т.е теперь у нас url будет выглядеть так: http://example.com/home/index/id:1

Переходим к index.php

<?php
// Включаем на время отладки вывод ошибок.
error_reporting(E_ALL);

// Узнаем корневую директорию.
$pathRoot = realpath(dirname(__FILE__)).'/';
// Для ОС Windows заменяем слеш, и записываем.
define('SITE_PATH_ROOT', str_replace('\\', '/', $pathRoot));

// Подключаем конфигурационный файл.
require_once('includes/settings/core.inc.php');

На этом мы и закончим пока что работу над index.php.

Теперь можно приступить к самой структуре MVC, и первое что мы будем делать, это класс для передачи значений в в контроллер.
Класс будет состоять из двух магических методов __set() и __get().

Создадим файл /includes/classes/MVC_Registry.class.php в котором создаем класс MVC_Registry

<?php

class MVC_Registry {

// Массив с переменными.
private $_vars = array();

/**
* __set
*
* Присваиваем переменным значения.
*
* @param string $name Имя переменной.
* @param mixed $val Значение переменной.
* @return bool
**/
public function __set($name, $val)
{

if (empty($this -> _vars[$name]) == false) {
return false;
}


$this -> _vars[$name] = $val;
return true;
}


/**
* __get
*
* Возвращаем значение переменной.
*
* @param string $name Имя переменной.
* @return mixed
**/
public function __get($name)
{

if (empty($this -> _vars[$name]) == true) {
return null;
}

return $this -> _vars[$name];
}
}

?>


Теперь этот класс надо подключить в index.php, и это мы сделаем при помощи магического метода __autoload().
Создадим файл /includes/setting/core.inc.php и пишем в нем следующее:

<?php

function __autoload($name)
{
// Добавляем прификс к названию класса.
$fileName = $name.'.class.php';
// Узнаем категорию в которой лежит класс.
$fileDir = SITE_PATH_ROOT.'/includes/classes/'.$fileName;

// Проверяем существует ли такой класс, или нет.
if (is_file($fileDir) == false) {
return true;
}

// Подключаем файл с классом.
include_once($fileDir);
}

// Теперь можно создать объект класса MVC_Registry, что бы не гадить в index.php.
$mvcRegistry = new MVC_Registry;
?>


Перейдем к самой главной части MVC, к маршрутизатору.
Маршрутизатор у нас отвечает за то, что нам должен выдать скрипт! если точнее, то он указывает в какой папке искать модель, какой файл подключать, и что выводить.
Класс будет содержать в себе 3 метода: __construct(), _getController(), getModul()

<?php

class MVC_Router {

// Массив со значениями.
private $_registry;

// Папка с контроллерами.
private $_path = '/includes/controllers/';

// Массив со стандартным контроллером.
private $_arrModul = array(
'dir' => 'home/',
'file' => 'index.cont.php'
);


/**
* __construct
*
* @param array $registry Массив со значениями.
*
**/
public function __construct($registry)
{
$this -> _registry = $registry;
}



/**
* _getController
*
* Узнаем путь к файлу модуля для дальнейшего его подключения.
*
**/
private function _getControllerClass()
{

// Проверяем указана ли папка с контроллером.
if (!empty($_GET['modDir'])) {

// Проверяем существует ли категория с указанным контроллером.
if (is_dir($this -> _path . $_GET['modDir'] . '/') === true) {

// Записываем указанную категорию.
$this -> _arrModul['dir'] = $_GET['modDir'] . '/';

}

// Проверяем указан ли контроллер, если он не указан, то пытаемся указать как index.
$_GET['modFile'] = empty($_GET['modFile']) ? 'index' : $_GET['modFile'];

// Проверяем существует ли файл контроллера
if (is_file($this -> _path . $this -> _arrModul['dir'] . '/' . $_GET['modFile'] . '.modul.php') === true) {

// Записываем указанный контраллер.
$this -> _arrModul['file'] = $_GET['modFile'] . '.modul.php';

}
}

// Записываем путь к файлу контроллера.
$this -> modulFile = SITE_PATH_ROOT . $this -> _path . $this -> _arrModul['dir'] . $this -> _arrModul['file'];

}



/**
* getModul
*
* Подключаем класс модуля, и выводим результат.
*
**/
public function getController()
{

// Узнаем путь к контроллеру.
$this -> _getControllerClass();

// Подключаем контроллер.
include_once ($this -> modulFile);

// Создать объект класса DisplayController
$controller = new DisplayController($this -> _registry);
// Выводим результат выполнения контроллера.
$controller -> display();
}

}

?>


Теперь в файле index.php добавим еще пару строк? в которых мы запускаем маршрутизатор, и выводим контроллер.

<?php
// Создадим объект класса MVC_Router
$mvcRouter = new MVC_Router($mvcRegistry);
// Подключаем контроллер.
$mvcRouter -> getController();
?>


Все готово! Теперь можно создавать контроллер!
Думаю у вас возник вопрос "Неужели нам придется каждый раз создавать конструктор класса DisplayController?", конечно же нет!

Создаем файл /includes/classes/MVC_BaseController.class.php в котором мы создадим абстрактный класс MVC_BaseController который будет выполнять не только подгрузку значений реестра, но и разберать переменные полученные из $_GET.

<?php
abstract class MVC_BaseController {

// Массив со значениями.
protected static $registry = array();



/**
* __construct
*
* @param array $registry Массив со значениями.
*
**/
public function __construct($registry)
{
self :: $registry = $registry;

// Проверяем указанны ли переменные.
if (empty($_GET['modVar']) === false) {

// Делим строку на части.
$aExVar = explode(';', $_GET['modVar']);

// Если в строке есть хоть одна переменная, то работаем дальше.
if (empty($aExVar) === false) {

$vars = array();

foreach ($aExVar as $aKey) {

// Делим строку на ключ и значение.
$aExValue = explode(':', $aKey);

// Проверяем есть ли в строке ключ и значение.
if (empty($aExValue[0]) === false and empty($aExValue[1]) === false) {

// Записываем переменную.
$vars[$aExValue[0]] = $aExValue[1];

}
}
}
// Пишем полученные переменные в глобальный массив $_GET
$_GET = array_map('trim', $vars);
}
}

// Указываем метод displey() как абстрактный.
abstract function display();
}
?>


Самое главное мы сделали, осталось дело за малым! Создаем файл контроллера /includes/controllers/home/index.cont.php
И в нем мы пишем следующее:

<?php
class DisplayController extends MVC_BaseController {

public function display()
{

echo 'Hello World';

}

}
?>


Посмотрев на работу скрипта, результатом у нас будет: Hello World


Теперь можно глянуть применение:

/index.php
<?php
define('SITE_PATH_ROOT', str_replace('\\', '/', realpath(dirname(__FILE__))).'/');

include_once ('includes/settings/core.inc.php');

$mvcRegistry -> testClass = new TestClass();

$mvcRouter = new MVC_Router($mvcRegistry);
$mvcRouter -> getController();
?>
/includes/classes/TestClass.class.php
<?php
class TestClass {

public function testMethod($str)
{
return 'I love '.$str;
}
}

?>
/includes/controllers/home/index.cont.php
<?php
class DisplayController extends MVC_BaseController {

public function display()
{
echo 'Hello World <br />' . self :: $registry -> testClass -> testMethod('Moscow');
}

}
?>

Результат выполнения:

Hello World
I love Moscow

------------------------------------
Подготовил статью: Nu3oN специально для http://7je.ru
Автор статьи: AxqpxA (16.11.11 / 20:18)
php, mvc, BaseController, Registry, Router
Рейтинг: +2
Просмотров: 2203
Комментарии (6) »