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

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

В этом уроке мы рассмотрим до конца основные возможности роутинга в Кохане. Ну а если вдруг что-то пропустим, изучим уже по мере надобности в последующих уроках.
В настройках роута, помимо указания в массиве таких параметров, как 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 коммент.

У меня возникла вот такая проблема. Я решил разбить контроллер на директории и на поддиректории :

application
|-controller
|—admin
|—main
|—-main.php
|—user
|—main
|—-main.php
|—-ajax
|——ajax.php

|—cabinet
|—auth

В других каталогах так же

Как мне сделать роуты ?
Дело в том что я хочу что бы работал запрос site.ru/cabinet/main/ или
site.ru/cabinet/ajax/ajax

т.е. По дефолту должен быть каталог user/ + тот который указывается в строке….
делаю так :

Route::set('default', '((user/)((/(/(/))))')

Но так не работает…подскажите как правильно составить роуты

Если вы хотите использовать директории, делайте также как с директорией admin. Указывайте в роуте параметр

'directory'  => 'название директории',

Нет, вы немного не поняли меня.
|+user
|++main
|+++main_welcome.php
|+++ajax
|++++main_ajax_welcome.php

Так вот мне надо что бы по запросу

site.ru/main/ajax/main_ajax_welcome

вызывался контроллер user/main/ajax/main_ajax_welcome

А по запросу site.ru/main/main_welcome
site.ru/user/main/main_welcome

Т.е.
Я хочу что бы дефолтным началом каталогов был user что бы его не указывать в uri

Что то вроде этого

