Запрос внутри запроса

Комментарии: 33  Просмотры: 26 738

Как вы помните (еще об этом написано на главной странице), фреймворк Kohana использует архитектурную модель HMVC (Hierarchical Model View Controller — Иерарархические Модель-Контроллер-Вид). Но до текущего момента мы использовали только MVC, точнее даже VC (не путать с WC), так как до модели мы еще не добрались. HMVC — это развитие концепции MVC. Рисунок, представленный ниже, отображает принцип ее работы:

Архитектурная модель HMVC

Совокупность Модель-Вид-Контроллер называется Триадой. Каждая триада функционирует независимо от других. Триада может запросить доступ к другой триаде через контроллер. Использование триад MVC позволяет добиться более глубокой и тщательной разработки приложений. Также уменьшается зависимость между различными частями приложения.
Давайте рассмотрим удобство такого подхода на примере комментариев к статьям. Как вы помните, у нас по адресу http://kohana/articles/article1 находится статья, название которой (для поиска по базе) — article1. Естественно комментарии уникальны, хранятся в базе данных и привязаны к конкретной статье. Мы работу с базой данных в Кохане еще не проходили, поэтому позже заэмулируем эту ситуацию. Но давайте обо всем по порядку. Измените Контроллер articles.php следующим образом:

<?php defined('SYSPATH') or die('No direct script access.');
 
class Controller_Articles extends Controller_Common {
 
    public function action_index()
    {
        $id = $this->request->param('id');
 
		if($id)
		{
			$content = View::factory('/pages/article')
				->set('article', $id)
				->bind('comments', $comments);
 
			$comments_url = 'comments/' . $id;
			$comments = Request::factory($comments_url)->execute();
		}
		else
		{
			$content = View::factory('/pages/articles');
		}
 
        $this->template->content = $content;
    }
 
} // Articles

Здесь я поменял блок, где выводится одна статья. Добавилась переменная $comments, которую мы передаем в блок с контентом. В ней собственно и будут лежать комментарии к статье. Откуда они там берутся ? Мы получаем их из специального Контроллера, сделанного под комментарии. Контроллер этот вызывается по адресу http://kohana/comments/наша статья, т.е. для адреса http://kohana/articles/article1 комментарии находяться по адресу http://kohana/comments/article1 (этот адрес собственно и присваивается переменной $comments_url). Логично, что раз у нас появился новый адрес, значит нужен новый роут. Поэтому в файле bootstrap.php добавьте следующие строчки (только добавляйте над роутами, относящимися к articles, в силу их «универсальности»:

Route::set('comments', 'comments/<id>', array('id' => '.+'))
	->defaults(array(
		'controller' => 'comments',
		'action'     => 'index',		
	));

Вот теперь, если обратиться по адресу http://kohana/comments/article1, у нас будет грузиться Контроллер из файла comments.php (на самом деле он пока у меня только будет грузится, у вас нет, так как вы его еще не сделали :) ). Грузиться он будет посредством строки:

    $comments = Request::factory($comments_url)->execute();

Она как раз и обращается по вышеуказанному адресу за комментариями. Но, результат мы получим не в окно браузера, а в переменную. Которую и передадим в блок контента. Как вы уже наверное догадались, нам надо реализовать Контроллер и Вид (обойдемся пока без модели) для комментариев. Это и будет та самая Триада.
Создайте Контроллер comments.php:

<?php defined('SYSPATH') or die('No direct script access.');
 
class Controller_Comments extends Controller {
 
    public function action_index()
    {
		$id = $this->request->param('id');
 
		$content = View::factory('/comments/show')
			->bind('comments', $comments);
 
		// Вместо switch-case будет вызов Модели
		switch($id)
		{
			case 'article1':
			$comments = array(
				array('name' => 'Вася', 'comment' => 'Привет, Петя'), 
				array('name' => 'Петя', 'comment' => 'Привет, Вася'),
			);			
			break;
 
			case 'article2':
			$comments = array(
				array('name' => 'Гена', 'comment' => 'Привет, Мир'),
			);			
			break;	
 
			default:
			$comments = array();		
		}
 
		$this->response->body($content);
    }
 
} // Comments

Разберем его подробнее. Поскольку блок комментариев абстрактен сам по себе, ему не нужны ни заголовок, ни описание, ни прочие параметры, которые мы прописывали в Базовом Контроллере. Поэтому наследовать мы будем напрямую Controller. В методе мы еще раз получаем название нашей статьи (переменная $id). После этого в переменную $content передаем наш файл Вида для комментариев и массив комментариев $comments. Этот массив в условиях боевого сайта мы будем получать из базы данных, исходя из $id и относящихся к нему комментариев. А пока я реализовал это посредством switch — case.
Наконец, строкой $this->response->body($content) обрабатывается и отдается все, что в итоге получилось, но поскольку вызов Контроллера производился из другого Контроллера, а не напрямую, то отдается в переменную, а не в окно браузера.
Теперь давайте добьем код до конца. Осталось сделать Вид для комментариев.
В папке с шаблонами создайте папку comments и в ней файл show.php. В нем будет просто цикл обработки массива:

