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

Комментарии: 51  Просмотры: 31 259

Продолжаем изучение Роутинга в Кохане. На прошлом уроке мы создали два роута для наших статичных страниц — страницы контактов и страницы о сайте. Но, как я и говорил, здесь можно обойтись одним роутом. Для этого нам понадобится регулярное выражение. С ним наш роут будет выглядеть так:

Route::set('static', '<action>(/<id>)', array('action' => 'about|contacts'))
        ->defaults(array(
            'controller' => 'static',
    ));

Что мы сделали. Мы добавили третий параметр — массив. В нем значение — это регулярное выражение, а ключ — название параметра, куда попадет часть адреса, соответствующая регулярному выражению. Вертикальная черта в регулярном выражении означает «Или». То есть под данный роут попадут адреса http://kohana/about или http://kohana/contacts, причем в первом случае в action подставится about, а во-втором contacts. Поэтому мы и указываем в массиве для defaults только значение для controller.
Регулярные выражения в роутах дают нам очень широкие возможности. Рассмотрим их на примере блога. Пусть у нас есть какие-то статьи или заметки — articles. И при заходе по адресу http://kohana/articles нам нужно выдавать список всех этих статей. А при заходе по адресу http://kohana/articles/название статьи или http://kohana/articles/номер статьи (зависит от того, как вы решите построить работу с поиском статьи по базе данных, через ид или название, но это сейчас не суть важно) нам нужно выдавать уже конкретную статью. Роут будет выглядеть примерно так:

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

Видно, что роут будет срабатывать только тогда, когда в первом сегменте адреса присутствует слово articles (так как оно вообще без скобок), то есть как раз то, что нам и надо. Также в адресе может присутствовать необязательный параметр id, для которого написано регулярное выражение. В любом случае, есть этот параметр или нет, будет срабатывать Контроллер articles и метод index. Создайте в папке с Контроллерами файл с названием 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');
            $content->article = $id;
        }
        else
            $content = View::factory('/pages/articles');
 
       $this->template->content = $content;
    }
 
} // Articles

Мы видим, что в этом Контроллере есть единственный метод action_index. В первой строке метода мы присваиваем переменной $id значение параметра id. Помните наше регулярное выражение ? Набор символов, совпавший с ним, как раз и попадет в эту переменную (согласно регулярному выражению — это любые символы в количестве от одного и больше). Ну а если таковых символов не имеется, то в переменную попадет NULL. Отсюда собственно и условие. Если переменная не пуста, подгружаем в контент шаблон article и передаем туда эту переменную, а если пуста, то подгружаем в контент шаблон articles.
А шаблоны у нас очень простые (создаем их в папке application/views/pages/).
Шаблон вывода одной статьи article.php:

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

Шаблон для вывода всех статей articles.php:

<strong>Список всех статей</strong>

Теперь, если вы перейдете по адресу http://kohana/articles, то в блоке контента получите текст «Список всех статей» жирным шрифтом. А если перейдете по адресу, например, http://kohana/articles/lesson8, то уже получите текст «Статья lesson8″. Понятное дело, что где-то в Контроллере должно идти обращение к модели, в котором в свою очередь будет идти выборка из базы. Для первого адреса будут выбираться все статьи, для второго — статья, название которой в данном случае будет «lesson8″. Думаю вы обращали внимание, что на блогах (взять даже этот) адреса так и выглядят — http://kohanaframework.su/advanced/route_p1, то есть route_p1 — это как раз и есть название статьи, по которому идет поиск в Базе Данных. Если такой статьи в базе данных нет, то просто выводим сообщение об ошибке примерно как здесь: http://kohanaframework.su/advanced/lesson. А название статьи на английском для поиска по базе вы сами вводите в админке, либо делается конвертация русского названия в транслит (так как русские буквы в адресе выглядят ужасно).
Есть еще такой момент. Нам совершенно необязательно принудительно указывать articles в роуте. Мы можем написать вот так:

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

То есть добавить угловые скобки. Что это нам дало? Представим какой-то игровой блог. На нем игры разбиты по жанрам. Аркады, стратегии, РПГ и так далее. Тогда ссылка на обзор аркадной игры будет выглядеть скорее всего как-то так: http://gameblog.ru/arcade/mario. А на стратегию например так: http://gameblog.ru/strategy/starcraft. Вот роут выше как раз и позволяет нам так писать. Теперь вы можете написать http://kohana/lessons или http://kohana/description/krevedko, все будет работать абсолютно так же, как раньше. Единственное, надо проследить, чтобы этот новый роут стоял под роутом с определением статичных страниц, иначе они не будут работать. На самом деле часть адреса с названием раздела не особо-то и нужна, она сделана больше для красоты и понимания. Ага, адрес http://gameblog.ru/strategy/starcraft, стало быть раздел — Стратегии и игра — Старкрафт. Но попробуйте написать http://gameblog.ru/arcade/starcraft или вообще http://gameblog.ru/strategy123456/starcraft, все скорее всего будет работать. Хотите живой пример ? Вот ссылка с сайта на DLE: http://madeforipad.ru/games/6-infinity-blade-2.html. А если зайти так http://madeforipad.ru/123/456/6-infinity-blade-2.html. Работает :) Но и это еще не все. Оказывается и название «6-infinity-blade-2.html» полностью там и не требуется. Главное, чтобы была цифра — ид статьи, и за ней шел какой-то символ, но уже не цифра. И заканчивалось это все на «.html». Проверьте сами.
На этом сайте тоже адреса вида: http://kohanaframework.su/123/route_p1 работают распрекрасно. Ну а если в адресе статьи нет, а есть только категория, тогда название конечно важно, ведь по нему будет идти поиск в базе.
Кто всего этого не знал, осмысливайте. Кто знает еще что-нибудь интересное или с чем-то несогласен — добро пожаловать в комментарии. Пока все, до новых встреч.

