Делаем простой HMVC-виджет в Kohana3

Просмотров: 10937Комментарии: 6
Web frameworks

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

Прежде всего, определим понятия. Виджет в контексте веб-приложения я понимаю как фрагмент веб-страницы, относительно независимый по содержанию от остального контента страницы и (опционально) могущий независимо от остального содержимого взаимодействовать с пользователем. Далее несколько существенных, на мой взгляд, особенностей: виджет может располагаться на всех страницах либо на некоторых. Виджет может иметь несколько независимых экземпляров на странице. В качестве примеров виджетов можно упомянуть разного рода календарики, списки дел, опросы, информацию о сайте и т. п. В общем, это очень «растяжимая» штука, которая может объять даже необъятное smile

Существенной особенностью виджета, определяющей его программную реализацию, является значительная независимость от остального содержимого страницы. Это позволяет не загромождать им метод контроллера приложения, вызывая виджет либо в конструкторе, либо локально в шаблоне страницы (для «автоматизированного» подключения, как в CMS, придется реализовывать виджеты по-другому).

Но хватит слов: пора заняться набросками кода.

Простой виджет вполне можно реализовать без HMVC: написать библиотечку, подключить ее в контроллере или шаблоне (или же использовать статический вызов) — и все. Но давайте используем модное нынче HMVC, чтобы по ходу получить еще один пример его применения. Будем творить простой виджет, показывающий в разных вариациях системное время и дату, а также приветствие с названием текущей страницы.

Создадим базовый контроллер, от которого будем наследовать виджеты. Пока что он пустой, но в перспективе будет содержать сервисные методы.

[code lang="php"]

class Controller_Widget extends Controller_Template {

    

}

[/code]

Виджеты будут храниться в папке application/controller/widget/. Создадим там файл date.php для контроллера Controller_Widget_Date. Вызывать виджет из Главного Контроллера или шаблона можно по-разному. Я буду вызывать свой как-нибудь так (для начала):

[code lang="php"]

Request::factory('widget_date/show/day-year')->execute();

[/code]

Соответственно, в контроллере виджета нужно прописать, как минимум, имя шаблона (не забываем создать шаблон!) и метод action_show(), принимающий один параметр (формат вывода):

[code lang="php"]

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;    

 

}

[/code]

В свойстве Request::instance()->action хранится имя исполняемого метода главного контроллера (поскольку вызван Request::instance() !) .

Шаблончик у меня выглядит так:

[code lang="php"]

<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>

[/code]

Хорошо, давайте пропишем наше творенье в Главном контроллере (Controller_Welcome). Поскольку виджеты, как предполагается, не должны зависеть от содержания страницы, то имеет смысл инициализировать их вне методов-обрабочиков страниц: например, в конструкторе или before(). Я очень люблю конструкторы, но надо же попробовать нововведение Kohana 3! Поэтому используем before().

[code lang="php"]

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();    

}

[/code]

Сначала мы завели массив $widgets, в котором будут храниться все виджеты. В методе before() мы вызываем parent::before(), поскольку там происходит инициализация нашего шаблона (можно не вызывать, но тогда придется вручную прописать $this->template = View::factory($this->template)).  

Далее мы привязываем наше хранилище виджетов к Главному шаблону, а затем делаем подзапрос нашего виджета, который и попадает в хранилище. Осталось сделать две вещи: прописать виджеты в Главном шаблоне

[code lang="php"]

<?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

    }

?>

[/code]

… и добавить в application/bootstrap.php специальный виджетный роут для HMVC

[code lang="php"]

Route::set('widget', '<controller>(/<action>(/<format>))', array('controller'=>'widget_\w+'))

    ->defaults(array(

        'controller' => 'widget_dummy',

        'action'     => 'index',

    ));

[/code]

Контроллер проверяется на соответствие с помощью регулярки, а по дефолту задается не существующий пока контроллер Controller_Widget_Dummy и метод action_index() (если хотите, можете их прописать, мы же не будем отягощать туториал).

Обновите страницу нашего тестового сайта — все должно заработать. Если вам не нравится показываемое время, исправьте в application/bootstrap.php временную зону (я исправил на родную 'Europe/Minsk').

Чтобы добавить виджет на каую-нибудь страницу, можно прописать в соответствующем методе вызов типа

[code lang="php"]

$this->widgets[] = Request::factory('widget_date/show/hour-min')->execute();

[/code]

Признаю, это не очень удобно. Что, если вам нужно более гибко настраивать показ виджета? Нужен конфиг. Давайте создадим новый виджет «Cdate», во всем подобный предыдущему, но совершеннее smile Нужно переименовать контроллер и шаблон виджета, малость подправить шаблон и подключить виджет в Controller_Welcome::before(), если хотим увидеть, — и все!

Начнем модификацию. Сначала в application/config/widget/ добавим конфиг cdate.php, например, такой:

[code lang="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'),

    ),

    

);

[/code]

Здесь я прописал несколько вариантов конфигурации, каждый из которых содержит, во-первых, формат отображения виджета, во-вторых, массив страниц, на которых виджет нужно отображать.

Метод загрузки конфига пристроим в родительском контроллере Controller_Widget:

[code lang="php"]

protected $_config;

    

public function load_config($conf_name,$conf_entry='default')

{

    $this->_config = Kohana::config($conf_name.'.'.$conf_entry);

}

[/code]

В свойстве контроллера Controller_Widget::$_config будет храниться загруженный конфиг.

Следующий этап — правка контроллера нашего виджета. Добавляем public $config_name = 'widget/cdate', а в методе Controller_Widget_Cdate::action_show() грузим конфиг, убеждаемся, что мы в правильном месте, и парсим формат:

[code lang="php"]

$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']));

[/code]

Осталось в Главном контроллере добавить в before() вызов контроллера виджета:

[code lang="php"]

$this->widgets[] = Request::factory('widget_cdate/show/page')->execute();

[/code]

Все работает: виджет отображается только на page1 и page2, как и прописано в конфигурационном файле.

 

Кстати, желающие могут вызывать виджет прямо из шаблона:

[code lang="php"]

<?php

    echo Request::factory('widget_date/show/year')->execute();

?>

[/code]

Скачать application

Всех именинников поздравляю с днем памяти св. благоверного князя Александра Невского!

Комментариев: 6 RSS

1 Remas 13-09-2009 00:04

Исходники прикреплены от другой статьи.

2 Sezarin 13-09-2009 00:14

...Кстати, желающие могут вызывать виджет прямо из шаблона:

От имени всех желающих - благодарность, и...

Results Triple Match: ZF:KO3:YII - 3:4:5

3 Александр Купреев 14-09-2009 11:58

Remas

извините, исправился

Sezarin

за что YII "5"?

4 Sezarin 14-09-2009 16:12

В Yii имеется CWidget - мощный класс виджетов со множеством подклассов.

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

5 Александр Купреев 15-09-2009 13:51

спасибо, буду иметь в виду

6 bitcreator 24-09-2009 22:40

Александр, спасибо за статьи о КО3!

С нетерпением жжду продолжения! smile

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


Используйте нормальные имена.

     

  

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

MaxSiteAuth. Войти через loginza

(обязательно)