Роутинг — Часть 3

Комментарии: 84  Просмотры: 28 478

В этом уроке мы рассмотрим до конца основные возможности роутинга в Кохане. Ну а если вдруг что-то пропустим, изучим уже по мере надобности в последующих уроках.
В настройках роута, помимо указания в массиве таких параметров, как controller и action, есть возможность указывать директорию directory. Для чего это может понадобиться ? Самый типичный пример — это раздел администратора. Довольно часто он прилично отличается по своей структуре от основного сайта, поэтому обычно его Контроллеры выносят в отдельную директорию. Вот эту самую директорию мы в роуте и пропишем. Делается это легко. В массиве появляется новый параметр directory:

Route::set('admin', 'admin(/<controller>(/<action>(/<id>)))')
            ->defaults(array(
            'directory'  => 'admin',
            'controller' => 'main',
            'action'     => 'index',
            ));

Теперь нужно создать файл Контроллера main.php и поместить его в директорию application/classes/controller/admin/. Контроллер будет очень простым:

<?php defined('SYSPATH') or die('No direct script access.');
 
class Controller_Admin_Main extends Controller_Common {
 
    // Главная страница
    public function action_index()
    {
        $content = View::factory('/admin/show');
        $this->template->content = $content;
    }
 
} // End Main

Здесь только два нюанса.
1. Поскольку Контроллер находится внутри директории admin, то название класса будет не Controller_Main, а Controller_Admin_Main. О формировании названий классов я неоднократно говорил и еще раз на всякий случай напоминаю.
2. У админки скорее всего будет свой собственный базовый Контроллер. Но здесь, для упрощения, я унаследовал класс Controller_Common. Просто имейте ввиду.
Ну и наконец последнее, что нужно сделать — это создать шаблон админки. Лежать он будет в application/views/admin/ и называться show.php. Не будем мучиться и придумывать что-то сложное, это вы сделаете сами. Я просто поместил туда текст:

<h3>Это админка</h3>

И теперь, если вы перейдете по адресу http://kohana/admin, то увидите свою админку во всей ее красе.
Для директорий также можно указать регулярное выражение, как мы это делали с action для страниц «О сайте» и «Мои контакты». Приведу пример из официального мануала фреймворка:

Route::set('sections', '<directory>(/<controller>(/<action>(/<id>)))', array('directory' => '(admin|affiliate)'))    
        ->defaults(array(        
            'controller' => 'home',        
            'action'    => 'index',    
        ));

Как это работает, должно быть понятно. Если кому-то непонятно, добро пожаловать в комментарии.
Идем дальше. Иногда нам нужно знать, какой Контроллер или action-метод отработал в данный момент. И очень часто нам нужно получить значения каких-то параметров, переданных в адресной строке. Немного я об этом уже говорил в предыдущих уроках, ну а теперь подробно.
Названия текущей директории, контроллера и action-метода можно получить следующим образом.
В контроллере:

$this->request->directory();
$this->request->controller();
$this->request->action();

Где угодно:

Request::current()->directory();
Request::current()->controller();
Request::current()->action();

Все остальные параметры (такие как id1, id2 итд) можно получить следующим образом:
В контроллере:

$this->request->param('id');

Где угодно:

Request::current()->param('id');

Понятно, что здесь в скобках указывается название нужного нам параметра. И это необязательно будет id.
Теперь, если мы исправим наш админский шаблон на такой:

<h3>Это админка</h3>
Директория  - <?php echo Request::current()->directory(); ?><br /><br />
Контроллер - <?php echo Request::current()->controller(); ?><br /><br />
Метод - <?php echo Request::current()->action(); ?>

То в админке получим:
Это админка
Директория — admin
Контроллер — main
Метод — index

Раз уж мы заговорили о параметрах, просто чтобы вы знали, их можно получать и в качестве аргументов метода, но лучше так не делать (Дополнение: как выяснилось, в версии 3.2 этого все-таки нельзя уже делать. Убрали и правильно сделали).
Теперь давайте поговорим про формирование адресов вида http://kohana/article1.html. Думаю вы не раз видели такие адреса. На первый взгляд можно подумать, что сайт полностью сделан из статических html-страниц. В Кохане все это реализовывается также через роуты.
Опять возьму пример из официального мануала:

