Простой MVC-фреймворк для PHP 5.2

Иногда бывает необходимо быстро создать небольшой сайт, однако от удобств больших фреймворков отказываться не хочется. Вместе с тем, нет желания палить из пушки по воробью, устанавливая и настраивая несколько мегабайт кода для простых скриптов.

Вот тогда и возникает потребность в миниатюрном MVC-фреймворке, обладающем основными атрибутами старших собратьев.

Фреймворк Web2bb – как раз именно из таких. Началось все со статьи Кевина Ватерсона Model View Controller MVC на сайте phpro.org. В ней автор попытался создать простой каркас для PHP-приложений. Затем по многочисленным просьбам читателей фреймворк был доработан и немного усовершенствован. Фреймворк этот теперь называется web2bb. Многих, однако, не устроило основное требование фреймворка: PHP 5.3. Согласитесь, что до массового проникновения этой версии PHP ещё далековато…

Я взял на себя смелость переделать код под PHP 5.2. Впоследствии я также усовершенствовал фреймворк. По-моему получилось неплохо. Фреймворк обладает фантастической скоростью: даже не пытайтесь сравнивать его с другими MVC. Разница будет громадной. Таким образом, каркас подойдёт и для высоко-нагрузочных проектов, работающих на слабых или shared-серверах. А так как код достаточно простой, то любой опытный разработчик разберется с ним за час и в дальнейшем сможет переделать или доделать фреймворк под свои нужды.

Требования простые: необходим PHP 5.2.x, хотя возможна работа и под 5.1. Фреймворк использует ООП, авто-загрузку классов, отражатели (Reflections) и PDO в качестве движка для доступа к БД.

Проект доступен на Google Code по адресу web2bb-php52. Доступ к коду осуществляется только через SVN на странице source. В комплекте есть пример простого форума/блога с необходимым SQL.

Давайте посмотрим на пример кода:

Модель blogModel (/application/models/app/blogmodel.php) наследует dbAbstraction:

// model
class blogModel extends dbAbstraction {
	private $db;

	public function __construct() {
		$this->db = db::getInstance(); // connect to database
	}

	public function getTopics($id=null) {
		if($id) {
			// get topic with id = $id
		    $sql = "SELECT * FROM topics WHERE id=:id";
		    $st = $this->db->prepare($sql);
		    $st->bindParam(":id", $id, PDO::PARAM_INT);
		    $st->execute();
		    $res = $st->fetch(PDO::FETCH_ASSOC);
		} else {
			// get all
		    $sql = "SELECT * FROM topics ORDER BY created DESC";
			$res = $this->db->query($sql);
		}
		return $res;
	}

	// ...SKIP...

	public function delComment($id) {
		$topic_id = $this->field('comments',$id,'topic_id'); // get comment's topic_id
		$this->delete('comments',$id); // delete comment
		$this->inc('topics',$topic_id,'com_count',-1); // update comment count
		return $topic_id;
	}
}

Контроллер blogController (/application/modules/blog/controllers/blogcontroller.php) наследует baseController:

// controller
class blogController extends baseController implements IController {
	public function __construct() {
		parent::__construct();
		$this->blog = new blogModel; // model
		$this->module = 'blog'; // set current module for render method
		$config = config::getInstance(); // get config data
		$this->view->version = $config->config_values['application']['version']; // set view variable $version
	}

	public function index() {
		$this->view->title = 'Blog';
    $this->view->topics = $this->blog->getTopics();
		// $this->layout=null; // no layout
		$this->cache = true; // false by default
		$this->render('index'); // render /modules/blog/views/index.phtml
	}

	public function add() {
		if(!empty($_POST)) { // save data
			$t = $_POST['topic'];
			$t['created'] = date('Y-m-d H:i:s');
			$this->blog->insert('topics',$t); // new topic
			$this->redirect("/blog/"); // redirect to topics list
		} else { // no data, render form
			$this->view->title = 'new topic';
			$this->render('add');
		}
	}

	// ...SKIP...

