Страницы

Поиск по вопросам

пятница, 24 января 2020 г.

Как организовать быстрый Reverse Routing?

#php


Есть такой роутинг

'/' => ['site', 'index'],
'/[s:action]' => ['site', '{action}'],
'/[s:controller]/[s:action]' => ['{controller}', '{action}'],
'/[s:module]/[s:controller]/[i:id]' => [ '{controller}', 'view', '{module}'], //$id
- параметр передаётся в action
'/[s:module]/[s:controller]/[s:action]/[i:id]' => ['{controller}', '{action}', '{module}'],
//$id - параметр передаётся в action


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

Допустим нужно сформировать ссылки для примера:

 '/' => '/',
 'site/index' => '/',
 'site/login' => '/login',
 'user/info' => '/user/info'
 'user/profile/view/123' => '/user/profile/123',
 'user/profile/edit/123' => '/user/profile/edit/123',


примеры

Допустим мы вводим URL / и попадаем на контроллер site экнен index, теперь на основе
этого же правила нужно сделать обратное правила для redirect/rewriterule/reverseroute/alias
как еще назвать не знаю. 
То есть нужно чтоб при вводе URL /site/index мы попадали на /

Допустим мы вводим URL /user/profile/123 попадаем в модуль user на контроллер profile
экнен view с параметром id=123, 
Аналогично из правил роутинга нужно чтоб при вводе URL /user/profile/view/123 нас
редиректило на /user/profile/123

И т.д. По правилам роутинга описанным выше

Попробую еще раз


Пользователь вводит URL /
Роутинг срабатывает на первом правиле('/' => ['site', 'index']), и вызывается SiteController::index()
Всё отлично и хорошо.
Возможна другая ситуация, пользователь вводит URL site/index
Роутинг срабатывает на третьем правиле('/[s:controller]/[s:action]' => ['{controller}',
'{action}']), и также вызывает SiteController::index()
Потом приходит СЕОшник, и говорит, а почему у нас два URL отдают один и тот же контент,
это не комильфо. Сделай переадресацию на основную страницу, тоесть на /, и так для
всех правил описанных в роутинге.
Задаю вопрос на StackOverflow, как это сделать имея правила роутинга описанные выше. 
'/' => ['site', 'index'] ====> '/site/index' => '/'


Немного про формат роутинга на всякий случай

Ключ - это условие по которому обрабатывается URL


s: - string
i: - integer


Значение - это массив состоящий из 


controller
action 
module


В явной форме или в виде {placeholder}, который берётся из URL по маске в ключе
    


Ответы

Ответ 1



То есть перечитав я усёк - у тебя несколько роутов ведут на один и тот же MCA (module controller action). Ты же хочешь, чтобы всегда оставалось только одно соответсвие URL <=> MCA - например чтобы редиректило, или выдавало 404. Добавлю ещё одно определение - роут, это шаблон(может быть строкой, массивом, коллбеком, и вообще чем угодно), по которому определённые URL адреса можно распарсить в MCA + массив параметров. Делается так - роутам добавляется параметр priority , или он может по умолчанию высчитываться от строковой длинны роута, например. Далее после этапа бутстрапа приложения - отсортируй роуты по priority. Предположим что для роутера ты завёл класс SomeRouter. Этот класс должен иметь как минимум два метода: parse (собрать MCA из URL-строки, может вернуть false - если URL не подходит ни единому роуту) и stringify (собрать MCA+прочие параметры в URL-строку). Этот класс содержит роуты (список, который в вопросе под фразой "Есть такой роутинг") Так вот при парсинге роута должен быть код, суть которого примерно: $requestMCA = SomeRouter::parse($URL); if (($goodURL = SomeRouter::stringify($requestMCA))!=$URL){ return redirect($goodURL); } Главная суть этого - как парсинг URL, так и сброрка URL - должны работать согласно предсказуемым приоритетам роутов : по приоретам работают циклы сбора/разбора внутри SomeRouter. При первом хите цикл сборки/разборки прерывается и возвращается результат. UPD: Обычно более конкретные роуты имеют более высокий приоритет, а менее конкретные - более низкий приоритет. Например роут / - наивысший приоритет, а роут /[s:module]/[s:controller]/[s:action]/* - низший приоритет.

Комментариев нет:

Отправить комментарий