Сразу скажу, что я не претендую на премию Дарвина.
И так, задался вопросом написания
простой MVC.
1. Единая точка входа
2. Разделение логики -> model, view, controller
3. В теории всё просто - приступаю
1. .htaccess
AddDefaultCharset UTF-8
#ErrorDocument 404 /404
Options +FollowSymlinks
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^([^/]*)$ index.php?module=pages&url=$1 [QSA,L]
RewriteRule ^main/?$ index.php?module=main [L,QSA]
RewriteRule ^/?$ index.php?module=main [L,QSA]
2. Index.php
session_start();
error_reporting(E_ALL);
ini_set('display_errors', 1);
define('ROOT', dirname(__FILE__));
require_once(ROOT . '/classes/Loader.php');
$router = new Router();
if(($content = $router->start()) !== false){
print $content;
} else {
header("HTTP/1.0 404 Not Found");
header("Status: 404 Not Found");
$_GET['module'] = 'pages';
$_GET['url'] = '404';
print $router->start();
}
if(1)
{
$time_end = microtime(true);
$exec_time = $time_end-$time_start;
echo "<!---\r\n";
echo "Врем загрузки скрипта: " . $exec_time . "\r\n";
foreach ($router->errors() AS $errors){
echo $errors . "\r\n";
}
echo "Автозагрузка: \r\n";
var_dump(spl_autoload_functions());
echo "-->";
}
3. Загрузчик классов Loader.php
spl_autoload_register('Autoload');
spl_autoload_extensions('.php');
function Autoload($class_name) {
if(stristr($class_name, '_') === FALSE){
$class_file = ROOT . '/classes/' . $class_name . '.php';
} else {
$file_type = explode('_', $class_name);
$module = $file_type[0];
$file_type = $file_type[1];
$class_file = ROOT . '/modules/' . $module . '/' . $file_type. '.php';
}
if (is_readable($class_file)){
require $class_file;
} else {
return false;
}
}
4. Router
class Router {
public $request;
public $config;
public $errors;
public function __construct(){
$this->request = new Request();
$this->config = new Config();
$this->errors = new Errors();
}
public function start(){
$module = $this->request->get('module');
$module = preg_replace('/[^A-Za-z0-9]+/', '', $module);
$module = strtolower($module);
$action = $this->request->get('action');
$action = preg_replace('/[^A-Za-z]+/', '', $action);
if(empty($module)){
$module = 'main';
}
if(empty($action)){
$action = 'Index';
}
$controller_class = ucfirst($module) . '_Controller';
$controller_path = ROOT . '/modules/'. $module .'/Controller.php';
$model_path = ROOT . '/modules/'. $module .'/Model.php';
if(!file_exists($controller_path)){
$this->errors->set('Контроллер модуля ' . $module . ' не найден');
return false;
}
if(!file_exists($model_path)){
$this->errors->set('Модель модуля ' . $module . ' не найдена');
}
$controller = new $controller_class;
if(method_exists($controller, $action))
{
print $controller->$action();
} else {
$this->errors->set('Метод ' . $action . ' модуля ' . $module . ' не найден');
return false;
}
}
public function errors(){
return $this->errors->get();
}
}
5. Класс для вывода ошибок Errors.php
class Errors {
public $data = array();
public function set($error)
{
return $this->data[] = $error;
}
public function get()
{
return $this->data;
}
6. Главный контроллер
class Controller {
public $template;
public $request;
public function __construct(){
$this->template = new Template();
$this->request = new Request();
}
}
7. Главная модель
class Model {
public $db;
public function __construct(){
$this->db = new Database();
}
}
Все модули (ROOT . '/modules/папка_с_модулем') наследуют
главную модель и контроллер.. В главном контролле вызываем шаблонизатор. В главной моделе вызываем подключение к бд собсно.
На примере, папка:
modules/test
1. Контроллер: modules/test/Controller.php
2. Модель: modules/test/Model.php
3. Шаблоны модулей (.tpl) хранятся в основной папке шаблона default.
Controller.php
class Test_Controller extends Controller {
public $test;
public function __construct(){
parent::__construct();
$this->test= new Test_Model();
}
public function index(){
$this->template->set('colors', $this->test->get_colors());
return $this->template->display('test.tpl');
}
}
Model.php
class Test_Model extends Model {
public function __construct(){
parent::__construct();
}
public function get_colors(){
return array(1 => 'green', 2 => 'red');
}
}
test.tpl
что-то типо этого:
{foreach $colors ...} ... {/foreach}
Классы Request, Database, Config и прочее описывать не буду, они просты и суть их ясна.
Больше интересует вопрос
про саму реализацию!
Все ли я правильно сделал? Ничего ли не забыл? Какие могут быть подводные камни.
Для себя хотелось простого и понятного mvc.
На практике - работает, но хотелось бы
услышать комментарии по этому поводу.
И в конце, не посылайте меня к гигантом и прочим yii, symphony, codeigniter .. etc