Route::set('static', '<path>.html',  array('path' => '[a-zA-Z0-9_/]+',))  
        ->defaults(array(
            'controller' => 'static',    
            'action' => 'index',  
        ));

У нас метода action_index в Контроллере static нет, но вы можете создать его, прописав внутри что-то вроде:

echo $this->request->param('path');

и тогда уже по адресу http://kohana/article1.html вы получите свой article1.
Ну и напоследок хотелось бы сказать про метод get. Если уже знакомый нам метод set устанавливает маршрут, то метод get, наоборот, получает маршрут. Выглядит это как-то так:

Route::get('default')->uri(array(
            'controller' => 'test',
            'action'    => 'index',
        ));

Если засунуть этот код внутрь контроллера и вывести через echo, то мы получим адрес test/index. А если написать:

Route::get('admin')->uri(array(
            'controller' => 'test',
            'action'    => 'index',
        ));

И вывести, то получится уже admin/test/index. Таким образом формируется нужный URL, согласно маршрутам, прописаным в соответствующих роутах. Возникает закономерный вопрос, а для чего это может нам понадобится. Если честно, я данный метод еще ни разу не использовал. Но это может пригодится для формирования ссылок в проекте. Тогда при каких-то изменениях, касающихся ваших ссылок (например, при замене косой черты на подчеркивание), вам не нужно будет их править, они изменятся по всему сайту автоматически.
А теперь совсем напоследок расскажу о кешировании роутов. Как вы успели заметить, хотя мы только начали создавать что-то вроде блога, но различных роутов накопилось уже приличное количество. Естественно каждый раз при загрузке сайта происходит обработка всех этих роутов, что довольно ресурсоемко, особенно если их много. Поэтому, когда разработка сайта завершена и роуты уже изменяться не будут, их обычно кешируют. У класса Route есть метод Cache, который принимает булево значение TRUE или FALSE. Я не устану повторять, что Кохана очень хорошо самозадокументирована, поэтому если вы не поленитесь и найдете в файле system/classes/kohana/route.php этот метод, то в комментариях увидите подробное (но на английском) его описание:

   /**
    * Saves or loads the route cache. If your routes will remain the same for
    * a long period of time, use this to reload the routes from the cache
    * rather than redefining them on every page load.
    *
    *     if ( ! Route::cache())
    *     {
    *         // Set routes here
    *         Route::cache(TRUE);
    *     }
    *    ...
    */

То есть все, что нужно сделать — это поместить наши роуты внутрь этого условия (вместо текста «//Set routes here»). Если вы все сделали правильно, то после открытия любой страницы сайта вы увидите сгенерированный кеш в папке application/cache/.
Ну теперь окончательно все. Довольно длинный урок получился. Это в качестве компенсации, что долго ничего не выкладывал :) Всех с наступающим. Встретимся в 2012 году.

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


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

Столкнулся с проблемой в кохана 3.2 редирект не работает на локалхосте, а на хостинге все тип топ(
может денвер нужно как нить настраивать под кохану????

Хм. Ни разу такой проблемы не испытывал. Ни на локалхосте, ни на хостинге. На локалхосте стоит денвер.
Редирект через Request::initial()->redirect() делаете ?

Вот таким вот образом:
$this->request->redirect();

А мой вариант тоже не работает ?

неа,я видел его в описании редиректа.Думаю теперь денвер переставить

Не могу сообразить, может подскажете: если у меня layout гравной один, а layout внутренних другой, как мне это реализовать? То ли роутами, то ли public $template нужный подставлять, то ли контроллер разный грузить… запутался я

По сути нужно то проверку Request::current()->uri() делать на «/», но как это рационально сделать, в каком нибудь common контроллере… %)

Да, можно там. При определенных условиях меняем шаблон..например
$this->template = View::factory(‘main2′);

