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

Комментарии: 51  Просмотры: 33 543

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

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 коммент.

Извините, такой вопрос, а если мне нужно передать несколько параметров, то что нужно все их заранее прописывать — ‘(/(/(/)))’ или я наверное очень невнимательно читал эту статью:(

В следующий раз используйте пожалуйста тег pre для вывода кода.

Скажите а если мне нужно сделать так чтоб все мои стать были в одном файле и выводились в на экран в зависимости от того какая статья была выбрана в списке статей…да и должна выводится только выбранная статья. Как это можно реализовать? Или каждая статья должна быть отдельным html файлом?

Немного помозговав, пришел к такому выводу. Все таки не хорошо список и конкретную статью выводить через один экшен. Предлагаю такое вариант контроллера
public function action_index()
{

$content = View::factory(‘/pages/articles’);

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

public function action_item()
{
$id = $this->request->param(‘id’);
$content = View::factory(‘/pages/article’);
$content->article = $id;
$this->template->content = $content;
}
Далее в роуте
Route::set(‘articles’, ‘articles/’, array(‘id’ => ‘.+’))
->defaults(array(
‘controller’ => ‘articles’,
‘action’ => ‘item’,
));
Таким образом получаем что параметр id у нас обязателен. Но если id не будет указан (адрес http://kohana/articles), то он подпадает на наш дефолтный роут.

Спасибо. Да, я сейчас именно так и делаю.

Здравствуйте. Спасибо за Ваши уроки. Все понятно и доступно.
Мой вопрос такой:
Сейчас у меня странички about и contacts обрабатываются static контролером. И чтобы попасть на эти странички мне нужно ввести kohana/static/about или kohana/static/contacts (я рассматриваю ситуацию до редактирования меню — ссылки в меню выглядят вот так page/about или page/contacts).

Я хочу в роут передать такое правило:

**********************************
( ‘static’, (controller/action), array (‘controller=> static|page’, action=>’about|contacts’))
**********************************

То есть, чтобы я мог попасть на страницу contacts и по адресу kohana/static/contacts и по адресу kohana/pages/contacts. Но не выходит. Выдает ошибку, что такого урла не существует

Здравствуйте. Спасибо за Ваши уроки. Все понятно и доступно.
Мой вопрос такой:
Сейчас у меня странички about и contacts обрабатываются static контролером. И чтобы попасть на эти странички мне нужно ввести kohana/static/about или kohana/static/contacts (я рассматриваю ситуацию до редактирования меню — ссылки в меню выглядят вот так page/about или page/contacts).

Я хочу в роут передать такое правило:

**********************************

( 'static', (/), array ('controller=> static|page', action=>'about|contacts'))

**********************************

То есть, чтобы я мог попасть на страницу contacts и по адресу kohana/static/contacts и по адресу kohana/pages/contacts. Но не выходит. Выдает ошибку, что такого урла не существует

Так:
‘controller=> static|page’
Не стоит писать. Не будете же вы создавать два одинаковых контроллера.

У вас будет что-то вроде

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

Здравствуйте, у меня такая ситуация: есть абоненты, у каждого абонента есть определенное количество телефонных линий. Подскажите какой написать роут чтобы по URL «mysite.ru/lines/» я попадал на список линий компании, по URL «mysite.ru/lines» на список всех линий всех компаний а по «mysite.ru/lines/» в настройки конкретной линии.

Конкретизируя вопрос — как это сделать одним роутом.

Простите, оформляя URLы не учел что угловые скобки сделаются тегами) Исправляю:
для списка всех линий всех компаний: mysite.ru/lines/
для списка все линий компании: musite.ru/lines/company_name
для отображения настроек конкретной линии: mysite.ru/lines/line_id

Решение найдено) Ответ нашел в статье. Спасибо

Интересует как именно попадает значение в переменную id, хотелось бы поподробней

Здравствуйте, Денис. Спасибо Вам за Ваш труд. У меня вопрос как и у предыдущего комментатора. Расскажите поподробней про этот id или где про него узнать. У меня не получается сделать ссылку на конкретную статью, из вашего описания не вполне понятно.

Ну если брать пример из урока:

Route::set('articles', 'articles(/<id>)', array('id' => '.+'))

здесь id обрамлен скобками <>, поэтому в него попадают данные, соответстующие регулярному выражению .+, то есть все, что находится в адресной строке после домен/articles/.

Или вам нужно рассказать, как это происходит внутри Коханы ?

Как внутри Коханы происходит думаю не надо пока, знаний маловато. Мне надо было разобраться, как сделать ссылку на конкретную статью. Думал, надо делать на каждую ссылку новый файл с номером. Почитав внимательнее этот пост, все-таки разобрался, что работает только один файл article, а номер статьи передается параметром, который затем и выводится. Спасибо

Да, именно так. Вы этот параметр можете потом в контроллере articles получить.

Route поддерживает регулятрные выражения POSIX или PCRE?

>> …то в переменную попадет NULL. Отсюда собственно и условие. Если переменная не пуста…
так что же туда попадает?
и не правильнее if ( ! is_null($id)) {…} — если NULL,
или if ( ! empty($id)) {…} — если она пустая?

Здравствуйте уважаемый автор! Спасибо за этот труд. На самом деле все описано на простом языке и все легко изучается и понимается! После всех пройденных уроков у меня получилось практически тоже самое что представлено у вас в образце (исключение — плюшки вроде каптчи, пагинации). Единственный момент, main.css предложенный вами в одной из статей немного отличается от того, что находится в образце. Это конечно мелочи, но все же я думаю вы учтете)



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

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