Наверх

Собственная маршрутизация в MODX

В разделе «Репосты» расположены чужие статьи, которые мне понравились или показались полезными.

Есть очень частый вопрос «а как вывести то-то по такой-то ссылке?». И речь здесь не о заморозке uri, а о собственном маршруте нахождения страницы по указанному адресу, типа такого. То есть, речь идёт о маршрутизации, или, в народе — роутинге.

MODX отлично работает с дружественными url и представляет кучу настроек для их функционирования, а там, где настроек не хватает, он даёт нам замечательный инструмент для описания собственной логики — системные плагины по событию OnPageNotFound.

Как следует из названия, событие это возникает, когда MODX не смог найти страницу по запрошенному адресу, и в этот момент мы можем перехватить запрос и вывести что-то своё. Если же мы ничего не перехватываем, то выводится 404 not found.

Теория

За обработку запроса от пользователя отвечает класс modrequest.class.php, в котором запускается метод handleRequest(). Он определяет, каким именно образом запрашивается страница, по id или по alias?

Первый случай нас не интересует, ибо это не friendly urls, а вот во втором вызывается сравнительно новый метод modX::findResource(). Именно он отвечает за сопоставление запрошенного адреса и id страницы.

Если страница найдена, то findResource возвращает её id, MODX получает нужный объект, передаёт в класс ответа
modresponse.class.php и всё хорошо. А вот если же findResource возвращает false, то вызывается метод modX::sendErrorPage().

Именно в этом методе и генерируется событие OnPageNotFound, в которое мы можем вклиниться и подсунуть нужную нам страницу.

Практика

Пишем плагинчик:
<?php
if ($modx->event->name != 'OnPageNotFound') {return false;}

echo '<pre>';
print_r($_REQUEST);
print_r($_SERVER);
die;
Отмечаем для него соответствующее событие, сохраняем и открываем на сайте любой несуществующий адрес, типа site.com/notfoundpage.html.

Вы должны будете увидеть вот такой вывод:


Первый массив содержит запрос пользователя, в котором должен быть ключ, указанный в системной настройке request_param_alias, а второй массив содержит переменные сервера. В принципе, они не особо нужны, но могут пригодиться для отладки.

Грамотно ловим запрошенный юзером адрес:
// Определяем системную переменную friendly urls
$alias = $modx->context->getOption('request_param_alias', 'q');

// Проверяем её наличие в запросе.
// Если не находим, то это фигня какая-то - выходим
if (!isset($_REQUEST[$alias])) {return false;}
// А если есть - работаем дальше
$request = $_REQUEST[$alias];

echo $request;die;

Вот мы и получили запрошенный адрес. Собственно, главный фокус в том, чтобы опираясь на запрошенный адрес вывести нужную нам информацию.

Давайте продолжим на реальном примере.

Вывод товаров бренда

Создаём на сайте страницу /brands/ в которой может быть вызов каталога товаров или что-то подобное — сюда мы будем отправлять юзера.
[[!mFilter2?
	&parents=`9`
	&hideContainers=`1`
	&element=`msProducts`
	&filters=`
		ms|price:number,
		parent:parents,
		msoption|tags,
		ms|vendor:vendors
	`
	&class=`msProduct`
	&sort=`product|pagetitle:asc`
	&tplFilter.outer.ms|price=`tpl.mFilter2.filter.slider`
	&tplFilter.row.ms|price=`tpl.mFilter2.filter.number`
	&tpls=`tpl.msProducts.row,tpl.msProducts.row2`
]]

Затем разбрасываем на сайте ссылки типа /brands/имябренда/, или /brands/имябренда.html, или /brands/имябренда — на ваше усмотрение. Мне нравится /brands/имябренда.

Пройдя по такой ссылке юзер сгенериует событие OnPageNotFound, где его перехватит наш плагин. Проверяем:


Ну а теперь можно уже и написать рабочий плагин:
<?php
if ($modx->event->name != 'OnPageNotFound') {return false;}
$alias = $modx->context->getOption('request_param_alias', 'q');
if (!isset($_REQUEST[$alias])) {return false;}

$request = $_REQUEST[$alias];
$tmp = explode('/', $request);
// Ссылка подходит под заданный формат: brands/brandname
if ($tmp[0] == 'brands' && count($tmp) >= 2) {
	// Определяем id раздела /brands/.
	// Конечно, можно его и руками прописать - но так гибче
	if (!$section = $modx->findResource($tmp[0] . '/')) {
		// Если вдруг раздел куда-то делся - выходим.
		return false;
	}
	// Теперь очищаем имя бренда от возможного расширения
	$name = str_replace('.html', '', $tmp[1]);
	// Если очищенное имя не равно запрошенному - то можно отредиректить юзера
	// Также возможен вариант с косой на конце имени бренда - его тоже учитываем
	// SEOшники должны оценить =)
	if ($tmp[1] != $name || (isset($tmp[2]) && $tmp[2] == '')) {
		$modx->sendRedirect($tmp[0] . '/' . $name);
	}
	
	// Люди с неправильной ссылкой ушли на правильную и дошли до этого момента со второго раза
	// Дальше проверяем наличие запрошенного бренда
	if ($brand = $modx->getObject('msVendor', array('name' => $name))) {
		// Круто, такой бренд есть, получаем его id
		$id = $brand->get('id');
		
		// Осталось выставить нужные переменные в запрос, как будто юзер их сам указал
		// Так как это mFilter2 - выставляем выбранный бренд
		$_GET['ms|vendor'] = $_REQUEST['ms|vendor'] = $id;
		// А теперь подсовывем юзеру страницу брендов, а дальше сниппет на ней сам разберётся
		$modx->sendForward($section);
	}
}
// Иначе ничего не делаем и юзер получает 404 или его перехватывает другой плагин.

Как видите, весь смысл в том, чтобы разобрать запрошенное имя бренда, запихать его в запрос и показать нужную страницу, взамен виртуальной.

Вот и вся маршрутизация. У кого остались вопросы?

Источник: bezumkin.ru/sections/tips_and_tricks/2918/


0 комментариев

    Авторизация

    через сервис Loginza:


    Шаблоны MODX

    1 2 Дальше »

    Объектная
    модель
    MODX