11 July 2016

Bitrix — UrlRewrite (feat. Juggernaut)

CMSWebsite developmentPHP1С-Bitrix


Здрасте!

Продолжаем лупить статьи на тему «Битрикс не так уж и плох, если его доработать».
На этот раз разговор пойдет на тему «url_rewrite», потому как я считаю, что текущий вариант вообще не идеален.
А идеальным я считаю вариант маршрутизации в микрофреймворках, например Slim (или тот же Lumen), вообщем тех, которые дружат с PSR-7.
Кому интересно, го под кат.
Кому не интересно, ну тут уж сами решайте ;-)

INTRO


На самом деле мои предыдущие статьи носили более менее абстрактный характер (ну кроме статьи про Juggernaut пожалуй), поэтому в данном посте постараюсь меньше писать теории и побольше кода.

Кстати про Juggernaut


Документация будет в скором времени, к сожалению есть некоторые преграды:
  1. время
  2. рефакторинг
  3. мне полюбился TDD, так что рефакторинг остановился до тех пор пока не напишу тесты
  4. направление развитие библиотеки как оказалось я не совсем еще до конца определил


Но это как говорить «совсем другая история», поэтому вернемся к тому, о чем собственно данная статья: роутинг.

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
Tags:bitrixбитриксроутингurlrewritejuggernaut
Hubs: CMS Website development PHP 1С-Bitrix
-4
14.2k 21
Comments 37