Доброго воскресенья, друзья! К работе над второй версий активно подключаются участники команды, что определенно радует. skvorets уже рисует новый интерфейс админки, JiLiZART стоит на страже багов в GIT-репозитории, inetlover продумывает интерфейсы и готовится к верстке, Varhal и Osiris вот-вот запустят сайт с темами для первой версии. Самое время продолжить вводный курс в архитектуру второй части. Хочешь принять посильное участие в общем деле? Пиши в личку!Что является наиболее важной задачей для разработчика системы? Преемственность разработки, чтобы другие люди легко включались в оригинальный код и могли быстро реализовать собственные разработки на базе исходной. Да, конечно, это лишь часть успеха, но без преемственности нет жизни. Говорят, мы живем в наших детях. Могу перефразировать в аспекте движка — система живет в сообществе.
Итак, моя задача до релиза второй версии привести нас с вами к общему знаменателю, чтобы все понимали, что происходит внутри, и осознавали архитектуру движка самостоятельно, а не только с моих отзывов в духе «Это просто супер!» :-)
Немного об абстракции
Вы знаете, что все хорошо тогда, когда все по фен-шую. Поэтому в своих творческо-программистких изысканиях я пришел к концепции МИСО. Абстрагируемся и упрощаем, упрощаем и абстрагируемся. В конечном счете, отбросив все фантазии, я пришел к выводу, что лучшей техникой джедайского кунфу является использование заложенных в PHP5 возможностей по-максимуму вместо того, чтобы изобретать свои велосипеды и костыли.Именно поэтому я решил все свести к полноценному ООП. Шестеренка — это класс. Нет, вы не поняли. Да, это «класс!», но это и класс по сути. Тот класс, который стоит в тени объекта.
Напомню последние изменения в файловой системе. Есть три места, где хранятся шестеренки:
- /engine ← шестеренки ядра (энтузиастам вход запрещен)
- /gears ← шестеренки для всех сайтов
- /sites/домен.сайта/gears ← шестеренки конкретного сайта
Для простоты поясню на примере.
$object = new User_Gear();
Что происходит при создании объекта класса User_Gear? Имя класса попадает в автолоадер, где оно преобразуется в путь. Нижнее подчеркивание _ заменяется на разделитель директории (в Windows — \, в Unix-based системах — /) и суффиксом приставляется расширение .php, после чего загрузки последовательно обходит указанные выше директории в обратном порядке и загружает первый попавшийся файл.- /sites/домен.сайта/gears/User/Gear.php ← упс, не существует
- /gears/User/Gear.php ← и здесь пусто
- /engine/User/Gear.php ← нашел! Загружаю.
Да, есть люди, которые сетуют за систему оберток, как в Kohana. Она удобна, но создает море лишних файлов, и пока что не требуется в нашем варианте. Поясню, она позволяет не просто переопределять, но и наследоваться в «слоеном пироге». Обратитесь более детально к документации Kohana. Помните, что разработка — это процесс, а не результат, поэтому при необходимости мы всегда сможем расширить структуру. Вообще все во второй версии делается только по необходимости. Никаких «а вдруг пригодится…». Таким образом мы минимизируем издержки и увеличиваем производительность.
Шестеренка
Перейдем к самому важному — шестеренке. Это базовая сущность второго cogear. Шестеренками представлено все — модули, плагины и даже темы.Шестеренка — это класс, который обладает всеми данными ему PHP5 атрибутами. В том числе и возможностью наследования.
В чем удобство? В том, что вы можете создавать свои продукты, основываясь лишь на различии от других. К примеру, базовый код шестеренки /engine/Core/Gear.php содержит информацию:
<?php
/**
* Gear
*
* @author Dmitriy Belyaev <admin@cogear.ru>
* @copyright Copyright © 2010, Dmitriy Belyaev
* @license http://cogear.ru/license.html
* @link http://cogear.ru
* @package Core
* @subpackage
* @version $Id$
*/
abstract class Gear {
/**
* Gear name
* @var string
*/
protected $name;
/**
* Gear description
* @var string
*/
protected $description;
/**
* Gear version
*
* By default it equals Cogear version
*
* @var string
*/
protected $version = COGEAR;
/**
* Core version
*
* By default it equals Cogear version
* * @var string
*/
protected $core = COGEAR;
/**
* Gear type
*
* 0 — Core
* 1 — Module
* 2 — Plugin
* 3 — Theme
*
* @var int
*/
protected $type = Gear::CORE;
/**
* Package
*
* @var string
*/
protected $package = 'Core';
/**
* Gear authors name
*
* @var string
*/
protected $author = 'Dmitriy Belyaev';
/**
* Gear email
*
* Contact email to resolve everything
* @var string
*/
protected $email = 'admin@cogear.ru';
/**
* Gear website
*
* @var string
*/
protected $site = 'http://cogear.ru';
/**
* Order in gear stack
*
* Value can be positive or negative to load after or before other gears.
*
* @var int
*/
protected $order = 0;
…
Поэтому при создании шестеренок ядра, я переопределяю только название и описание, все остальные данные (версия, разработчик и так далее) остаются теми же. И не надо в каждой новой шестеренке указывать, что ее версия совпадает, например, с версий движка (а для компонентов ядра это всегда так), или что я — ее автор. Также и вы можете создать свою базовую шестеренку, и все другие свои продукты от нее наследовать. Убирая повторы даже в информации, мы экономим время. Ведь чтобы поправить информацию во всех своих шестеренках, вы можете изменить таковую только в первоначальной, от которой все наследуются.<?php
/**
* User gear
*
* @author Dmitriy Belyaev <admin@cogear.ru>
* @copyright Copyright © 2011, Dmitriy Belyaev
* @license http://cogear.ru/license.html
* @link http://cogear.ru
* @package Core
* @subpackage
* @version $Id$
*/
class User_Gear extends Gear {
protected $name = 'User';
protected $description = 'Manage users.';
protected $order = -10;…
Наследование
В классе шестеренки есть метод init, который вызывается движком в порядке загрузки шестеренок (параметр order). По-умолчанию, он загружает скрипты и стили, создает базовый роут и вызывает хук. В отнаследованных шестеренках вы можете переопределить метод, сохраняя вызов родительского через parent::init(), к примеру.Класс темы /engine/Core/Theme.php наследуется от шестеренки. Как я уже упоминал, тема — тоже шестеренка, только более продвинутая. В методе init абстрактного класса темы вызывается родительский метод у всех отнаследованных тем, чтобы подгрузить их скрипты и стили. Это очень удобно, потому что вы можете создавать свои темы, указывая только лишь изменения от предыдуших. При этом вы вольны переопределить метод init абстрактного класса темы и выстроить такую загрузку, которая вам потребуется. Полная свобода для творчества и самореализации!
/engine/Core/Theme.php:
…
/**
* Init
*/
public function init(){
$Reflection = new ReflectionClass($this);
$parent = $Reflection->getParentClass();
if($parent->name != 'Gear' && $parent->name != 'Theme'){
$theme = new $parent->name;
$theme->init();
$cogear = getInstance();
$cogear->gears->{$parent->name} = $theme;
}
parent::init();
$cogear = getInstance();
$cogear->theme = $this;
Template::bindGlobal('theme',$this);
$cogear->hook('done',__CLASS__.'->render');
$this->template = new Template($this->gear.'.'.$this->layout);
}
…
Напоследок код темы Default и отнаследованной от нее темы 960 на базе замечательного CSS-фреймворка 960.gs.
/engine/Theme/Default/Gear.php:
<?php
/**
* Default Theme gear
*
*
*
* @author Dmitriy Belyaev <admin@cogear.ru>
* @copyright Copyright © 2010, Dmitriy Belyaev
* @license http://cogear.ru/license.html
* @link http://cogear.ru
* @package Theme
* @subpackage Default
* @version $Id$
*/
class Theme_Default_Gear extends Theme{
protected $name = 'Default Theme';
protected $description = 'Default engine theme.';
}
/engine/Theme/960/Gear.php:<?php
/**
* 960 Theme gear
*
*
*
* @author Dmitriy Belyaev <admin@cogear.ru>
* @copyright Copyright © 2010, Dmitriy Belyaev
* @license http://cogear.ru/license.html
* @link http://cogear.ru
* @package Theme
* @subpackage Default
* @version $Id$
*/
class Theme_960_Gear extends Theme_Default_Gear{
protected $name = '960.gs Theme';
protected $description = 'Theme based on 960 grid system.';
protected $version = '1.0';
}
Приветствую любые вопросы, пожелания и предложения!


А запуск сайта с шаблонами намечен на этой неделе, сейчас несколько премиум тем доверстываем и ГОУ!
Предлагаю кешировать пути, чтобы не обходить каждый раз «указанные выше директории». Оптимизировано на мелочь, но все равно приятно
Хотя в mzz есть такая фишка, там создаётся фаил со списком всех просканированных файлов и обращение к файловой системе происходит через него.
а во-вторых, как часто ты ставишь новые шестеренки и как часто будет проводиться «проход» по файлам?
Система может пребывать в двух состояниях — разработки и продакшена. В режиме разработки кеш выключен всегда (кроме системного, который перманентный и хранит данные). И все.
По поводу ресурсоемкости операции file_exists — она очень дешевая. Не стоит пока париться на этот счет, данное место всегда можно оптимизировать, а сейчас итак показатели по производительности более чем отличные.
Версия 2 из git-репозитория достаточно стабильна для использования на реальном проекте?
Если я правильно понял, то во второй ветке отказались от CodeIgniter?