<?php foreach($comments as $comment): ?>
 
    <strong>Имя пользователя:</strong><br />
    <?php echo $comment['name']; ?><br />
    <strong>Комментарий пользователя:</strong><br />
    <?php echo $comment['comment']; ?>
    <br /><hr /><br />
 
<?php endforeach; ?>

Сразу проверьте, что при переходе по адресу http://kohana/comments/article1 у вас выводятся комментарии Васи и Пети, а по адресу http://kohana/comments/article2 комментарий Гены. Если все работает, то остался последний штрих. В шаблоне article.php допишите вывод комментариев. Должно получится как-то так:

Статья <?php echo $article; ?>
<br /><br />
<?php echo $comments; ?>

Все. Теперь заходите в статьи и наслаждайтесь тем, что от статей одни только заголовки, а юзеры уже что-то понаписали :) . Вот мой Образец.
Напоследок хочется еще сказать вот что. Мне лично не очень будет нравиться, если всякие проходимцы будут лазить по адресам вроде http://kohana/comments/article1, т.е. сразу смотреть комментарии, в обход статей. Хотя адресов они могут и не знать, но все же. Закрыть такой несанкционированный доступ очень просто. Допишем в comments.php условие:

if(Request::initial() === Request::current())
    Request::initial()->redirect(URL::site());

И таким образом отсечем нарушителя редиректом. Нечего лазить там, где не надо. На этом совсем все. Переваривайте информацию, пробуйте и до встречи в следующем уроке.

<< Назад | Вперед >> | Обсудить на форуме


К записи оставлено 33 коммент.

Добавлю, что для проверки можно также использовать is_initial(), которое вернет True или False.

как при помощи валидации kohana организовать аякс проверку?

Очень просто:
В случае ошибок есть массив $errors. Его отправляешь ответом — если не прошла валидация, если все ок отправляешь true. А сам механизм очень простой, в данном случае можно обойтись JSON и Jquery.

добавьте в описание, еще то что можно передавать параметры.

ErrorException [ Fatal Error ]: Class ‘Pagination’ not found

У меня в 3.2 нету такого модуля и класса, как я нагуглил — его надо устанавливать дополнительно

верно. это я случайно с этого
http://kohanaframework.su/modules/pagination
урока скопипастил и не посмотрел. щас поправлю.

Поясните пж не много эту строчку:

$comments = Request::factory($comments_url)->execute();

Назначение мне понятно, но не понятна реализация. Т.е здесь происходит обращение к контроллеру ‘comments’, а то что идёт после «/» — в качестве параметра?

execute() — что делает этот метод?

После / идет идентификатор текущей статьи. Нам ведь нужно знать, к какой статье выводить комментарии.
А метод execute запускает запрос, который был составлен. Этот метод в Кохане используется часто, посмотрите те же базы данных.

$request = Request::initial();

if(Request::initial() === Request::current())
Request::initial()->redirect(URL::site());

Извиняюсь, а зачем мы создаем переменную $request.
Если мы ей не пользуемся?

Дада. Лишнее. Сейчас уберу. Вообще лучше проверку производить через

if($this->request->is_initial())
...

Добрый день.
Какие еще есть способы запроса из контроллера другого контроллера?

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

Ну можно роут один универсальный написать. Разграничить регулярками.
И вы уверены, что вам нужно на все части создавать контроллеры и нельзя обойтись просто подключением шаблона ?

Можно конечно обойтись и одним контроллером. Но мне кажется, что идея HMVC: разбивать задачу на более мелкие части (в данном случае имеются ввиду — контроллеры элементов страницы) и разрабатывать отдельно каждую часть.

Вот мне и интересно какие еще есть методы обращения к другим контроллерам?

Кстати, в моем случае, через «роуты» и не получиться. Ведь мне надо, чтобы вызывался контроллер /page/, а в нем уже вызывались контроллеры элементов страницы, которые не имеют самостоятельного адреса в URL.

Как такое можно реализовать?

Не обойтись одним контроллером, а обойтись одним роутом :) Контроллеры конечно должны быть разные.
А элементы страницы можно вызывать через роуты. Посмотрите, как вызов капчи устроен. Между прочим тоже через роут.

Спасибо Вам за ответы. Я подниму эту тему на форуме, что бы не засорять уроки.

 
Request::initial()-&gt;redirect(URL::site());
 
//неверно перенаправляет в случае 
 
'base_url'   =&gt; '/kohana/',
 
RewriteRule .* kohana/index.php/$0 [PT]
//наверное, потому что redirect уже содержит
...
public function redirect($url = '', $code = 302)
...
$url = URL::site($url, TRUE, Kohana::$index_file);

                              
                          

Что-то я не совсем улавливаю концепцию.. Если на разных разделах сайта (контролерах) у меня масса одних и тех же блоков, то их разумно реализовать в отдельных контроллерах. Но получается что при сборке страницы я вынужден каждый блок формировать через отдельный запрос к серверу..? Вместо локального обращения к внутренним ресурсам системы? Это же замедляет отдачу контента.. Я на типе кавычек пытаюсь экономить в РНР.. а тут такой тормоз..? Скажите что я ошибаюсь..

В Kohana 3.3 больше не поддерживается метод Request->redirect(‘url’). Можно использовать HTTP::redirect(‘url’).



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

Пожалуйста, зарегистрируйтесь для комментирования.