Антон Шевчук // Web-разработчик

PHP Framework Bluz // PHP

Тут такое дело, зарождается ещё один фреймвёрк, и думаю многих он заинтересует, ибо легковесных фреймвёрков под PHP 5.4 не так уж и много :)

Почему рождается новый «велосипед» — да старый уже ж не в пору и скрипит

Чтобы не листать весь пост, вот вам ссылка на GitHub — https://github.com/bluzphp

В чем его удобство

Во-первых, следование заветам usability кода, за чем я старался следить.
Во-вторых, это отказ от какой-либо совместимости со старыми версиями PHP (устарел, давай, до свидания).
В-третьих, этот фреймвёрк создаётся как и положено — исходя из требований проекта, т.е. он выращен не искусственно под лозунгами «шоб було», а под реальные задачи, которые появлялись в проекте

Особенности

Поскольку фреймвёрк создавался под нужды проекта, то именно этим фактором обусловлено большинство принятых решений. В частности достаточно специфичный ACL, да и прикрученный twitter bootstrap из коробки тоже оттель.

Так же упомяну, что данный фреймвёрк начал проклёвываться ещё год назад в одном высокогонагруженном проекте, и о нём я еще расскажу на ThinkPHP ;)

Так что же внутри? А внутри всё пляшет от Application, который отвечает чуть меньше, чем за всё и с десяток пакетов, которые обеспечивают комфортную и быструю разработку приложений

MVC

Куда уж без него, но в нашей реализации есть военная хитрость, вот к примеру контроллер:

<?php
return
/**
 * @privelege View User Profile
 * @cache 5 minutes
 * @param integer $id
 * @return closure
 */
function($id) use ($view) {
    /**
     * @var View $view
     */
     $view->user = $app->getDb()->fetchObject(
          "SELECT * FROM users WHERE id = ?", 
          array($id), 
          'Users\Row');
};

Без паники, да action не предусмотрены, лишь модули и контроллеры-замыкания, и да — это упрощает разработку. Внимательный читатель уже заметит как контроллер «ловит» входные параметры, и что у него оказывается уже есть кеширование, и описана какая-то привилегия — да, всё это работает, как и задумывалось ;)

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

return
/**
 * @var Bluz\View $view
 * @return closure
 */
function() use ($view) {
    $view->title = "Hello world"
};

Собственно код шаблона:

<h2><?=$title?></h2>
<!-- так тоже работает -->
<h2><?=$this->title?></h2>

Всякие мелкие фишки по работе с шаблонизатором описаны в соответствующем разделе wiki

База данных

Для работы с базой данных предусмотрен пакет Db (оригинально то как), он включает в себя Db\Db, Db\Table и Db\Row. Класс Db представляет из себя лишь обёртку над PDO, и слегка упрощает нам жизнь:

<?php
// init settings
$db->setConnect(array(
    'type' => 'mysql',
    'host' => 'localhost',
    'name' => 'db name',
    'user' => 'root',
    'pass' => ''
));
 
// quote variable
$db->quote($id)
 
// query
$db->query("SET NAMES 'utf8'");
 
// get one
$db->fetchOne("SELECT COUNT(*) FROM users");
 
// get row
$db->fetchRow("SELECT * FROM users WHERE id = :id", array(':id'=>$id));
 
// get array
$db->fetchAll("SELECT * FROM users WHERE ip = ?", array($ip));
 
// get pairs
$pairs = $db->fetchPairs("SELECT ip, COUNT(id) FROM users GROUP BY ip", array());
 
// get object
// .. to stdClass
$stdClass = $db->fetchObject('SELECT * FROM some_table WHERE id = ?', array($id));
// .. to new Some object
$someClass = $db->fetchObject('SELECT  * FROM some_table WHERE id = ?', array($id), 'Some');
// .. to exists instance of Some object
$someClass = $db->fetchObject('SELECT * FROM some_table WHERE id = ?', array($id), $someClass);

// plain insert/update/delete
$db->insert('some_table', array('col1'=>'foo', 'col2'=>'bar'));
$db->update('some_table', array('col1'=>'bar', 'col2'=>'foo'), array('id'=>1));
$db->delete('some_table', array('id'=>1));

О транзакциях тоже не забыл, вот пример контроллера:

if ($this->getDb()->transaction(function() {
    /**
     * @var \Bluz\Application $this
     */
    $this->getDb()->delete('acl_privileges');
})) {
    $this->getMessages()->addSuccess('All data was saved');
} else {
    $this->getMessages()->addError('Internal server error');
}

Классы Table и Row это некое подобие active record:

<?php
namespace Application\Users;
class Row extends \Bluz\Db\Row
{
   public function preInsert()
   {
       $this->created = gmdate('Y-m-d H:i:s');
   }
   public function preUpdate()
   {
       $this->updated = gmdate('Y-m-d H:i:s');
   }
}
 
$userRow = new \Application\Users\Row();
$userRow -> login = 'username';
$userRow -> save();

Роутеры

Просты до безобразия, указываются непосредственно в комментариях контроллера:

/**
 * @route /users/{$id}
 * @param integer $id
 */

При использование не требуют явного указания имени (привет ZF):

<?php
$this->url('users', 'login');
$this->url('users', 'profile', array('id' => $id));
$this->url('pages', 'show', array('name' => $name));
?>

Конечно, подобная реализация не без недостатков, но таки вполне юзабельно, и под стать фремвёрку.

Ещё

Есть еще пачка пакетов, пожалуй стоит привести их список:

  • Acl — позволяет быстро и гибко организовать раздачу прав
  • Cache — очень простая обёртка над memcached
  • EventManager — события и их обработчики
  • Registry — тут без комментариев
  • Request — объект запроса, сам по себе используется редко
  • Session — лишь обёртка

Выводы

Я конечно не надеюсь, что вы присоединитесь к разработке, но я искренне верю, что вам пригодится сам фреймвёрк, возможно его код или идеи из него :)

Если интересно — присоединяйтесь к Skype чату ;)

© Антон Шевчук 2007-2023