+

Создаем свой PHP MVC framework. Часть 1.

Заметки, Мои шедевры, Программирование

Метки (теги) : , ,

Автор: masdeft

В данной серии статей я опишу реализацию PHP MVC framework’a. Подобных статей достаточно много, но как мне показалось, в некоторых не достаточно ясно и подробно изложена информация, и даже во многих является устаревшей. Что такое MVC и что представляет собой термин Framework я описывать не буду в связи с избытком информации по данным темам. Все пожелания прошу приводить в комментариях.


В данной статья я опишу:
1. Выбор стиля кодирования.
2. Структура.
3. FrontController.
4. Конфигурации фреймворка.

Первое с чего хочу начать, нужно придерживаться строгих правил и стилей написания кода.  Я пользуюсь  документацией по стандартам Zend Framework и Вам советую.
Далее разберемся со структурой приложения.


-application
--config
---main.php
--components
--controllers
---IndexController.php
--models
--views
---index
----index.php
---layouts
----default.php
--modules
---components
---controllers
---models
---views
-library
-- ... наша библиотека классов
-public
--index.php


В директории components будут находиться вспомогательные классы (виджеты, хелперы, и т.д.), каждая группа компонентов может быть расположена в отдельной директории, а отдельные компоненты группы соответственно в поддиректориях. Автозагрузкза классов происходит с использованием namespase по соглашению

-components
--Helpers
---MyHelper
--- ...
--Widgets
...

Подобным образом будет сделано в моделях для более гибкой иерархии классов. Определимся с названием фреймворка. Я его назвал “My own framework” или сокращенно “mof”, таким образом все классы ядра фреймворка будут именоваться начиная с приставки “Mof_”, которая указывает на корневую папку библиотеки.

Идем дальше.
Напишем наш – index.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#public/index.php

// Определяем путь к корню папки application
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
 
set_include_path(realpath(APPLICATION_PATH . '/../library'));
 
require_once 'Mof/Application.php';
 
// Присваиваем значение пути к файлу конфигураций
$config = APPLICATION_PATH . '/config/main.php';
 
Mof_Application::init($config)->run();

Файл конфигураций main.php содержит в себе массив значений (на подобии Yii фреймворка), которые можно применить в любом мести приложения. Базовые конфигурации будут использоваться ядром фреймворка.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#application/config/main.php

return array(
	'db' => array(
		'dsn' => 'localhost',
		'database' => 'test',
		'username' => 'root',
		'password' => '',
		'prefix' => 'enxt_'
	),
	'modules' => array(
		'admin' => array(
			'enable' => true,
		),		
	),
	'user' => array(
		'defaultAdminName' => 'administrator',
		'defaultAdminPassword' => 'admin',
		'role' => 'admin',
	),
	'defaultController' => 'Index',
	'defaultLayout' => 'default',
);

Создадим корневую папку нашей библиотеки Mof и в ней файл Application.php.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# library/Mof/Application.php

class Mof_Application
{
	/**
	 * @var MofApplication
	 */
	private static $_loader;
 
	/**
	 * @var array
	 */
	protected static $_classMap = array(
		'Component' => 'components',
		'Model' => 'models',
	);
 
        /**	 
	 * @var Mof_Template
	 */
	public $template;
 
	/**
	 * instanse
	 *
	 * @param string $config
	 * @return MofApplication
	 */
	public static function init($config)
	{
		if (self::$_loader == NULL) {
			self::$_loader = new self($config);
		}
		return self::$_loader;
	}
 
	public function __construct($config)
	{
		spl_autoload_register(array($this, '_load'));
		if (is_string($config)) {
			$configArray = require($config);
			Mof_Config::set($configArray);
		}
	}	
 
	/**
	 * Run application
	 *
	 * @throws Exception
	 */
	public function run()
	{
		if (isset(Mof_Config::get()->modules)) {
			foreach (Mof_Config::get()->modules as $moduleName => $params) {
				self::$_classMap['modules'][ucfirst($moduleName)] = $moduleName;
			}
		}
		$this->template = new Mof_Template();
		$router = new Mof_Router();
		$router->route($this);
 
		$baseModelObject = new Mof_Model();
		if ($baseModelObject->getError()) {
			throw new Exception($baseModelObject->getErrorMessage());
		}
	}
 
	/**
	 * Autoloader
	 *
	 * @param str $className
	 * @return void
	 */
	private function _load($className)
	{
		$length = strpos($className, '_');
		$classNameItems = explode('_', $className);
		$lowerFirstItem = strtolower($classNameItems[0]);
		if (isset(self::$_classMap[$classNameItems[0]])) {
			$classCoreDir = APPLICATION_PATH . DIRECTORY_SEPARATOR . self::$_classMap[$classNameItems[0]];
		} elseif (isset(self::$_classMap['modules'][$classNameItems[0]])) {
			$classCoreDir = APPLICATION_PATH . DIRECTORY_SEPARATOR . 'modules'
							 . DIRECTORY_SEPARATOR . self::$_classMap['modules'][$classNameItems[0]]
							 . DIRECTORY_SEPARATOR . Mof_Application::$_classMap[$classNameItems[1]];
			$className = str_replace($classNameItems[1] . '_', '', $className);
		} else {
			$classCoreDir = dirname(__FILE__);
		}
		$classFile = $classCoreDir . strtr(substr($className, $length), '_', DIRECTORY_SEPARATOR) . '.php';
		if (is_file($classFile)) {
			require_once $classFile;
		}
	}
 
}

Класс Mof_Application “запускает” наше приложение и обеспечивает загрузку всех нужных нам классов, детальное описание которого будет в следующей части, которую постарасю написать незамедлительно. А пока на этом все. Спасибо.

Комментарии:

Оставить комментарий

=