понедельник, 10 января 2011 г.

Kohana 3: Работа с отображениями

В предыдущей части Kohana 3: Первые шаги мы научились устанавливать фреймворк из репозитария, настраивать index.php, создавать контроллер, создавать метод вызываемый по умолчанию и немного общаться с внешним миром. В этой части мы познакомимся с отображениями (views), научимся передавать данные в отображения, работать с вложенными отображениями и переменными отображений.

Используется несколько вариантов перевода View на русский язык, в основном используется три: представление, вид или отображение. Я буду использовать отображение, мне оно привычнее.

Для начала перейдём в каталог с нашей копией репозитария фреймворка Kohana. Если в каталоге application отсутствует каталог views мы создадим его, а в нём создадим подкаталог pages. Теперь в каталоге pages создадим файл first.php со следующим содержимым:

<html>
<head>
     <title>Привет!</title>
</head>
<body>
     <h1>Это моё первое отображение</h1>
</body>
</html>

В контроллере first.php изменим содержимое метода action_index(), на следующие:

public function action_index()
     {
          $this->request->response = View::factory('pages/first');
     }

Сохраним его и откроем http://kohana.local/first/ в браузере. Вы должны увидеть "Это моё первое отображение".

Код используемый в нашем методе очень простой, мы использовали метод "Factory" класса "View" для загрузки файла application/views/pages/first.php, сформировали его и вывели. Вернёмся к application/views/pages/first.php и добавим в него:

<?php echo $content;?>

После тэга h1. Ваше отображение должно выглядеть так:

<html>
<head>
     <title>Привет!</title>
</head>
<body>
     <h1>Это моё первое отображение</h1>
     <?php echo $content;?>
</body>
</html>

Если мы обновим страницу браузера, то увидим сообщение об ошибке о неопределённой переменной. Давайте исправим это. Изменим содержимое метода action_index() контроллера на следующее:

public function action_index()
{
    $view              = View::factory('pages/first');
    $view->content     = 'У нас есть данные!';
    $this->request->response = $view->render();
}

Теперь, если мы обновим страницу браузера, то увидим "Это моё первое отображение" и ниже "У нас есть данные!". Рассмотрим каждую строку кода метода.

$view = View::factory('pages/first');

Здесь мы загружаем файл ("application/views/pages/first.php") в контроллер отображения.

$view->content     = 'У нас есть данные!';

Присваиваем переменной отображения "content" значение "У нас есть данные!", переменная и значение будут доступны в отображении.

$this->request->response = $view->render();

Формируем и выводим страницу.

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

public function action_index()
{
    $data['content']         = 'У нас есть данные!';
    $view                    = View::factory('pages/first', $data);
    $this->request->response = $view->render();
}

Обычно для передачи переменных в шаблон используются массивы в которых ключ это имя переменной, а значение, собственно значение переменной. Но мы ещё не закончили, вот ещё два способа сделать тоже самое:

public function action_index()
{
     $view = View::factory('pages/first')
          ->set('content','У нас есть данные!');

     $this->request->response = $view->render();
}

Выше использовался метод цепи, используя этот метод можно назначить все переменные отображения. И четвертый способ:

public function action_index()
{
    $content = 'У нас есть данные!';
    $view = View::factory('pages/first')
          ->bind('content', $content);
    $this->request->response = $view->render();
}

В выше приведённом способе мы использовали метод bind класса View, как вы заметили его тоже можно использовать с методом цепи. Метод bind немного отличается от set, он не устанавливает значение переменной отображения, а создаёт ссылку на переменную. Таким образом для изменения содержимой отображения content на нужно просто изменить содержимое переменной $content.

Если мы внесём следующие изменения:

public function action_index()
{
     $content = 'У нас есть данные!';
     $view = View::factory('pages/first')
          ->bind('content', $content);
     $content = 'Наши данные изменились';
     $this->request->response = $view->render();
}

То вместо "У нас есть данные!", мы увидим "Наши данные изменились".

Давайте сделаем отображение в отображении! Создадим в каталоге "application/views/" каталог с именем "blocks". Далее создадим в этом каталоге файл с именем first_inner.php и следующим содержимым:

<h3>Это вложенное отображение</h3>

