Делаем простой HMVC-виджет в Kohana3
Метки: Kohana | обучение
Суббота, 12 сентября 2009 г.
Просмотров: 1547
Подписаться на комментарии по RSS
По просьбам читателей излагаю свой взгляд на то, как можно сделать виджет в Ko3. Хочу оговорить, что в своих туториалах я основываюсь на уже пройденном ранее материале и стараюсь не затрагивать непройденный, чтобы новичкам было удобно.
Прежде всего, определим понятия. Виджет в контексте веб-приложения я понимаю как фрагмент веб-страницы, относительно независимый по содержанию от остального контента страницы и (опционально) могущий независимо от остального содержимого взаимодействовать с пользователем. Далее несколько существенных, на мой взгляд, особенностей: виджет может располагаться на всех страницах либо на некоторых. Виджет может иметь несколько независимых экземпляров на странице. В качестве примеров виджетов можно упомянуть разного рода календарики, списки дел, опросы, информацию о сайте и т. п. В общем, это очень «растяжимая» штука, которая может объять даже необъятное ![]()
Существенной особенностью виджета, определяющей его программную реализацию, является значительная независимость от остального содержимого страницы. Это позволяет не загромождать им метод контроллера приложения, вызывая виджет либо в конструкторе, либо локально в шаблоне страницы (для «автоматизированного» подключения, как в CMS, придется реализовывать виджеты по-другому).
Но хватит слов: пора заняться набросками кода.
Простой виджет вполне можно реализовать без HMVC: написать библиотечку, подключить ее в контроллере или шаблоне (или же использовать статический вызов) — и все. Но давайте используем модное нынче HMVC, чтобы по ходу получить еще один пример его применения. Будем творить простой виджет, показывающий в разных вариациях системное время и дату, а также приветствие с названием текущей страницы.
Создадим базовый контроллер, от которого будем наследовать виджеты. Пока что он пустой, но в перспективе будет содержать сервисные методы.
class Controller_Widget extends Controller_Template {
}
Виджеты будут храниться в папке application/controller/widget/. Создадим там файл date.php для контроллера Controller_Widget_Date. Вызывать виджет из Главного Контроллера или шаблона можно по-разному. Я буду вызывать свой как-нибудь так (для начала):
Request::factory('widget_date/show/day-year')->execute();
Соответственно, в контроллере виджета нужно прописать, как минимум, имя шаблона (не забываем создать шаблон!) и метод action_show(), принимающий один параметр (формат вывода):
public $template = 'widgets/date';
public function action_show ($format = 'year-day-hour-min')
{
$fields = explode('-',strval($format));
$d = getdate();
$date = "";
foreach ($fields as $field)
{
switch ($field)
{
case "min":
$date .= 'Minutes: '.$d['minutes'].'<br />';
break;
case "hour":
$date .= 'Hours: '.$d['hours'].'<br />';
break;
case "day":
$date .= 'Day: '.$d['month'].' '.$d['mday'].'<br />';
break;
case "year":
$date .= 'Year: '.$d['year'].'<br />';
break;
}
}
$this->template->page = Request::instance()->action;
$this->template->date = $date;
}
В свойстве Request::instance()->action хранится имя исполняемого метода главного контроллера (поскольку вызван Request::instance() !) .
Шаблончик у меня выглядит так:
<div style="background-color: #FFEEEF;"> <h4>«Date» widget<br />Welcome to the "<?php echo $page; ?>" page</h4> <p>Current date is:<br /><?php echo $date; ?></p> </div>
Хорошо, давайте пропишем наше творенье в Главном контроллере (Controller_Welcome). Поскольку виджеты, как предполагается, не должны зависеть от содержания страницы, то имеет смысл инициализировать их вне методов-обрабочиков страниц: например, в конструкторе или before(). Я очень люблю конструкторы, но надо же попробовать нововведение Kohana 3! Поэтому используем before().
public $widgets = array();
public function before()
{
parent::before();
$this->template->bind('widgets', $this->widgets);
// attach "anywhere presented" widget
$this->widgets[] = Request::factory('widget_date/show/year-day')->execute();
}
Сначала мы завели массив $widgets, в котором будут храниться все виджеты. В методе before() мы вызываем parent::before(), поскольку там происходит инициализация нашего шаблона (можно не вызывать, но тогда придется вручную прописать $this->template = View::factory($this->template)).
Далее мы привязываем наше хранилище виджетов к Главному шаблону, а затем делаем подзапрос нашего виджета, который и попадает в хранилище. Осталось сделать две вещи: прописать виджеты в Главном шаблоне
<?php
if (is_array($widgets) AND ! empty($widgets))
{
?>
<div id="widget_place" style="position: absolute; right: 10px; top: 20px;">
<?php
foreach ($widgets as $widget)
{
echo $widget;
}
?>
</div>
<?php
}
?>
… и добавить в application/bootstrap.php специальный виджетный роут для HMVC
Route::set('widget', '<controller>(/<action>(/<format>))', array('controller'=>'widget_\w+'))
->defaults(array(
'controller' => 'widget_dummy',
'action' => 'index',
));
Контроллер проверяется на соответствие с помощью регулярки, а по дефолту задается не существующий пока контроллер Controller_Widget_Dummy и метод action_index() (если хотите, можете их прописать, мы же не будем отягощать туториал).
Обновите страницу нашего тестового сайта — все должно заработать. Если вам не нравится показываемое время, исправьте в application/bootstrap.php временную зону (я исправил на родную 'Europe/Minsk').
Чтобы добавить виджет на каую-нибудь страницу, можно прописать в соответствующем методе вызов типа
$this->widgets[] = Request::factory('widget_date/show/hour-min')->execute();
Признаю, это не очень удобно. Что, если вам нужно более гибко настраивать показ виджета? Нужен конфиг. Давайте создадим новый виджет «Cdate», во всем подобный предыдущему, но совершеннее
Нужно переименовать контроллер и шаблон виджета, малость подправить шаблон и подключить виджет в Controller_Welcome::before(), если хотим увидеть, — и все!
Начнем модификацию. Сначала в application/config/widget/ добавим конфиг cdate.php, например, такой:
return array
(
'default' => array
(
'format' => 'day-hour-min-year',
'allowed_pages' => array(),
),
'form' => array
(
'format' => 'hour-min',
'allowed_pages' => array('form'),
),
'page' => array
(
'format' => 'year-hour-min',
'allowed_pages' => array('page1','page2'),
),
);
Здесь я прописал несколько вариантов конфигурации, каждый из которых содержит, во-первых, формат отображения виджета, во-вторых, массив страниц, на которых виджет нужно отображать.
Метод загрузки конфига пристроим в родительском контроллере Controller_Widget:
protected $_config;
public function load_config($conf_name,$conf_entry='default')
{
$this->_config = Kohana::config($conf_name.'.'.$conf_entry);
}
В свойстве контроллера Controller_Widget::$_config будет храниться загруженный конфиг.
Следующий этап — правка контроллера нашего виджета. Добавляем public $config_name = 'widget/cdate', а в методе Controller_Widget_Cdate::action_show() грузим конфиг, убеждаемся, что мы в правильном месте, и парсим формат:
$this->load_config($this->config_name,$entry);
if ( ! in_array(Request::instance()->action, $this->_config['allowed_pages']))
{
$this->auto_render = FALSE;
return NULL;
}
$fields = explode('-',strval($this->_config['format']));
Осталось в Главном контроллере добавить в before() вызов контроллера виджета:
$this->widgets[] = Request::factory('widget_cdate/show/page')->execute();
Все работает: виджет отображается только на page1 и page2, как и прописано в конфигурационном файле.
Кстати, желающие могут вызывать виджет прямо из шаблона:
<?php
echo Request::factory('widget_date/show/year')->execute();
?>
Скачать application
Всех именинников поздравляю с днем памяти св. благоверного князя Александра Невского!


Комментариев: 6
Исходники прикреплены от другой статьи.
]]>
От имени всех желающих - благодарность, и...
Results Triple Match: ZF:KO3:YII - 3:4:5
]]>
Remas
извините, исправился
Sezarin
за что YII "5"?
]]>
В Yii имеется CWidget - мощный класс виджетов со множеством подклассов.
Виджет в Yii реализован как самостоятельный компонент, который может генерировать представление, основанное на модельных данных, а также может быть использован как микродиспетчер, встраиваемый в представление...
]]>
спасибо, буду иметь в виду
]]>
Александр, спасибо за статьи о КО3!
С нетерпением жжду продолжения!