Здрасте!
Продолжаем лупить статьи на тему «Битрикс не так уж и плох, если его доработать».
На этот раз разговор пойдет на тему «url_rewrite», потому как я считаю, что текущий вариант вообще не идеален.
А идеальным я считаю вариант маршрутизации в микрофреймворках, например Slim (или тот же Lumen), вообщем тех, которые дружат с PSR-7.
Кому интересно, го под кат.
Кому не интересно, ну тут уж сами решайте ;-)
INTRO
На самом деле мои предыдущие статьи носили более менее абстрактный характер (ну кроме статьи про Juggernaut пожалуй), поэтому в данном посте постараюсь меньше писать теории и побольше кода.
Кстати про Juggernaut
Документация будет в скором времени, к сожалению есть некоторые преграды:
- время
- рефакторинг
- мне полюбился TDD, так что рефакторинг остановился до тех пор пока не напишу тесты
- направление развитие библиотеки как оказалось я не совсем еще до конца определил
Но это как говорить «совсем другая история», поэтому вернемся к тому, о чем собственно данная статья: роутинг.
UrlRewrite by Bitrix
Порядок маршрутизации я думаю лучше изобразить схемкой (и понятно, и наглядно):
Что это все значит:
include bitrix/urlRewrite.php
Подключаем файл который занимается маршрутизацией (ну это я думаю и так все поняли).
Вообще данный пункт (и все что выше на блок схеме) — это заслуги .htaccess:
RewriteCond %{REQUEST_FILENAME} !-f # не файл
RewriteCond %{REQUEST_FILENAME} !-l # не символьная ссылка
RewriteCond %{REQUEST_FILENAME} !-d # не директория
RewriteCond %{REQUEST_FILENAME} !/bitrix/urlrewrite.php$ # не файл маршрутизации
RewriteRule ^(.*)$ /bitrix/urlrewrite.php [L]
fix request_uri for IIS
Данный пункт, судя по комменту в коде, ответственен за какие то косяки IIS (бедняга MS), за какие я не в курсе, но логика следующая:
если QUERY_STRING имеет вид «wtf=404;http(s)://wtf.ru», то все GET параметры запроса чистятся и данная конструкция убирается из адреса.
На вопрос «что проиходит?» я не могу дать ответа, так что едем дальше.
include dbconn.php
Подключаем базу.
Зачем? Непонятно, т. к. запросов к базе дальше нет и работа идет только с файловой системой.
Я конечно не опускался в реализацию классов для работы с файлами, но если им нужно что-либо от базы, то это не иначе как печально :-(
decode request page (for UTF-8)
Все понятно из названия, кодирование REQUEST_URI.
Зачем? Зачем Битрикс любит Windows-1251? Без понятия. Но это будет продолжаться вечно (и это инсайдерская информация).
include /urlRewrite.php
Собственно подключаем сами правила маршрутизации.
process Url
Немного странные действия, но все же происходит следующее:
Если есть GET параметр SEF_APPLICATION_CUR_PAGE_URL, то приравниваем REQUEST_URI к его значению, а затем переписываем все зависимые переменные и глобальные массивы ($_GET, $_SERVER, …)
process urlRewrite
О, да!
Мы до него добрались.
Собственно что происходит:
- Парсим параметр CONDITION.
- Заменяем параметр CONDITION на RULE в REQUEST_URI
- Добавляет в $_GET и $_REQUEST переменные из правила маршрутизации.
- Проверяем существует ли указанный файл, валидный ли у него путь и не является ли он административным (upload, bitrix, bitrix/services, bitrix/groupdavphp).
- Если все ок, то подключаем.
Меня одного смущает что проверка идет после того как мы уже сунули все параметры в глобальные переменные?
Много неясностей, зачем сделано так, а не иначе?
Ну и много неясностей, зачем вообще это сделано?
Так что теперь перейдем к идеальному варианту Slim’a.
UrlRewrite by Slim
Как делает этот замечательный фреймворк:
$app = new \Slim\App();
$app->get('catalog/{sectionCode}/{elementCode}/', function(Request $request, Response $response) {
// code
});
$app->post('catalog/{sectionCode}/{elementCode}/', function(Request $request, Response $response) {
// code
});
$app->put('catalog/{sectionCode}/{elementCode}/', function(Request $request, Response $response) {
// code
});
$app->delete('catalog/{sectionCode}/{elementCode}/', function(Request $request, Response $response) {
// code
});
$app->run();
Легко и непринужденно цепляемся к нужному действию, с нужным маршрутом, параметрами и реализацией.
UrlRewrite by Juhhernaut
Ну, а теперь пробуем все это миксануть.
Выкидываем из Slim'a указание метода и собственно реализацию действия, вместо нее будет путь до файла.
Для начала обозначим синтаксис привязки маршрутов к реальным физически файлам (по факту это является мануалом использования):
/*
* подключаем файлы для роутрера
*/
include_once __DIR__.'/modules/olof.juggernaut/includeRewrite.php';
use Jugger\Context\Router;
/**
* создаем роутер
* в отличии от Slim'a маршруты не добавляются, а выполняются
* таким образом как только маршрут найден,
* остальной код не будет выполняться
*/
$r = new Router();
/*
* поиск файла с комнца маршрута
* например, URL запроса выглядит так: "/catalog/section1/section2/element1/",
* То поиск поочередно будет перебирать директории в поисках файла 'index.php':
* - /catalog/section1/section2/element1/index.php
* - /catalog/section1/section2/index.php
* - /catalog/section1/index.php
* - /catalog/index.php
*
* в корень сайта опускаться поиск не будет
* также никакие параметры не будут добавлены в переменные GET и REQUEST,
* т.к. нет шаблона маршрута
* данный способ хорошо подходит для стандартной ситуации Битрикс
* когда маршрутизация ложится на плечи компонентов
*/
$r->runRecursive();
/*
* добавляем маршрут
* формат записи:
* {nameParam},
* {nameParam:regExp}
* где 'regExp' - регулярное выражение. Например, '\d+' или '[0-9]+'
*/
$r->run(
"/page/",
"/page/index1.php"
);
$r->run(
"/page/{p1:[0-9]+}/{p2}",
"/page/index2.php"
);
$r->run(
"/catalog/",
"/catalog/index1.php"
);
/*
* добавляем сразу несколько маршрутов
*/
$r->run(
[
"/catalog/{sectionCode}/",
"/catalog/{sectionCode}/{elementId:\d+}/",
],
"/catalog/index2.php"
);
/*
* маршрутизация в один файл с параметром ?r=path/to/file
*/
$r->run("{r:.+}", "index.php");
/*
* окончание роутига
* если никакой маршрут не подошел
* то подключается /bitrix/urlrewrite.php
*/
$r->end();
По факту, если реализацию маршрутов оставить на совести компонентов, то достаточно будет прописать следующую конструкцию (да, так тоже можно ;-) ):
(new Router())
->runRecursive()
->end();
Данный файл нужно (можно) назвать urlrewrite.php, кинуть его в папку /local/ и внести правки в .htaccess файл, который лежит в корне.
Вместо:
RewriteCond %{REQUEST_FILENAME} !/bitrix/urlrewrite.php$
RewriteRule ^(.*)$ /bitrix/urlrewrite.php [L]
Нужно прописать:
RewriteCond %{REQUEST_FILENAME} !/local/urlrewrite.php$
RewriteRule ^(.*)$ /local/urlrewrite.php [L]
И собственно все. Простой и понятный роутинг у вас в кармане.
Ссылки:
Juggernaut: github.com/irpsv/juggernaut.bitrix
Реализация роутера: github.com/irpsv/juggernaut.bitrix/blob/master/olof.juggernaut/lib/Context/Router.php