Views в Kohana3

Рубрика: Web frameworks
Метки: |
Среда, 12 августа 2009 г.
Просмотров: 1834
Подписаться на комментарии по RSS

В прошлом туториале мы установили Kohana на сборку XAMPP и запустили простейший трехстраничный сайт. Фактически, он представлял собой «голый» контроллер, выводящий в браузер запрошенную страницу. Бесспорно, такой подход имеет право на существование, особенно в веб-приложениях без пользовательского интерфейса. Однако при наличии достаточно сложной верстки отдаваемых посетителю страниц очень неудобно делать все в контроллере. Хочется выделить разметку в отдельный файл (или файлы; хотя это менее удобно для верстальщика, многие современные CMS делают именно так) и только «натягивать» их на данные по мере необходимости. Тут нам на помощь приходит реализованный в фреймворке Kohana архитектурный паттерн Model-View-Controller (MVC) в той своей части, которая обозначается как View-Controller. View как раз представляет собой шаблоны разметки для вывода данных, сами же данные предоставляются контроллером (хотя можно и напрямую из модели брать), который компонует Views в отдаваемую страницу. Впрочем, теория лучше понимается в сочетании с практикой. Давайте добавим к уже написанному нами контроллеру шаблоны отображения (Views).

Однако сначала обновимся до второго релиз-кандидата Kohana3. Не обновляем только наш контроллер и вручную (либо с помощью системы управления версиями) перезаписываем все, что нужно, в application/bootstrap.php, потому как некоторые приятные изменения там произошли. После обновления все должно заработать как раньше.

Итак, прикрутим к нашему котроллеру какой-нибудь View. Например, к нашей супер-авто-навигации. Создадим папку application/views/elements/, куда и закинем файл navigation.php. Шаблон будет очень простой (я не дизайнер):

  1.  <ul id="site_nav">
  2.  <li style="display: inline; font-weight: bold;">Navigation: </li>
  3.  <?php
  4.  if (is_array($items) AND ! empty($items))
  5.  {
  6.      foreach ($items as $item)
  7.      {
  8.  ?>
  9.      <li style="display: inline;"><?php echo $item; ?></li>
  10.  <?php
  11.      }
  12.  } else {
  13.      echo 'No navigation presented';
  14.  }
  15.  ?>
  16.  </ul>

Сейчас нужно подключить его в контроллере, попутно передав нужные данные. Думаю, что логичнее всего будет сделать это в нашем методе Controller_Welcome::_simple_nav() отвечающем за формирование навигационных элементов. Да, предварительно надо переделать метод так, чтобы он формировал массив навигационных элементов. Это просто: вместо конкатенации строк будет добавление элемента массива

  1.  $slugs[] = HTML::anchor($slug, url::title($slug));

Ну а дальше классически присоединим шаблон, передав в него данные

  1.  $view = new View('elements/navigation');
  2.  $view->items = $slugs;

Кстати, можно присоединить шаблон более элегантно, с использованием «фабричной» генерации объекта и метода View::set('template_var', $controller_var), позволяющего присвоить переменной шаблона $template_var значение переменной $controller_var:

  1.  $view = View::factory('elements/navigation')
  2.              ->set('items',$slugs);

Все работает!

