MVC приложение на php. Часть 1
Из паттернов меня устраивало mvc, registry. Для запросов я написал небольшой слой абстракции, для роутинга — свою функцию парсинга запроса.
Структура веб-приложения будет такой
Папка application
Входной файл index.php подключает bootstrap.php. Тот в свою очередь подключает ядро, конфиг-файл, некоторые библиотеки и запускает маршрутизатор.
use Core\Route;
require_once 'lib/registry.php';
require_once 'config.php';
require_once 'lib/datebase.php';
require_once 'core/model.php';
require_once 'core/view.php';
require_once 'core/controller.php';
require_once 'core/route.php';
$router = new Route();
$router->start(); // запускаем маршрутизатор
Реестр устроен просто:
namespace Lib;
class Lib_Registry {
static private $data = array();
static public function set($key, $value) {
self::$data[$key] = $value;
}
static public function get($key) {
return isset(self::$data[$key]) ? self::$data[$key] : null;
}
static public function remove($key) {
if ( isset(self::$data[$key]) ) {
unset(self::$data[$key]);
}
}
}
Здесь геттеры и сеттеры для сохранения глобальных значений.
Далее подключается конфиг, в котором у нас только параметры подключения к БД и более ничего, экземпляр коннектора записывается в реестр для использования как глобальное значение.
use Lib\Lib_Registry;
define('PATH_SITE', $_SERVER['DOCUMENT_ROOT']);
define('HOST', 'localhost');
define('USER', 'root');
define('PASSWORD', 'mypass');
define('NAME_BD', 'articles');
define ('DS', DIRECTORY_SEPARATOR);
$mysqli = new mysqli(HOST, USER, PASSWORD,NAME_BD)or die("Невозможно установить соединение c базой данных".$mysqli->connect_errno());
Lib_Registry::set('mysqli',$mysqli);
$mysqli->query('SET names "utf8"'); //база устанавливаем кодировку данных в базе
Далее роутинг.
Запрос вида http://domen.ru/articles/index преобразуется в Контролллер — Экшн. Название контролллера и экшна задается в стиле Zend framework, camel case — Controller_Name, function action_name(). Файл контролллера, модели, въюхи должен совпадать с названием контроллера в нижнем регистре без префикса Controller_ или Model_
Класс модели задается так же — Model_Name, файл вьюхи мы уже выяснили — по имени экшна или явно в методе generate(name)
Так как в перспективе у нас создание админки — создадим папки client и admin. Кстати наш маршрутизатор будет учитывать вложенные папки, т.е. можно будет создать подпапки в контроллерах (напр. /about/contacts/contacts.php ) и обратиться к нему по его пути /about/contacts/
Итак, мы запустили маршрутизатор
/**
*
*/
public function start()
{
// catch AJAX request
if ($this->getIsAjaxRequest()) {
}
session_start();
$this->dispatch();
}
Работает диспетчер
/**
*
*/
public function dispatch(){
// диспетчер получает файл совпадающий с названием контроллера, экшн и аргументы
$this->getDirections($file, $controller, $action, $args);
/* ************* include Controller - Model */
if (is_readable($file) == false) {
die ("File $file 404 Not Found");
}
// подключили контроллер
include ($file);
$model = str_replace("controller", "model", $file);
// Model additional
if(is_readable($model)){
// подключаем модель
include($model);
}
/* ****** получаем класс ** */
$controller = ucfirst($controller);
$class = ucfirst($this->namespace).'\Controller_' . $controller;
// создаем экземпляр
$controller = new $class($this->controller_path_folder);
if (is_callable(array($controller, $action)) == false) {
die ("Action $action 404 Not Found");
}
// вызываем экшн
$controller->$action($args);
}
Диспетчер вызывает метод getDirections(), т.е. получить директивы запроса. По умолчанию дефолтный контроллер — articles, экшн — index.
/**
* @param $file
* @param $controller
* @param $action
* @param $args
*/
private function getDirections(&$file, &$controller, &$action, &$args) {
$route = (empty($_SERVER['REQUEST_URI'])) ? '' : $_SERVER['REQUEST_URI'];
unset($_SERVER['REQUEST_URI']);
$route = trim($route, '/\\');
$controller_path = $this->path;
if (empty($route)) {
/* ******************* Default directions ******** */
$controller = 'articles';
$action = 'action_index';
$controller_path = $this->controller_path_folder = "application/controllers/$this->namespace/";
$file = $controller_path.$controller.".php";
}
else
{
$parts = explode('/', $route);
/* ************** namespace ********** */
if($parts[0] == "admin") {
$this->namespace = "admin";
array_shift($parts);
}
/* ***************** folders & subfolders ******* */
$fullpath = $this->controller_path_folder = $controller_path . $this->namespace;
foreach ($parts as $part) {
$fullpath .= DS . $part;
if (is_dir($fullpath)) {
array_shift($parts);
continue;
}
if (is_file($fullpath . '.php')) {
array_shift($parts);
$file = "$fullpath.php";
break;
}
}
/* *************** Controller, Action, Params ******** */
if(!isset($part))
$part = "articles";
$controller = $part;
if(!$file)
$file = $fullpath."/$part.php";
$action = array_shift($parts);
if(!$action)
$action = 'action_index';
else
$action = "action_$action";
$args = $parts;
}
}
В следующем уроке рассмотрим создание базовых контроллера, моделей и вьюх, напишем запросы.
Файлы 1-го урока здесь
https://github.com/vaajnur/create_php_application
Ветка мастер будет 1-м уроков, далее для каждого урока одноименная ветка — lesson1, lesson2, 3..
Уроки из темы, сжечь к херам и удалить сайт…
начну с тебя
Спасибо,вот только бы побольше комментариев в коде. А так то, что надо.