Теперь откроем файл application/views/pages/first.php и добавим в него следующие строки:

<?php echo View::factory('blocks/first_inner')->render(); ?>

Наш файл отображения должен стать примерно таким:

<html>
<head>
     <title>Привет!</title>
</head>
<body>
     <h1>Это моё первое отображение</h1>
     <?php echo $content;?>
     <?php echo View::factory('blocks/first_inner')->render(); ?>
</body>
</html>

Итак, если мы обновим страницу браузера, то увидим то же, что было раньше и "Это вложенное отображение" добавленное в конце. Это удобно использовать для статического контента, но мы не сможем использовать переменные, непосредственно в этом отображении. Давайте это исправим. Для начала вернёмся к нашему контроллеру ("application/classes/controllers/first.php") и отредактируем метод "action_index":

public function action_index()
{
     $first_inner['content']     = 'У нас есть ещё данные';
     $first['content']          = 'У нас есть данные!';
     $first['first_inner']     = View::factory('blocks/first_inner', $first_inner)
                                        ->render();
     $view                         = View::factory('pages/first', $first);
     $this->request->response = $view->render();
}

Здесь будет сформировано отображение, которое будет помещено в массив переменных из которых будет сформировано главное отображение. Если вы заметили, то я сначала сформировал вложенное отображение и поместил его в массив переменных главного отображения, а затем сформировал и вывел главное отображение. Далее нам нужно изменить главное отображение ("application/views/pages/first"). Вставим эту строку вместо той, где выводилось вложенное отображение:

<?php echo $first_inner; ?>

Наше отображение должно выглядеть так:

<html>
<head>
     <title>Привет!</title>
</head>
<body>
     <h1>Это моё первое отображение</h1>
     <?php echo $content; ?>
     <?php echo $first_inner; ?>
</body>
</html>

Теперь внесём изменения во вложенное отображение ("application/views/blocks/first_inner.php"):

<h3>Это вложенное отображение</h3>
<?php echo $content; ?>

Если мы обновим страницу браузера, то увидим следующее:

Это моё первое отображение
У нас есть данные!
Это вложенное отображение
У нас есть ещё данные

Выглядит круто, теперь мы можем делать более удобные модульные отображения. Давайте добавим глобальные переменные, которые будут доступны в наших отображениях. Вернёмся к контроллеру ("application/classes/controllers/first.php") и добавим в начало метода "action_index()" следующую строку:

View::set_global('x', 'Это глобальная переменная');

Теперь наш метод выглядит так:

public function action_index()
{
     View::set_global('x', 'Это глобальная переменная');

     $first_inner['content']     = 'У нас есть ещё данные';
     $first['content']          = 'У нас есть данные!';
     $first['first_inner']     = View::factory('blocks/first_inner', $first_inner)
                                        ->render();
     $view                         = View::factory('pages/first', $first);
     $this->request->response = $view->render();
}

Добавим в оба наши отображения строку:

<br/><?php echo $x;?>

После обновления страницы браузера мы увидим надпись "Это глобальная переменная" в двух местах на странице. Как вы видите это довольно удобно, если какие-то данные необходимо вывести в нескольких отображениях. В основном мы используем метод set_global класса View, это делает переменную доступной во всех копиях объекта View. Так же можно использовать метод bind_global для создания ссылки на переменную. Глобальные методы класса View удобно использовать в методе before() контроллера.

P.S. За основу взяты материалы с Inside DealTaker и Unofficial Kohana 3.0 Wiki

Другие части руководства:

Похожие по тематике посты:

2 комментария:

Unknown комментирует...

Отличия от kohana 3.1:
$this->request->response = $view->render(); в 3.1 заменяем на $this->response->body($view->render());
Если неправ - автор поправит, я пока еще учусь.

alex комментирует...

Вы правы в версии 3.1 класс Request был разделён на два класс Request и Response.

$this->request->response = 'foo';

Было изменено на:

$this->response->body('foo');

Это было указано в руководстве по миграции http://kohanaframework.org/3.1/guide/kohana/upgrading (http://dev-mark.blogspot.com/2011/02/kohana-31_09.html)

Спасибо за ваш комментарий.