Предисловие
Сижу я такой, делаю интернет-магазин. И уже второй клиент просит меня поставить компонент для управления выводом товаров по персональным рекомендациям (BigData). Я не любитель применять новые фишки битрикс пока не услышу что "это" уже не сырое и можно использовать. Ну, думаю я , срок уже подошёл, к тому же вроде как всё само должно работать. А нет (не должно было удивить), само всё работать будет только для магазина из коробки (Современный интернет магазин от битрикс).
Разочарование
Открываю я компонент catalog.bigdata.products и вижу о ужас, тот же самый фарш что в новых компонентах для магазина после версии 12.0. Очень много кода, код тянется давно и разбираться в нём нет никакого желания: там и корзина и пересчёты и ску. Что делать если в простом магазине всего этого нет, а добавление товара в корзину происходит всего 1 строчкой? Что делать тем, кто не использует весь "фарш" универсальных компонентов - а просто пишет только то, что необходимо, и не оставляет кучу хвостов в своём коде? Открыв этот шаблон и ковыряя его, я всё проклял) и написал жалобное сообщение . На что получил интересный ответ, который помог написать свой компонент для "упрощённой работы".
Принцип работы компонента catalog.bigdata.products
Компонент большой, наследуется от catalog.viewed.products, тащит за собой много чего. Тонны тонны кода в шаблоне.
Идея работы:
Ближе к делу (к коду)
Я решил написать свой собственный компонент который выполняет минимальные операции по работе с персонализацией. идея у меня останется прежней, а вот кода будет меньше.
Так выглядит вызов компонента
RCM_TYPE - полностью слизан с catalog.viewed.products (то есть весь тот же самый список рекомендаций)
ELEMENT_ID/ELEMENT_CODE - это ID/код товара, к которому будут подбираться "похожие товары" по рекомендации
ELEMENTS_LIMIT - Количество ID элементов для запроса в облако
Остальные параметры интуитивно понятны
Метод в компоненте, который устанавливает массив для запроса в облако:
Метод для выбора рекомендации (слизан с catalog.bigdata.products) ничего сложного просто дополнение уже установленного массива данными в зависимости от рекомендации:
На этом основные методы компонента можно опустить (больше ничего и не требуется, но я написал ещё метод curl если кому то будет необходимо)
Шаблон нашего компонента
С помощью двух последний параметров идёт установка кук, которые необходимы для работы с персонализацией.
Файл script.js
В принципе всё! Единственное в чём я сомневаюсь это какой RID (recomenadion ID) должен передаваться в облако, потому что в стандартном компоненте, он то принимает значение из списка, то какой-то хеш, если кто-то знает, буду рад совету.
Спасибо Медведеву Дмитрию, за наводку (привет битрикс), Сухареву Антону из "Кузницы" за "поделился идеей работы bigdata"
Компонент собран на скорую руку. Взять можно .
ЗЫ: Для битрикса remember пишется с одной M.
ЗЫ2: Я чувствую что не настанет того дня когда CMS будет писаться и для разработчиков в том числе. А это плохо, плохо ковырять продакшн код не имея документации и не имея примеров использования - отсюда все проблемы. 9 проектов из 10 используют стандартные компоненты, а использование кода в этих компонентах под задачи стремится к 1% (про шаблоны идёт речь). И никакие композиты, оптимизации и аналитики или хостинги не решат этих проблем. Битрикс становится прожорливее и не успевает железо за его ненасытными потребностями или потребностями менеджеров.
Сижу я такой, делаю интернет-магазин. И уже второй клиент просит меня поставить компонент для управления выводом товаров по персональным рекомендациям (BigData). Я не любитель применять новые фишки битрикс пока не услышу что "это" уже не сырое и можно использовать. Ну, думаю я , срок уже подошёл, к тому же вроде как всё само должно работать. А нет (не должно было удивить), само всё работать будет только для магазина из коробки (Современный интернет магазин от битрикс).
Разочарование
Открываю я компонент catalog.bigdata.products и вижу о ужас, тот же самый фарш что в новых компонентах для магазина после версии 12.0. Очень много кода, код тянется давно и разбираться в нём нет никакого желания: там и корзина и пересчёты и ску. Что делать если в простом магазине всего этого нет, а добавление товара в корзину происходит всего 1 строчкой? Что делать тем, кто не использует весь "фарш" универсальных компонентов - а просто пишет только то, что необходимо, и не оставляет кучу хвостов в своём коде? Открыв этот шаблон и ковыряя его, я всё проклял) и написал жалобное сообщение . На что получил интересный ответ, который помог написать свой компонент для "упрощённой работы".
Принцип работы компонента catalog.bigdata.products
Компонент большой, наследуется от catalog.viewed.products, тащит за собой много чего. Тонны тонны кода в шаблоне.
Идея работы:
- Компонент отрабатывает первый раз - делает запрос к сервису (в облако) (только запрос)
- Компонент отрабатывает второй раз посылает запрос к аякс странице (уже в компоненте) (подставляя значения полученные из облака)
- Отображает данные (подгружает аякс), вешает события и т.д. (Схема очень упрощенная так как есть много всяких разных ньюансов)
Ближе к делу (к коду)
Я решил написать свой собственный компонент который выполняет минимальные операции по работе с персонализацией. идея у меня останется прежней, а вот кода будет меньше.
Так выглядит вызов компонента
<?$APPLICATION->IncludeComponent( "shantilab:bigdata.products.list", ".default", array( "IBLOCK_TYPE" => "products", "IBLOCK_ID" => 13, "CACHE_TYPE" => "N", "CACHE_TIME" => "0", "COMPONENT_TEMPLATE" => ".default", "RCM_TYPE" => "any", "ELEMENT_ID" => "", "ELEMENT_CODE" => "", "ELEMENTS_LIMIT" => "10", "CACHE_GROUPS" => "Y" ), false );?> |
ELEMENT_ID/ELEMENT_CODE - это ID/код товара, к которому будут подбираться "похожие товары" по рекомендации
ELEMENTS_LIMIT - Количество ID элементов для запроса в облако
Остальные параметры интуитивно понятны
Метод в компоненте, который устанавливает массив для запроса в облако:
public function setBigData($type = null, $productId = null)
{
$this->dataToRequest = array(
'uid' => $_COOKIE['BX_USER_ID'], //Кука пользователя
'aid' => Counter::getAccountId(), // хэш лицензии (\Bitrix\Main\Analytics\Counter)
'count' => $this->arParams['ELEMENTS_LIMIT'], //количество
);
//Id товара, если нужно искать похожие
$productId = intval($productId);
if ($productId)
$this->productId = $productId;
if ($type)
$this->setType($type); //выбор рекомендации
} |
Метод для выбора рекомендации (слизан с catalog.bigdata.products) ничего сложного просто дополнение уже установленного массива данными в зависимости от рекомендации:
public function setType($type){
if ($type == 'any_similar' && $this->productId)
{
$this->possibleTypes = array('similar_sell', 'similar_view', 'similar');
$type = $this->possibleTypes[array_rand($this->possibleTypes)];
}
elseif ($type == 'any_personal')
{
$this->possibleTypes = array('bestsell', 'personal');
$type = $this->possibleTypes[array_rand($this->possibleTypes)];
}
elseif ($type == 'any')
{
$this->possibleTypes = array('similar_sell', 'similar_view', 'similar', 'bestsell', 'personal');
if (!$this->productId){
unset($this->possibleTypes[array_search('similar_sell', $this->possibleTypes)]);
unset($this->possibleTypes[array_search('similar_view', $this->possibleTypes)]);
unset($this->possibleTypes[array_search('similar', $this->possibleTypes)]);
}
$type = $this->possibleTypes[array_rand($this->possibleTypes)];
}
if ($type == 'bestsell')
{
$data['op'] = 'sim_domain_items';
$data['type'] = 'order';
$data['domain'] = Context::getCurrent()->getServer()->getHttpHost();
}
elseif ($type == 'personal')
{
$data['op'] = 'recommend';
}
elseif ($type == 'similar_sell')
{
$data['op'] = 'simitems';
$data['eid'] = $this->productId;
$data['type'] = 'order';
}
elseif ($type == 'similar_view')
{
$data['op'] = 'simitems';
$data['eid'] = $this->productId;
$data['type'] = 'view';
}
elseif ($type == 'similar')
{
$data['op'] = 'simitems';
$data['eid'] = $this->productId;
}
if ($this->arParams['IBLOCK_ID'])
$data['ib'] = $this->arParams['IBLOCK_ID'];
foreach($data as $key => $val){
$this->dataToRequest[$key] = $val;
}
} |
Шаблон нашего компонента
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?>
<div class="bigdata-recommended"> <!--Блок родитель-->
<div class="bigdata-wrap"></div> <!--Блок куда будут вставляться данные ajax запросом-->
</div>
<sc ript>
var bigData = { // объект хранилище для запросов
'cookie_prefix': '<?=CUtil::JSEscape(COption::GetOptionString("main", "cookie_name", "BITRIX_SM"))?>', //префикс
'cookie_domain': '<?=$APPLICATION->GetCookieDomain()?>', //домен
'recommendationId': '<?=$arResult['RID']?>', //ID рекомендации, установленной в компоненте
'ajaxElementsPage': '<?=$componentPath?>/ajax.php', // страница с кодом, который будет выполнятся после запроса в облако
'data': <?=CUtil::PhpToJSObject($arResult['BIG_DATA'])?>, //данные для запроса
'url': '<?=$arResult['REQUEST_URL']?>', //url для запроса
'detailPageUrlRecommendedClass': 'bx_rcm_view_link', //класс, который нужно проставить для ссылок, ведущих на детальную карточку товара (ВАЖНО!)
'addToCartActionClass': 'add2cart' //класс, который нужно проставить для тега корзины (ВАЖНО!)
}
</sc ript> |
Файл script.js
function getCookie(name) {
// Опущу описание, так как это просто функция, которая возвращает значение куки по заданному имени
}
function rememberRecommend(rcmId, productId){ //слизано с catalog.bigdata.products, теперь можно сразу указать тип рекомендации и ID товара. В стандартном компоненте подавался ещё и объект, нам не нужно
var plCookieName = bigData.cookie_prefix + '_RCM_PRODUCT_LOG';
var plCookie = getCookie(plCookieName);
var itemFound = false;
var current_server_time = new Date().getTime();
var cItems = [],
cItem;
if (plCookie)
{
cItems = plCookie.split('.');
}
var i = cItems.length;
while (i--)
{
cItem = cItems[i].split('-');
if (cItem[0] == productId)
{
cItem = cItems[i].split('-');
cItem[1] = rcmId;
cItem[2] = current_server_time;
cItems[i] = cItem.join('-');
itemFound = true;
}
else
{
if ((current_server_time - cItem[2]) > 3600*24*30)
{
cItems.splice(i, 1);
}
}
}
if (!itemFound)
{
cItems.push([productId, rcmId, current_server_time].join('-'));
}
var plNewCookie = cItems.join('.');
var cookieDate = new Date(new Date().getTime() + 1000*3600*24*365*10);
document.cookie=plCookieName+"="+plNewCookie+"; path=/; expires="+cookieDate.toUTCString()+"; domain="+bigData.cookie_domain; //Установка куки
}
//Получение кода (html) со странице, которая будет вызвана после запроса в облако (возвращаемые данные вставляются в контейнер).
function getProducts(ids){
console.log('Getting ajax page...');
$.ajax({
url : bigData.ajaxElementsPage,
data: {'IDS': ids} //Полученные ID товаров из облака
}).done(function(html) {
console.log('Ajax page is getted');
if (!html)
console.log('No items found');
$('.bigdata-recommended .bigdata-wrap').html(html);
});
}
$(document).ready(function(){
//Событие на клик ссылки для перехода на детальную страницу.
//(ВАЖНО!)Сопроводить все ссылки на детальную карточку классом из переменной bigData.detailPageUrlRecommendedClass и атрибутом data-product-id в котором лежит значение ID элемента
$(document).on('click', ".bigdata-recommended ." + bigData.detailPageUrlRecommendedClass, function(event){
event.preventDefault();
var _this = $(this);
var productId = _this.data('product-id');
rememberRecommend(bigData.recommendationId, productId);
location.href = _this.attr('href');
});
//Событие на клик добавления в корзину.
//(ВАЖНО!)Сопроводить тег с добавлением в корзину классом из переменной bigData.addaddToCartActionClass и атрибутом data-product-id
$(document).on('click',".bigdata-recommended ." + bigData.addaddToCartActionClass, function(e){
e.preventDefault();
var _this = $(this);
var productId = _this.data('product-id');
rememberRecommend(bigData.recommendationId, productId);
});
console.log('Getting ids...');
// Запрос к облаку BigData
$.ajax({
method : "POST",
url : bigData.url,
data: bigData.data
}).done(function(response) {
response = JSON.parse(response);
if (!response.items)
return;
console.log('Ids is getted');
getProducts(response.items);
});
}); |
В принципе всё! Единственное в чём я сомневаюсь это какой RID (recomenadion ID) должен передаваться в облако, потому что в стандартном компоненте, он то принимает значение из списка, то какой-то хеш, если кто-то знает, буду рад совету.
Спасибо Медведеву Дмитрию, за наводку (привет битрикс), Сухареву Антону из "Кузницы" за "поделился идеей работы bigdata"
Компонент собран на скорую руку. Взять можно .
ЗЫ: Для битрикса remember пишется с одной M.
ЗЫ2: Я чувствую что не настанет того дня когда CMS будет писаться и для разработчиков в том числе. А это плохо, плохо ковырять продакшн код не имея документации и не имея примеров использования - отсюда все проблемы. 9 проектов из 10 используют стандартные компоненты, а использование кода в этих компонентах под задачи стремится к 1% (про шаблоны идёт речь). И никакие композиты, оптимизации и аналитики или хостинги не решат этих проблем. Битрикс становится прожорливее и не успевает железо за его ненасытными потребностями или потребностями менеджеров.
| Когда Тейлора (создателя фреймворка Laravel) спросили: «Стоило ли так много времени тратить на документирование?», он ответил, что лучше задержит релиз Laravel 5.1, чем выпустит его с плохой документацией. |