Здрасте!
Продолжаем лупить статьи на тему «Битрикс не так уж и плох, если его доработать».
На этот раз разговор пойдет на тему «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
Комментарии (37)
AlexLeonov
11.07.2016 11:19+1Что только не делают битриксоиды, лишь бы не писать нормальный код.
Роутер — одна из самых простых частей приложения, особенно в парадигме MVC: подай на вход Request, на выходе получи Route, как некий внутренний путь по приложению, и решай, что с этим путем делать. Ну ОК, еще обработай исключение «Соответствие не найдено», превратив его в ответ 404.
Чтобы не заморачиваться, создай конфиг роутинга в виде массива, где ключами будут шаблоны, на соответствие которым проверяется Request, а значениями — функции, которые получат этот Request, группы совпавшие в шаблоне, замкнут на себя контекст и вернут Route.
Всё!
Что все эти люди делают с этой простейшей концепцией? Зачем? Ради чего вы вообще пишете вот такой код?maxpsyhos
11.07.2016 11:40+1В Битриксе UrlRewrite — это статичный конфиг, в котором кроме копания ручками ещё автоматически вносятся роуты от виджетов, поэтому никаких функций там нет, при его архитектуре они там не нужны.
AlexLeonov
11.07.2016 11:54Вы сейчас прослушали миниатюру «Битрикс: нам не нужно нормально программировать, потому что у нас такая вот архитектура»
maxpsyhos
11.07.2016 12:16-2Вы сейчас прослушали миниатюру «Есть только MVC и PSR пророк его, всё остальное от лукавого».
AlexLeonov
11.07.2016 12:25-2MVC — нет, конечно. Архитектур много, все они разные. Нет ничего плохого в чем-то, что не вписывается в прокрустово ложе MVC.
PSR — да. Если вы не уважаете стандарты, принятые сообществом — вон из профессии.Delphinum
11.07.2016 12:33-2А при чем тут уважение стандарта и его использование? И что еще за «принятие сообществом» такое? Где то было совещание PHP разработчиков, на котором подписали договор о безоговорочном следовании PSR всеми участниками сообщества, иначи им запрещается использовать в своей работе данный ЯП?
AlexLeonov
11.07.2016 12:38Где то было совещание PHP разработчиков
Да, конечно.
Вот например: http://www.php-fig.org/psr/psr-4/meta/#6-votes
Если вы не считаете этих людей авторитетами для себя, у меня для вас плохие новости — вы за бортом современного PHP.Delphinum
11.07.2016 12:42А где там речь об исключение из профессии тех, кто не придерживается PSR?
Если вы не считаете этих людей авторитетами для себя
При чем здесь то, кем я для себя считаю этих людей? Не надо подменять понятия.
вы за бортом современного PHP
Какой ужас, модное, современное, молодежное проходит мимо меня!AlexLeonov
11.07.2016 12:44Зря иронизируете. Отстать очень легко.
Delphinum
11.07.2016 12:47-2Я не боюсь отстать, я боюсь убить свое время на нечто переходное. PSR это хорошо, но не нужно быть таким категоричным, это же всего лишь стандарт.
rpsv
11.07.2016 12:36Потому что в Битриксе нет единой точки входа, и поэтому роутер не всегда подключается, а только когда обращение идет не к существующему файлу.
А в чем сложность собственно? Алгоритм:
1. Получили URI.
2. Привели соответствие с шаблонами.
3. Подключили нужный файл, либо 404 выплюнули.
По поводу конфига: да, вероятно вы правы, стоит добавить возможность добавить массово конфиг.
А теперь по поводу кода: чем он вам не по нраву?AlexLeonov
11.07.2016 12:41Он не семантичен. Что такое run()? Зачем нужен end()?
Не проще ли:
try { $request = ...; $route = (new Router( new Config(ROUTE_CONFIG_PATH) ))->processRequest($request); }
rpsv
11.07.2016 12:46run — проверка шаблона на соответствие (если приятней глазу читайте как process).
По сути весь этот велосипед строился ради runRecursive.
end — кидает на Битриксовый обработчик, если в текущем нет нужных правил, т.к. данный роутер вспомогательный, стандартные компоненты вряд ли будут ему следовать.
Request в вашем примере, в данному случае это URI, по нему идет маршрутизация, другие данные не нужны.Delphinum
11.07.2016 12:48А битрикс не различает GET, POST, PUT, DELETE?
rpsv
11.07.2016 12:58Маршрутизация основана только на URI, методы в счет не идут. Остальной обработкой занимаются либо сами страницы, либо компоненты в них подключенные.
В Битрикс нет «стандартного» MVC (контроллер, модель, представление). После роутинга, подключается страница, а не действие контроллера.Delphinum
11.07.2016 13:00Тобишь внутри страницы еще один роутер? А почему тогда это не реализовать на уровне веб-сервера?
rpsv
11.07.2016 13:09Чтобы правила были доступны из PHP, для той же генерации ссылок по шаблону.
Битрикс также позволяет генерировать шаблоны маршрутизации из админки, сохраняются они соответственно в PHP.
Как по мне, писать напрямую правила маршрутизации в htaccess — не круто.
Delphinum
11.07.2016 11:53А что мешало взять любой готовый пакет для роутинга и подключить его?
мне полюбился TDD, так что рефакторинг остановился до тех пор пока не напишу тесты
Тесты это круто, конечно, но чуствую я, «эра» Juggernaut начинает подходить к концу.rpsv
11.07.2016 12:41А что мешало взять любой готовый пакет для роутинга и подключить его?
Прокачка скилла. (А вообще FastRoute хорош).
Тесты это круто, конечно, но чуствую я, «эра» Juggernaut начинает подходить к концу.
Спасибо за веру)))Delphinum
11.07.2016 12:45Вы решили писать «замену» битрикса с целью прокачки скилла?
rpsv
11.07.2016 12:55Атата! Не меняйте смысл слов, Вы спросили про роутинг, а не Juggernaut)))
На самом деле роутер писался глядя в код FastRoute, а не использовал я его из-за неполного понимая open-source лицензий.
А по поводу прокачки скилла: juggernaut в некоторых местах рефакторит битрикс, но в некоторых что-то привносит свое. Он создан для удобства, если только для моего, то так тому и быть, меньше париться с документацией)Delphinum
11.07.2016 13:01Ну вы же предлагаете использовать данный роутер в Juggernaut?
rpsv
11.07.2016 13:07Не в таком виде.
В juggernaut я планирую сделать «нормальную» точку входа, чтобы можно было маршрутизировать в формате «контролер / действие».
Собственно сделать единственный кофинг для роутера, с возможностью последующей генерации ссылок по шаблону.
M-A-XG
11.07.2016 12:28>include /urlRewrite.php
Там же вроде не camelCase…
>include dbconn.php
Там вроде не только база, а и другие настройки…
Ваш роутер подтягивает битриксовские правила роутинга?
>Что все эти люди делают с этой простейшей концепцией? Зачем? Ради чего вы вообще пишете вот такой код?
А я вообще не пишу код роутинга, он в нгинксе. :)rpsv
11.07.2016 13:02Там же вроде не camelCase…
В статье: что-то вроде псевдокода
Там вроде не только база, а и другие настройки…
И опять вроде))) В основном там база, да и из названия это следует. Помимо базы также присутствуют константы кеша и еще парочку непонятных/неизвестных мне. Но в любом случае это не должно подключаться до роутинга, с учетом того, что данные константы вряд ли там используются (не факт)
Ваш роутер подтягивает битриксовские правила роутинга?
Если в роутере не сработало ни одно из правил, то далее уже подключается стандартный роутингM-A-XG
12.07.2016 10:19>И опять вроде)))
Я с Битриксом 2 года не работаю уже, поэтому могу ошибаться, поэтому вроде. :)
>В основном там база.
Вчера искал исходник с работы по Битриксу, ради интереса залез в дбконн, там много всего, короме базы. Для базы вроде только адресс сервера, логин, пароль, база.
>да и из названия это следует
Название неочевидное… :)
>это не должно подключаться до роутинга
http://dev.1c-bitrix.ru/api_help/main/general/pageplan.php
>Если в роутере не сработало ни одно из правил, то далее уже подключается стандартный роутинг
А в конфиг вашего роутинга пишутся параметры с вызуального редактирования параметров комплексного компонента?
rpsv
12.07.2016 12:33http://dev.1c-bitrix.ru/api_help/main/general/pageplan.php
Знаю такую страницу, только не понимаю к чему это?
А в конфиг вашего роутинга пишутся параметры с вызуального редактирования параметров комплексного компонента?
Нет они пишутся в файл '/urlrewrite.php' (не путать с 'bitrix/urlrewrite.php' который отвечает за маршрутизацию), не вижу смысла подключать его, если в дальнейшем (если нет подходящих правил) все равно маршрутизацией будет заниматься битирксовый роутерM-A-XG
12.07.2016 13:51>Знаю такую страницу, только не понимаю к чему это?
Почему это все подключается…
В том файле не только БД ну и остальное.
>Нет они пишутся в файл '/urlrewrite.php' (не путать с 'bitrix/urlrewrite.php' который отвечает за маршрутизацию), не вижу смысла подключать его, если в дальнейшем (если нет подходящих правил) все равно маршрутизацией будет заниматься битирксовый роутер
Боже, роуты пишутся вручную или с редактора параметров компонента?rpsv
13.07.2016 08:58Почему это все подключается… В том файле не только БД ну и остальное.
Вообще нет. В том файле определяются только константы, а страница грузиться начинает после подключения /bitrix/header.php или файла пролога (собственно после маршрутизации).
Боже, роуты пишутся вручную или с редактора параметров компонента?
Вы сначала мозги включите, а потом божечку вспоминайте. У Битрикса свой формат роутинга (маршрутов, подстановки параметров, ...), и опять напишу, что не вижу смысла писать, потому как затем подключается битриксовый роутер, а в данный маршрутизации писать нужно ручкамиM-A-XG
13.07.2016 11:04Так /bitrix/header.php и подключает их все… :)
Я знаю, что у битрикса свой формат.
Я спрашиваю, пишете ли вы в свой файл. :)
kazmenko
12.07.2016 23:40+1Битрикс ужасен… И ужасен во всем за исключением того что делает его битриксом (сертификация ФСТЭК и прочие необходимые пряники). Чем меньше в сайте битрикса тем лучше для сайта… Тем лучше для его овнера… Тем лучше для сапорта и криэйтеров проекта… А это «чем меньше» достигается связкой Silex/Slim/Lumen плюс API Bitrix плюс любимый JS+CSS фреймворк. Да это похоже на «мерседес» замаскированный под костыли… Но многолетний опыт разработки на этой «платформе» порой приводит к таким вот странным решениям…
oxidmod
>> Зачем? Зачем Битрикс любит Windows-1251? Без понятия. Но это будет продолжаться вечно (и это инсайдерская информация).
шел 2016 год… просто слов нет.
почему люди этим пользуются? неужели у них не бывает клиентов скажем из Германии? или из того же Китая?
rpsv
Есть возможность ставить Битрикс под UTF-8, но это не основная кодировка, по-умолчанию 1251.
А по поводу клиентов: вряд ли)))
Скорее всего из СНГ только, да и то все равно 1251 не спасет.