Вы не смотрите на меня, как на последнюю инстанцию :) Я сам готов послушать хорошие советы, так как сам самоучка и не факт, что нельзя сделать лучше. Паттерны для того и придумывали )

То есть все, что нужно сделать – это поместить наши роуты внутрь этого условия (вместо текста «//Set routes here»).
а где это прописывать ? в bootstrap.php?

Здравствуйте.

Не подскажите, как построить роут типа «mail/2342/?code=ewe342424wr»?

Это нужно для Api Mail кто догадался. Пробовал так: «mail//?=» — не сработало. Наверное из-за ? и =. Как можно правильно составить рег. выражение для параметров, чтобы роут прошел?

Да и если знаете, где можно убрать проверку в кохане для урлов?

Нужно именно полное совпадение ?
Можно использовать просто

Route::set('mail', 'mail/<id>', array('id' => '[0-9]+'))

а внутри контроллера уже работать с $_GET['code']
Насчет проверки урлов — не понял. Это вы про что ?

Извините, затупил.
Действительно: $code = Arr::get($_GET, ‘code’, ‘error’);

А что очерёдность Route имеет такое значение или это я чево та не так сделал? Когда Route админа расположен сверху над Route articles всё работает нормально когда наоборот — не выводит страницу админа а подставляет слово
«админ» вместо статьи — Статья admin.

Конечно очередность имеет значение. Но только в том случае если один роут является частным случаем другого. Например, тот же default подходит абсолютно под все варианты адреса. Поэтому он должен быть всегда в самом низу и выполняться, когда все вариации исчерпаны.

Ну а в моем случае роут админа и статьи вроде не связаны в чём может быть ошибка?

ну значит связаны

Подскажите,
для удобства меню создал как виджетом.
Прописал роут:
Route::set(‘widgets’, ‘widgets(/(/(/)))’)
->defaults(array(
‘directory’ => ‘widgets’,
‘action’ => ‘index’,
));
Уже в контроллере получаю содержание виджета через ->execute
Беда в том что если прописать widgets/controller/action
В браузер выдаст шаблон виджета и только.
А этого понятно допускать не надо, как запретить, присечь подобное дело?

Написать проверку и сделать, например, редирект.

if($this->request->is_initial())
			Request::initial()->redirect(URL::site(''));

Вообще здесь
http://kohanaframework.su/advanced/request_within_request
про это написано. Надеюсь виджет — это у вас не только шаблон, а связка контроллер-вид или модель-контроллер-вид.

спасибо, какрас до следующего урока и не дошел.
Именно контроллер-модель-вид. А как же можно по другому=)

Оказывается можно. «Спецы» из школы программистов зачем-то организуют в виде виджета вызов представления, вместо того, чтобы просто написать
echo View::factory(‘reg_form’);

При запросе http://kohana/article1.html получаю следующее сообщение:
Unable to find a route to match the URI: article1.html

Роут:
Route::set(‘static’, ‘.html’, array(‘path’ => ‘[a-zA-Z0-9_/]+’,))
->defaults(array(
‘controller’ => ‘static’,
‘action’ => ‘index’,
));

Контроллер:
class Controller_Static extends Controller_Common {
public function action_index()
{
echo $this->request->param(‘path’);
}
}

Не пойму в чем дело…

Я не вижу у вас

<path>

в роуте. Наверное в комментах срезало. Напишите код на форуме или здесь, но засуньте в теги pre.

А как быть, если я хочу ссылку вида http://kohana.ru/about.php?id=5 ?

Пишу:

Route::set(‘static’, ‘.php(?id=)’, array(‘action’ => ‘about|contacts’))
->defaults(array(
‘controller’ => ‘static’,
));

Не выходит.

Route::set(‘static’,'&ltaction&gt(?id=&ltid&gt)…

Да чтож такое. Надеюсь Вы поняли, что я хотел написать..

P.S. может стоит htmlspecialchars() использовать вместо strip_tags() ?

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

А. Вон выше и было. konkere интересовался. И еще где-то писал про это, кажется на форуме.

как реалезовать 404 ошибку по умолчанию?



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

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