P.S. Да, кстати. После всех наших уроков у вас должно получится что-то такое: Образец.

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


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

Название категории, если что можно получить через
$this->request->param(‘articles’);
Мало ли, кто-то не догадался :)

class Controller_Articles extends Controller_Common {

public function action_index()
{
$id = $this->request->param(‘id’);

$content = View::factory(‘/pages/article’)
-> bind(‘article’, $id);

$this->template->content = $content;
}

}

Так проще и правильнее.

а где тут вывод всех статей ?

Упс, упустил, что вьюшки разные… Но тогда, по моему скромному мнению, вообще надо разделить action на 2 разных. Все-таки, список постов и пост (с комментариями, например) — абсолютно разные вещи.

Ну я просто думал сделать два метода отдельных, для списка статей и для статьи и в action вызывать нужный и возвращать результат. Вообще конечно момент спорный и каждый может делать так, как ему удобнее.

Имхо, существует очень замечательная штука the rails way. И подразумевает она определенный набор соглашений, даже если речь не идет о Ruby on Rails, все равно эти соглашения везде будут только полезны. Думаю kohana не исключение.
Так вот, в соответсвии с the rails way в данном случае должно быть два экшена: один для списка, один для конкретной статьи. Вызывать из экшена другие методы контроллера — считается дурным тоном. Разделение должно осуществлятся по средствам роутинга. Если в kohana такого нет — что ж… Это огромное упущение разработчиков.

Есть ещё такой формат получения переменных:
$login = Arr::get($_POST, ‘login’, »);

$login = Arr::get($_POST, ‘login’, ‘ ‘);

ну да. для получения данных из форм.

Чувствую скоро надо будет форум ставить :)

Не совсем понял, для чего использование третьего параметра с регулярным выражением в роутах? В обоих примерах все работает также и без них, вот так:
Route::set(‘static’,'(/)’)
Route::set(‘articles’,'(/)’)

в комменте обрезало угловые скобки с их содержанием)

в смысле без array(‘action’ => ‘about|contacts’) ?
а теперь любой другой адрес попробуйте )

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

Просто если вы уберете этот массив, то все страницы кроме главной будут попадать на этот роут. А поскольку в контроллере static только два экшна, то на все остальные будет ошибка. Если надо добавить еще одну статическую страницу, просто добавляем еще один экшн в контроллер и его название — в регулярное выражение.

у меня че то не выводит статью по id

HTTP_Exception_404 [ 404 ]: The requested URL article/lesson8 was not found on this server

а по articles отрабатывает нормально

ура заработало! в роуте к id угловые скобки добавил

Без угловых скобок вы так и должны передавать ‘id’ )

Загляните на форум по данной теме пж =))

Талант, инфа the best I’ve ever seen :) , через рекламу СПАСИБО

Как же настроить если у меня десятки однообразных статических страниц, для каждой свой action писать?
Я хочу что бы URL был красивый для всех (site/static) и добавлять через интерфейс, не за лазить каждый раз в код.

Можно написать один роут для таких страниц, где будет регулярка вроде
about|contact|info итд, но натравливать их все на один action. Просто в этом action-е исходя из параметра (about|contact|info итд) делать выборку из базы нужной информации и выводить ее в один постоянный шаблон.

Т.е. будет один роут, один action, но разные страницы.

Ну да, это понятно, за ответ спасибо.

Но опять таки, регулярное выражение при добавлении новой страницы нужно будет каждый раз дописывать, лезть в код.

Разве что из базы прямо в bootstrap грузить данные))

Ну можно прописать для адреса site/static к примеру, чтобы проверяло только первый сегмент — site, а static сделать как параметр и можно тогда не лезть в код, а просто если параметра в базе не окажется, выдавать Такой страницы не существует.

Т.е. если в адресе первый сегмент — site, кидает на соответствующий контроллер и соответствующий action, а дальше уже само разбирается.

Извиняюсь, site это я имел ввиду доменное имя.
То есть этот роут по дефолту уже занят

Спасибо за очередной урок!
На дворе утро, мозговая активность на исходе, пора спать :)

С наилучшими пожеланиями,

На дворе лето. Поэтому уроки сейчас выходят реже. У меня и так один выходной, хочется отдохнуть немножко. Но на этих выходных думаю соберусь- напишу чего-нибудь :)



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

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