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

Комментарии: 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 коммент.

скажите пожалуйста куда имеенно вставлять етот код
if(Request::initial() === Request::current())
Request::initial()->redirect(URL::site());

і как он должен виглядить в версии 3.3
спасибо

В Контроллер Comments.php, перед строчкой:
$id = $this->request->param(‘id’);

Лучше после строчки, чтобы $id уже была объявлена.
Тогда редирект можно на саму статью сделать, а не на главную

в 3.3 должно выглядить так:
if(Request::initial() === Request::current())
HTTP::redirect(URL::site());

Вот это и есть то, ради чего стоит использовать Kohana. Все остальные плюшки, не настолько привлекательны, что бы слазить с насиженного CI. Да детка! Вменяемая модульность купе с контроллером шаблонов. Layout, как он есть… а не жалкая эмуляция на костылях созданных своими руками и попутным изобретением велосипеда, как в CI. Спасибо.

я знал, что будет подвох… ну почему я розовый шестигранник? =(

А зачем нам надо давать комментариям отдельный роут и закрывать его доступ?

Я так понимаю вся красота роута в том, что потом мы можем ajax забрать необходимую информацию по роуту комментариев?

Почему в этом случае не сделать модуль который взвращал бы комментарии, без роута. Что-то типа

Comments::get(1); ?

При обращении к статье выдается ошибка ErrorException [ 8 ]: Array to string conversion ~ SYSPATH\classes\Kohana\Log\Writer.php [ 81 ]

Ошибка исправлена, был не верный путь к виду с перебором комментарий

В Кохане 3.3 из класса Request удалили метод redirect().
Поэтому вместо:
Request::initial()->redirect(URL::site());
надо писать так:
Controller::redirect(URL::site());

Или так же можно сделать
HTTP::redirect(URL::site());

Зачем на главную?

$id = $this->request->param(‘id’);

if(Request::initial() === Request::current())
HTTP::redirect(URL::site().’articles/’.$id);

У меня работает такая конструкция:

$id = $this->request->param('id');
                if(Request::initial() === Request::current())
                HTTP::redirect(URL::site('article/'.$id));

Странно что тут об этом ни кто ничего не написал, но лично я долго понять не мог почему не выводятся комменты когда заходишь в статья1, статьи2..
Вообщем если
$comments_url = ‘comments/’ . $id;
То получается мы вызываем site.ru/comments/1
а надо site.ru/comments/article1
т.е. правильно будет
$comments_url = ‘comments/article’ . $id;

Ну или в switch изменить сами знаете что. Вариант со switch лучше) Админ, поправляй.



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

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