	public function delete($obj,$id=null) {
		switch($obj) {
			case 'topic':
				$this->blog->delTopic($id);
				$this->redirect("/blog/");
				break;
			case 'comment':
				$tid = $this->blog->delComment($id); // and return topic_id for redirect
				$this->redirect("/blog/view/".$tid);
				break;
			default:
				exit;
		}
	}
}

Внешний шаблон (/application/layouts/index.phtml):

<!-- layout -->
<html>
<head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 <title><?php echo $title; ?></title>
 <link rel="stylesheet" href="/css/style.css">
</head>
<body>
<h1><?php echo $title; ?></h1>
<a href="/"><?php echo lang::__HOME; ?></a> | <a href="/blog"><?php echo lang::__BLOG; ?></a> | <a href="/contact"><?php echo lang::__CONTACT; ?></a><br/>
<!-- $content is the page template -->
<div id="content"><?php echo $content; ?></div>
</body>
</html>

Шаблон страницы /blog/index/ (/application/modules/blog/views/index.phtml):

<!-- index page template -->
<h1><?php echo $heading; ?></h1>
<p><?php echo $breadcrumbs ?></p>
<table>
<?php foreach ($topics as $topic ): ?>
<tr>
<td><?php echo $topic['id'] ?> (<a href="/blog/delete/topic/<?php echo $topic['id'] ?>/">del</a>)</td>
<td><a href="/blog/view/<?php echo $topic['id'] ?>/"><?php echo $topic['title'] ?></a> (<?php echo $topic['com_count'] ?>)</td>
<td><?php echo $topic['content'] ?></td>
<td><?php echo $topic['author'] ?></td>
<td><?php echo $topic['created'] ?></td>
</tr>
<?php endforeach; ?>
</table>
<a href="/blog/add/">new topic</a>

Ваши мысли в комментариях.

Комментарии (9)

  1. Edward
    22.09.09 в 03:18

    Очень Интересный вариант.
    Скачал твой вариант для PHP5.2, всё работает кроме ссылки блог? В чем может быть загвоздка?

  2. Сергей Яценко
    22.09.09 в 08:53

    Чтобы блог работал, нужно создать БД из приложенного sql-файла, затем прописать настройки БД в конфигурационном файле.

  3. Edward
    24.09.09 в 00:39

    Океан извинений – всё работает.
    Вот только маленький вопрос меня терзает.
    Кодировка БД UTF-8, а при кодировке сайта windows-1251 записи из БД не читаются. Где можно поправить кодировку? Плюс кодировку лучше задавать в конфиге.

  4. Сергей Яценко
    24.09.09 в 07:46

    Где вы нашли windows 1251? Там везде юникод. Кодировка базы в «\application\config\config.ini.php», кодировка html в «\application\layouts\index.phtml».

  5. surg66
    25.10.09 в 15:30

    Интересный фреймворк. Только поигравшись с блогом заметил кривости в ссылках, лишние слеши приписываются…

  6. carat
    27.10.09 в 21:16

    а как скачать фреймворк? по ссылке автора пусто

  7. Сергей Яценко
    27.10.09 в 23:42

    Чтобы скачать, нужно установить систему управления версиями Subversion (TortoiseSVN, например, для Windows). Затем идем в раздел source и читаем инструкции.

  8. zloyuser
    16.12.09 в 21:47

    интересно… MVC всегда смущал меня своей нагруженностью, а тут и размер и скорость действительно впечатляют. Поковыряюсь на досуге.

  9. Алексей
    05.03.10 в 14:38

    Я вот только одной задумки не понял…FrontController, View – это модели??? Нет.

    В web2bb смешан фреймворк и CMS…у нас есть модули…почему бы не складывать в папки модулей модели, которые к нему относятся? /application/models/app это не практично.

    Если убрать интерфейс из контроллера…то отражатели совершенно не нужны, просто лишний код…я их сразу убрал.

    Вообще искал простой фреймворк около 3 месяцев, так ничего и не нашел….может стоит создать общество…создадим русский PHP фреймворк :) Там поставить цель сделать удобный фреймворк размером 50-100кб не более