Rout::set(‘default’,'//’)
->default(
array(
‘directory’ => ‘user/ + ‘ <—Но увы так писать нельзя =(((
)
)
Такая конструкция невозможна….а очень хотелось бы… чувствую придётся расширять кохановский класс

Rout::set(default,'%directory%/%controller%/%action%’)
-&gt;default(
array(
‘directory’ =&gt; ‘user/ + %directory%‘ &lt;—Но увы так писать нельзя =(((
)
)

Тег pre не пашеть. Заменил < на %

Можно два роута написать. Если в адресе есть слово ajax — вызывать первый, с директорией, иначе второй. Главное первый выше поставить.

pre работает. добавляйте lang=»php»

Так в том то и проблема….как написать роут =).

Вот смотрите
site.ru/user/main/users/getUsers
site.ru/user/main/ajax/users/getAjaxUsers

Вот смотрите, тут user/main/ и user/main/ajax это директории тобишь далее users это контроллер и getUsers а так же getAjaxUsers — это action

site.ru/user/form/forms/getForms
здесь user/form — это директория

Но эти запросы слишком длинные, да и дело даже не в длине, мне просто напросто не нужна в урл директория user… а без неё ничего не пашет, я хочу что бы когда был запрос site.ru/main/users/getUsers

кохана автоматически ставила перед /main директорию user и использовала её… но такой роут я не смог написать

На счёт двух роутов вы правы, я так и делал, но дело в самих роутах, как их сделать правильно ??

hi, big friend. Попытался закэшировать (if ( ! Route::cache())
* {
* // Set routes here
* Route::cache(TRUE);
* })
Выдает ошибку в коде. Я как понимаю надо раскомментировать.

Да, надо раскомментировать конечно.

Дефолтный роут такой:

 Route::set('default', '((/(/)))')
	->defaults(array(
		'controller' => 'page',
		'action'     => 'index',
        ));

Остальные роуты прописаны выше.
Если в адресную строку ввожу прописанные правила — то все работает, если ввести через слэш какую-нибудь ерунду, например kohana/adm/amd, то выдает ошибку:
The requested URL adm/amd was not found on this server.
Подскажите, как роутами отловить некорректные адреса и направить их на одну страницу?

‘(<controller>(/&ltaction>(/&ltid>)))’

Здравствуйте, Денис! Немного не понял на счет суффикса html.

У нас метода action_index в Контроллере static нет, но вы можете создать его, прописав внутри что-то вроде:
echo $this->request->param(‘path’);

Куда внутри прописать и что вообще даст вывод параметра ‘path’ при загрузке метода action_index. Я попробовал сделать так: прописал

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

создал action_index:
public function action_index()
{
header(«Location: «.URL::base().$this->request->param(‘path’));
}
Но тут дело в том, что при перенаправлении должен сработать роутер articles для определения id статьи, а он, соответственно, уже пропускается, т.к. уже был выбран другой роутер static. Можете разъяснить данную ситуацию?

echo $this->request->param(‘path’); — это просто для примера.
Там же написано

и тогда уже по адресу http://kohana/article1.html вы получите свой article1.

Т.е. echo как раз и выводит часть урл. А дальше мы уже с ним делаем, что хотим, из базы достаем статью, например.
А вот ваш редирект не понял, зачем он.

А если url будет http://kohana/article/article1.html, тогда в path уже article/article1 будет.

В принципе можно строку article/article1 обработать. Обрезать article/ и останется article1. А может есть ещё варианты поизящнее?

Да, но можно так настроить регулярку, чтобы он брал последний сегмент, отделяя его за счет слеша. Я на своих сайтах собственно так и делаю. А перед этим в адресе может быть сколько угодно подразделов.

У меня такой роут на сайте.

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

и адреса вида
http://kohana/computers/macbook.html
или даже
http://kohana/hard/computers/macbook.html
или тот же
http://kohana/macbook.html
работает все три варианта.

Спасибо за ответ, Денис! Отличный материал! Как говорится «дай бог тебе здоровья!» -))

создал папку в controllers, назвал ее widgets, создал там контроллер и прописал роут

Route::set(‘widgets’, ‘widgets((/(/)))’)
->defaults(array(
‘directory’=>’widgets’,
‘controller’ => ‘menu’,
‘action’ => ‘index’,
));

помогите кто нить плиз

Осталось понять, в чем вопрос.

сорри) забыл суть вопроса написать))

Kohana_HTTP_Exception [ 404 ]: The requested URL widgets was not found on this server.

все написано вроде бы правильно, раз седьмой уже переписываю

да и не в этом этом дело, тот же самый простой хеллоу ворлд не работает если контроллер запихнуть в папку и прописать к нему роут

Посмотри как у тебя контроллер прописан. Если ты перенес Controller_Welcome в другую папку, то имя должно быть таким: Controller_Имя папки_Welcome

Никак не могу совладать с описанием роута для адреса вида:

/game/details.php?id=XX

Нужно прописать данную схему для обратной совместимости со ссылками от старой версии сайта.

Может кто подскажет?
Мне всего лишь ID нужен при обращении по такому урл.

А зачем тут роут. Добавляйте ?id=XX к адресу как обычно, кто вам мешает ?

Так у меня по прямому такому пути нет ничего, даже файла.
Т.е. как мне направить пользователя при запросе /game/details.php?id=XX в нужный контроллер используя роуты?

Выскакивает всё время ошибка на любые вариации правила роутинга для этого адреса
Unable to find a route to match the URI: game/details.php

Что-то вроде

Route::set('game', 'game/details.php')  
        ->defaults(array(
            'controller' => 'game',    
            'action' => 'index',  
        ));

и создать контроллер Controller_Game и в нем метод action_index.

Фу ты блин. Точно! Вот у меня мозг заклинило =)
Всего лишь без параметров нужно было описать.
Вот спасибо, Денис.
Контроллер уже есть такой, а в before стоит обработка других случаев неправильного обращения к контровллеру Game.

Выходит, выцепить из /game/details.php?id=68 методом $this->request->param(‘id’) не получится.

Никаких стандартных Кохановских вариантов получения параметра запроса нет, кроме как через $_REQUEST?

Ругается на SYSPATH\classes\Kohana\Request\Client\Internal.php:

Kohana_HTTP_Exception [ 404 ]: The requested URL admin/page/index was not found on this server.

при формировании адресов вида http://kohana/article1.html... Как я правильно понял «Route::set(‘static’, ‘.html’…» необходимо добавить до Routа с default. А вывод сразу добавлять в контроллер static? А обращение к шаблону? Может из-за этого ошибка. И get тоже выдает ту же самую ошибку.

У вас он почему-то ищет в папке admin.



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

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