Всем привет 
Сразу к делу. На одном проекте у заказчика возникло требование, чтобы на каждой второй странице списка элементов/товаров вместо одного из товаров отображалась реклама.
Т.е. если на каждой странице у нас должно отображаться по три элемента списка, то на каждой четной странице будет отображаться два элемента + 1 рекламный блок, замаскированный под товар.
Естественно возник вопрос как это сделать не сильно ломая Битрикс и не теряя никаких элементов при пагинации.
На чистом SQL задача решается довольно просто: корректной установкой LIMIT. Но на первый взгляд Битрикс в своем GetList не дает возможности установить LIMIT самим. Можно только указать сколько тебе элементов надо и текущую страницу.
Я уже было приуныл, но все таки решил поковырять ядро на авось. И авось оправдался
В недрах CDBResult был найден вот такой кусочек кода:
Битрикс проверяет наличие некоего (недокументированного
) параметра SubstitutionFunction передаваемого и если он есть, то доверяет составление пагинации и нашего заветного LIMIT ему.
Ихххаа!!1
Далее дело за малым: написать свою функцию пагинации по нехитрому алгоритму.
На каждой второй странице у нас по сути добавляется один элемент. На каждой второй странице = каждый шестой элемент - фейковый. Т.е. по сути у нас добавляется (Общее количество элементов / 5) элементов. Т.е.
Ну и надо еще высчитать правильное смещение в LIMIT. Оно считается тоже очень просто:
Дальше просто копируем весь оставшийся код CDBResult::NavQuery в нашу функцию после того как мы переопределили все нужные нам параметры.
Ну и собственно все. Теперь нашу функцию (назовем ее SD_OneFakeElementOnEverySecondPage) нужно всего лишь передать в любой GetList и она отстроит нам правильную пагинацию и выведет корректное число элементов на страницах.
Например, это может выглядеть так:
Всё, спасибо за внимание
ЗЫ: полный код функции можно посмотреть здесь:
ЗЗЫ: Ну и

Сразу к делу. На одном проекте у заказчика возникло требование, чтобы на каждой второй странице списка элементов/товаров вместо одного из товаров отображалась реклама.
Т.е. если на каждой странице у нас должно отображаться по три элемента списка, то на каждой четной странице будет отображаться два элемента + 1 рекламный блок, замаскированный под товар.

Естественно возник вопрос как это сделать не сильно ломая Битрикс и не теряя никаких элементов при пагинации.
На чистом SQL задача решается довольно просто: корректной установкой LIMIT. Но на первый взгляд Битрикс в своем GetList не дает возможности установить LIMIT самим. Можно только указать сколько тебе элементов надо и текущую страницу.
Я уже было приуныл, но все таки решил поковырять ядро на авось. И авось оправдался

В недрах CDBResult был найден вот такой кусочек кода:
/bitrix/modules/main/classes/mysql/database.php:989
function NavQuery($strSql, $cnt, $arNavStartParams)
{
if(is_set($arNavStartParams, "SubstitutionFunction"))
{
$arNavStartParams["SubstitutionFunction"]($this, $strSql, $cnt, $arNavStartParams);
return;
} |
) параметра SubstitutionFunction передаваемого и если он есть, то доверяет составление пагинации и нашего заветного LIMIT ему.Ихххаа!!1

Далее дело за малым: написать свою функцию пагинации по нехитрому алгоритму.
На каждой второй странице у нас по сути добавляется один элемент. На каждой второй странице = каждый шестой элемент - фейковый. Т.е. по сути у нас добавляется (Общее количество элементов / 5) элементов. Т.е.
//Пересчитываем общее количество записей с учетом того, что на каждой четной странице у нас стоит один фейк элемент $oResult->NavRecordCount = ( floor( $oResult->NavRecordCount / ($oResult->NavPageSize+$oResult->NavPageSize-1) ) + $oResult->NavRecordCount ); |
Ну и надо еще высчитать правильное смещение в LIMIT. Оно считается тоже очень просто:
$iSecondHalf = $iHalfPages = floor( $oResult->NavPageNomer / 2 ); if($oResult->NavPageNomer % 2 == 0)$iSecondHalf--; if( $iSecondHalf < 0) $iSecondHalf = 0; //Пересчитываем смещение. $NavFirstRecordShow = $iHalfPages* ( $oResult->NavPageSize ) + $iSecondHalf* ( $oResult->NavPageSize-1 ); $NavLastRecordShow = ($oResult->NavPageNomer % 2 == 1)?$oResult->NavPageSize:($oResult->NavPageSize-1); |
Дальше просто копируем весь оставшийся код CDBResult::NavQuery в нашу функцию после того как мы переопределили все нужные нам параметры.
Ну и собственно все. Теперь нашу функцию (назовем ее SD_OneFakeElementOnEverySecondPage) нужно всего лишь передать в любой GetList и она отстроит нам правильную пагинацию и выведет корректное число элементов на страницах.
Например, это может выглядеть так:
$rsElement = CIBlockElement::GetList( array(), array( 'IBLOCK_ID' => 31337 ), false, array( 'SubstitutionFunction' => 'SD_OneFakeElementOnEverySecondPage' ) ); |
Всё, спасибо за внимание

ЗЫ: полный код функции можно посмотреть здесь:
ЗЗЫ: Ну и