Есть способ несколько упростить формирование отдаваемой страницы, избавившись от рутинной необходимости явно цеплять основной шаблон и выводить его в $this->request->response. Для этого достаточно унаследовать наш контроллер не от стандартного класса Controller, а от не менее стандартного Controller_Template:

  1.  class Controller_Welcome extends Controller_Template {

Главное, не забыть, что по умолчанию для основного шаблона ищется и используется views/template.php. Если у вас он другой, нужно это явно декларировать, например, так

  1.  public $template = 'custom_template';

Создадим простой базовый шаблон custom_template.php и поместим его в views/, сверстав как-то так:

  1.  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  2.  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  3.  <head>
  4.  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  5.  <meta name="keywords" content="" />
  6.  <meta name="description" content="" />
  7.  <title><?php if ( ! empty($title)) echo $title; ?></title>
  8.  </head>
  9.  <body>
  10.  <div class="container">
  11.      <div id="navigation">
  12.          <?php echo $navigation; ?>
  13.      </div>
  14.      <div id="content">
  15.          <?php echo $content; ?>
  16.      </div>
  17.  </div>
  18.  </body>
  19.  </html>

Теперь из методов контроллера заполним его данными. Вот, например, как я это сделал в методе Controller_Welcome::action_index():

  1.  public function action_index()
  2.  {
  3.      $this->template->title = 'Main page';
  4.      $this->template->content = 'hello, world!!';
  5.      $this->template->navigation = $this->_simple_nav();
  6.  }

Заметьте: уже нет необходимости явно присваивать свойству $this->request->response сгенерированный вид. Присвоение сейчас осуществляется в унаследованном методе Controller_Welcome::after().

Давайте добавим еще немного удобства в рутинную процедуру заполнения шаблонов данными. В этом нам поможет метод View::bind(), позволяющий на самой ранней стадии «привязать» к переменной шаблона какую-либо переменную контроллера и потом уже не следить за тем, где ее инициализировать. Чтобы наглядно показать простоту такого способа работы, создадим новый вид для отображения области контента: application/views/elements/content.php

  1.  <p>
  2.  <?php echo $p1; ?>
  3.  </p>
  4.  <p>
  5.  <?php echo $p2; ?>
  6.  </p>

Назначив его, мы должны заполнить $p1 и $p2, однако не можем сделать это раньше, чем эти  переменные определены:

 

  1.  $this->template->content = View::factory('elements/content')
  2.                                          ->set('p1',$par1)
  3.                                          ->set('p2',$par2);
  4.                                         
  5.  $par1 = 'news 1';
  6.  $par2 = 'news 2';

выдаст ошибку.

Но здесь можно поступить так:

  1.  $this->template->content = View::factory('elements/content')
  2.                                          ->bind('p1',$par1)
  3.                                          ->bind('p2',$par2);
  4.                                         
  5.  $par1 = 'news 1';
  6.  $par2 = 'news 2';

Нетрудно убедиться на практике, что сейчас все проходит как надо. В чем преимущество View::bind()? На практике в контроллере зачастую приходится переопределять значения переменных, выводимых в шаблон. Данный метод позволяет не отслеживать все такие переопределения, назначив «ответственные» переменные на ранней стадии обработки и делая дальше все, что душа пожелает.

Удачи!

ЗЫ. Кому нужно, можно скачать архив папки application/

]]>twitter.com Google Buzz google.com bobrdobr.ru del.icio.us technorati.com linkstore.ru news2.ru rumarkz.ru memori.ru moemesto.ru]]>

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

  1. 2009-08-12 в 12:57:48 | Sezarin
    ]]>]]>

    Прочитав очередной пост-главу у меня возникли некоторые вопросы по построению шаблона страницы, в частности, возможна ли вставка в шаблон дополнительных блоков, скорее всего - виджетов, привязанных к контролерам отдельных модулей? Например:

    <div id="right-block">
      <?php echo $widget_one; ?>
      <?php echo $widget_twoo; ?></div>
    

    И, если да, то как при этом будет осуществляться вызов соответствующих контролеров.

  2. 2009-08-12 в 17:36:28 | Александр Купреев
    ]]>]]>

    Конечно, возможна

    Об этом будут следующие главы smile

  3. 2009-08-19 в 13:43:52 | Броткин Иван (анонимно)

    По поводу bind() - очень удобно при цикличном выводе блоков (комментарии к примеру):

    $subview = View::factory('comment')->bind('comment', $comment);
    foreach($comments as $comment) 
      echo $subview;
    

    Вроде так smile

  4. 2009-08-19 в 14:47:15 | Александр Купреев
    ]]>]]>

    Спасибо, Иван, очень классная иллюстрация удобства View::bind()! Действительно, в этом случае отпадает необходимость в цикле переназначать $subview, достаточно это сделать однажды перед циклом.

  5. 2009-09-07 в 00:37:51 | Ахмадишин Ренат (анонимно)

    Было просто великолепно узнать как все же вставить свои виджеты.

  6. 2009-09-07 в 10:16:37 | Александр Купреев
    ]]>]]>

    хорошо, подождите несколько дней -- напишу продолжение

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

Не регистрировать/аноним

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

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



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