Задать вопрос

MVC PHP разбор полётов, всё ли верно я сделал?

Сразу скажу, что я не претендую на премию Дарвина.
И так, задался вопросом написания простой 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
  • Вопрос задан
  • 1552 просмотра
Подписаться 8 Оценить 2 комментария
Пригласить эксперта
Ответы на вопрос 3
ThunderCat
@ThunderCat Куратор тега PHP
{PHP, MySql, HTML, JS, CSS} developer
В принципе, глубоко в код не лез, по беглому пробежался,
* немного напрягает наименования переменных и классов, я привык к camelCase, сегодня это в пыхе стандарт де-факто(хотя тут ща может вспыхнуть реальный холивар)
* классы обычно именуются с большой буквы,
* сегодня модно dependency injection, в этом ключе базовый класс не должен включать в себя бд, и знать в принципе не должен о существовании бд. При манипуляциях с данными по иерархи объектов нужно в бд передавать объект, и бд уже возвращает все что нужно(читай про di в гуглах).
* если все же базовый класс включает бд и все, то нахуа он Вам? Реализуй уже и CRUD хотя бы.
* Для удобства работы я бы рекомендовал еще отдельный класс коллекций объектов, очень помогает.
В остальном - каждый сходит с ума как ему нравится )
Ответ написан
@kstyle
может, пригодится
Ответ написан
Комментировать
Taraflex
@Taraflex
Ищу работу. Контакты в профиле.
Приведите код минимум к стандарту PSR-2
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы