Посмотрев на собственные посты и комментарии в прошлом, посмотрев на сообщество и степень его активности на данный момент, посмотрев на степень развития и направление развития вендора, я решил что постить статьи о разработке в блоги битрикса бессмысленно. Поэтому я решил размещать статьи у себя в блоге (он обязательно появится, руки не доходят), а сюда скидывать ссылку - как это делают все вменяемые разработчики.
К делу.
Я считаю разработку на битриксе неповоротливой и очень долгой, чтобы это ускорить я решил использовать docker. Разворачивание окружения занимает секунды (после первого запуска - сначала подтянутся все зависимости) и позволяет работать с проектом практически мгновенно. Не думаю, что стоит рассказывать о докере много (тема давно известна). Вообще, репозиторий создавался для своих целей, но если кому то поможет в разработке (почему бы не поделиться).
Что в сборке: - PHP 7.3 (в том числе CLI а также composer) - Встроенный xdebug / opcache - nginx 1.14 (apache не нужен, как бы совсем, тем более для разработки) - mysql 5.7 (хочется 8, но пока битрикс на нём не заводится) - smtp сервер (mailhog доступен по локальному адресу для просмотра писем) - memcache (пока нет официального расширения для php 7.3) - redis
Планируется: - bitrix-push-server - mariadb (вместо mysql) - поддержка композитного кэша - поддержка битрикс24
PS Я знаю что есть https://github.com/bitrixdock/bitrixdock - и это очень неплохая сборка докера (на самом деле это лучшая сборка битрикс докера), но у ребят идея сделать это универсальным средством и для прода и для дева - это другой путь. Моя же цель - сделать сборку современной (использовать последние версии ПО), простой, и удобной для разработки в первую очередь (мало кто доверяет докеру на проде, но это вопрос времени)
Микулич Евгений, вот это и расстраивает. Я не очень дружу с командной строкой, но когда устанавливаю Docker и выполняю разные команды, начинающиеся с docker - вылазят ошибки, не помню уже какие, год назад это было. Так и не смог их побороть.
Рязанцев Андрей написал: вылазят ошибки, не помню уже какие, год назад это было. Так и не смог их побороть.
Любой инструмент предполагает изучение его инструкции к применению. Многие ставят докер (и любые другие инструменты) но разбираться в этом не хотят - само по себе ничего не заработает, надо разбираться.
Сам спросил. сам разобрался, кому будет интересно решение: чтобы получить доступ к данным типа Адрес Доставки, Название компании, ИНН, КПП и пр. необходимо вызвать метод GetGroups() у $propertyCollection. Пример установки адреса Доставки:
Предисловие Сижу я такой, делаю интернет-магазин. И уже второй клиент просит меня поставить компонент для управления выводом товаров по персональным рекомендациям (BigData). Я не любитель применять новые фишки битрикс пока не услышу что "это" уже не сырое и можно использовать. Ну, думаю я , срок уже подошёл, к тому же вроде как всё само должно работать. А нет (не должно было удивить), само всё работать будет только для магазина из коробки (Современный интернет магазин от битрикс).
Разочарование Открываю я компонент catalog.bigdata.products и вижу о ужас, тот же самый фарш что в новых компонентах для магазина после версии 12.0. Очень много кода, код тянется давно и разбираться в нём нет никакого желания: там и корзина и пересчёты и ску. Что делать если в простом магазине всего этого нет, а добавление товара в корзину происходит всего 1 строчкой? Что делать тем, кто не использует весь "фарш" универсальных компонентов - а просто пишет только то, что необходимо, и не оставляет кучу хвостов в своём коде? Открыв этот шаблон и ковыряя его, я всё проклял) и написал жалобное сообщение здесь. На что получил интересный ответ, который помог написать свой компонент для "упрощённой работы".
Принцип работы компонента catalog.bigdata.products Компонент большой, наследуется от catalog.viewed.products, тащит за собой много чего. Тонны тонны кода в шаблоне. Идея работы:
Компонент отрабатывает первый раз - делает запрос к сервису (в облако) (только запрос)
Компонент отрабатывает второй раз посылает запрос к аякс странице (уже в компоненте) (подставляя значения полученные из облака)
Отображает данные (подгружает аякс), вешает события и т.д. (Схема очень упрощенная так как есть много всяких разных ньюансов)
Как же работает персонализация? В нужный момент (переход по ссылке или бросок в корзину) происходит установка специальных куков (в которых указан ID товара, рекомендация и время). К тому же компонент catalog.element генерирует какой-то js код, при оформлении заказа видимо куки улетают на сервис и там происходит всякая магия.
Ближе к делу (к коду) Я решил написать свой собственный компонент который выполняет минимальные операции по работе с персонализацией. идея у меня останется прежней, а вот кода будет меньше.
RCM_TYPE - полностью слизан с catalog.viewed.products (то есть весь тот же самый список рекомендаций) 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) ничего сложного просто дополнение уже установленного массива данными в зависимости от рекомендации:
На этом основные методы компонента можно опустить (больше ничего и не требуется, но я написал ещё метод curl если кому то будет необходимо)
Шаблон нашего компонента
<?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, чем выпустит его с плохой документацией.
Старикевич Максим, если вы сами товар добавляете в корзину, то в функциях Add2Basket или Add2BasketByProductID надо в массиве arProductParams кроме всего передать "секретное" свойство "RECOMMENDATION" => 1, и тогда товар и сам заказ отметится голубой иконкой рекомендаций.
Про пользу документации - поддерживаю полностью. Про возможность через наследование добавить функционал, не ломая непонятные потроха вокруг - поддерживаю.
Всем добрый вечер. Небольшая статейка будет полезна больше пользователям nix систем. Но всё это реализуемо и на windows.
Для меня как для разработчика является нудным и утомительным занятием развёртывание рабочей среды под проект. По хорошему среду надо разворачивать максимально приближенную к боевой конфигурации сервера (те кто работают с боевыми серверами на прямую - ай ай ай. Надо уже переходить хотя бы на локаль -> продакшн. Хотя в идеале лучше локаль -> тест сервер -> боевой с миграциями и прочими штуками). Каждый проект заслуживает особого внимания и я не люблю разворачивать проекты на одном окружении (конфиги всё равно разные).
Для windows систем есть веб окружения от вендора (от битрикса). Есть виртуальная машина от битрикс - по мне так ад адовый (не машина то очень неплохо собрана, просто хз как её на моей убунте запускать)
Все примочки вендора это хорошо и здорово. Но есть другие пути. Рабочее окружение можно развернуть в один клик так сказать. До настройки окружения чисто под битрикс мне ещё далеко, но я собрал типовое окружение LAMP (php, apache, mysql, linux). Делюсь наработкой.
VirtualBox - программное обеспечение для виртуализации операционных систем Vagrant - программное обеспечение для создания и конфигурирования виртуальной среды разработки Git - распределённая система управления версиями файлов.
После установки создаём папку проекта (например vagrant-lamp)
mkdir vagrant-lamp
Переходим в папку
cd vagrant-lamp
Инициализируем Vagrant
vagrant init
После этого в папке появляется файл Vagrantfile
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "base"
end
После этого нам нужно выбрать box (это виртуалка, которую в последующем vagrant сам закачает на вашу машину). Выберем например Ubuntu 14.04 (хотя дебиан лучше наверное). Список доступных боксов
config.vm.box = "ubuntu/trusty64"
Доработаем файл
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "ubuntu/trusty64"
config.vm.network "forwarded_port", guest: 80, host: 8080 //пробрасываем порты (80 - порт на виртуалке, 8080 - порт на нашей машине)
config.vm.network "forwarded_port", guest: 3306, host: 33060 //пробрасываем порты для mysql (3306 - порт на виртуалке, 33060 - порт на нашей машине)
config.vm.synced_folder ".", "/home/vagrant" //проводим синхронизацию текущего каталога с каталогом на виртуальной машине (мощь!)
config.vm.provision :shell, :path => "bootstrap.sh" //скрипт который будет выполнен после разворачивания виртуалки
end
Создадим файл bootstrap.sh (bash)
#!/usr/bin/env bash
# Variables path
php_config_file="/etc/php5/apache2/php.ini"
xdebug_config_file="/etc/php5/mods-available/xdebug.ini"
mysql_config_file="/etc/mysql/my.cnf"
apache_config_file="/etc/apache2/apache2.conf"
host_document_root="/home/vagrant"
apache_document_root="/var/www/html"
apache_ports_config_file="/etc/apache2/ports.conf"
project_folder_name='public'
# Variables env
DBNAME=vagrant
DBUSER=vagrant
DBPASSWD=vagrant
echo "--- Начало установки ---"
echo "--- Обновление списка пакетов ---"
apt-get -qq upd ate
echo "--- Установка базовых пакетов ---"
apt-get -y install vim curl build-essential python-software-properties git
echo "--- Обновление списка пакетов ---"
apt-get upd ate
echo "--- Установка Apache2 ---"
apt-get install -y apache2
echo "--- Установка MySql ---"
echo "mysql-server mysql-server/root_password password ${DBPASSWD}" | debconf-set-selections
echo "mysql-server mysql-server/root_password_again password ${DBPASSWD}" | debconf-set-selections
echo "phpmyadmin phpmyadmin/dbconfig-install boolean true" | debconf-set-selections
echo "phpmyadmin phpmyadmin/app-password-confirm password ${DBPASSWD}" | debconf-set-selections
echo "phpmyadmin phpmyadmin/mysql/admin-pass password ${DBPASSWD}" | debconf-set-selections
echo "phpmyadmin phpmyadmin/mysql/app-pass password ${DBPASSWD}" | debconf-se t-selections
echo "phpmyadmin phpmyadmin/reconfigure-webserver multiselect none" | debconf-se t-selections
apt-get -y install mysql-server-5.5 mysql-client phpmyadmin
mysql -uroot -p${DBPASSWD} -e "CRE ATE DATABASE ${DBNAME}"
mysql -uroot -p${DBPASSWD} -e "grant all privileges on $DBNAME.* to '${DBUSER}'@'localhost' identified by '${DBPASSWD}'"
echo "--- Установка репозиториев ---"
add-apt-repository ppa:ondrej/php5
#uncomment to install NodeJS
#add-apt-repository ppa:chris-lea/node.js
apt-get -qq update
echo "--- Установка PHP ---"
apt-get install -y php5 libapache2-mod-php5 php5-curl php5-gd php5-mcrypt php5-mysql php-apc
echo "--- Установка и конфигурация xDebug ---"
apt-get install -y php5-xdebug
cat << EOF | sudo tee -a ${xdebug_config_file}
xdebug.scream=1
xdebug.cli_color=1
xdebug.show_local_vars=1
EOF
echo "--- Включение mod-rewrite ---"
a2enmod rewrite
echo "--- Установка root папки---"
sudo rm -rf ${apache_document_root}
sudo ln -fs ${host_document_root}/${project_folder_name} ${apache_document_root}
echo "--- Настройка php.ini и apache2.conf ---"
sed -i "s/error_reporting = .*/error_reporting = E_ALL/" ${php_config_file}
sed -i "s/display_errors = .*/display_errors = On/" ${php_config_file}
#uncomment to work with Boris
#echo "--- Работа с Boris---"
#sed -i "s/disable_functions = .*//" /etc/php5/cli/php.ini
sudo sed -i 's/AllowOverride None/AllowOverride All/g' ${apache_config_file}
a2enconf phpmyadmin
echo "--- Перезагрузка Apache2 ---"
service apache2 restart
echo "--- Перезагрузка mysql ---"
service mysql restart
#echo "--- Установка composer ---"
#uncomment to install coomposer
#curl --silent https://getcomposer.org/installer | php
#mv composer.phar /usr/local/bin/composer
#echo "--- Установка NodeJS и NPM ---"
#uncomment to install NodeJS NPM
#apt-get -y install nodejs
#curl --silent https://npmjs.org/install.sh | sh
#echo "--- Установка Gulp, Bower ---"
#uncomment to install Gulp and Bower
#npm install -g gulp bower
#echo "--- Обновление компонентов проекта ---"
#uncomment to update packages
#cd /vagrant
#sudo -u vagrant -H sh -c "composer install"
#cd /vagrant/client
#sudo -u vagrant -H sh -c "npm install"
#sudo -u vagrant -H sh -c "bower install -s"
#sudo -u vagrant -H sh -c "gulp"
Таким образом установим на машину всё необходимое.
Создадим в текущем каталоге папку public и в неё положим index.php
Кстати есть вот такой сервис на основе puppet puphpet.com где через интерфейс можно собрать любой конфиг и быстро сляпать необходимый сервер - очень круто.
Вообщем то всё просто. Рутинные задачи заставляют придумывать что-нибудь. Сегодня понял что больше не могу костылить сортировку по названию, по цене и т.д. И написал свой компонент, с базовым компонентом с возможностью гибкой кастомизации.
вот вы битрикс все ругаете. но предлагаете какую то индусскую архитекутуру. но вообще не понимаете суть компонентов - компонент это отдельная готовая сущность. а если надо наследование и переиспользование надо разбивать на классы-сервисы. которые в модуле должны быть и которые будут использоваться компонентом.
Эта статья - ответ на вопрос: Что предлагает модуль в отличии от стандартного функционала SEO 14.5?
Благодаря тому, что модуль никак не привязан к сущности инфоблоков можно задать теги для элемента/раздела хоть на 10 лет вперёд, используя поля в правиле Начало активности и Конец активности. (Пример: для обуви можно расписать продвигающие тексты на год вперёд (зима, лето весна, осень);
Если элемент привязан к нескольким разделам модуль установит данные актуального раздела, в случае с инфоблоками - будет взято значение первого привязанного раздела;
Модуль предлагает устанавливать любые мета теги (можно хоть свои придумать). Инфоблоки - только TITLE, KEYWORDS, DESCRIPTION;
Можно задать отдельно данные для постранички к конкретному тэгу (также есть поддержка замены ключей). В инфоблоках нет такого функционала.
Таргетинг - работает как в модуле Реклама (то есть можно задать несколько путей для срабатывания правила). Можно 1 правило применять для нескольких товаров/элементов/разделов (например нужно продвинуть 5 каких-то товаров). В инфоблоках - идём и в 5 элементах меняем данные
Многосайтовость. Можно задать правило/ключ как для определённого сайта, так и для всех сайтов сразу, так же как и для определённого шаблона. Инфоблоки - только для тех сайтов, к которым привязан инфоблок, шаблоны сайтов не учитываются вообще.
Переменные запроса. Можно задать срабатывание правила при определённых значения в URI (Например: http::/shop.ru/catalog/?filter=Y&color=green&material=cotton. Таким образом, можно продвигать, например, страницу фильтра). В инфоблоках - отсутствует любая работа с переменными в URI. То есть 1 элемент = 1 набор TITLE, KEYWORDS, DESCRIPTION и всё.
PHP выражение. Здесь можно задать любое условие на языке PHP (расписывать не имеет смысла). В инфоблоках отсутствует.
Гибкое управление условием наличия установленных ключей. Можно задать любое количество правил с различным набором ключей (Например задать 3 правила для элемента для разных случаев: для вкладки описания, для вкладки отзывов, для вкладки характеристик. По сути страница будет одна, но при разных активных вкладках может быть разный набор ключей, а в зависимости от них будут срабатывать разные правила и можно продвигать сразу три страницы). В инфоблоках - отсутствует.
Региональность. И ей подобные (например дилер магазина) сущности относятся ко всему сайту и часто требуется включить их в формирование продвигающих текстов. (Например Купить товар по самой низкой цене в Челябинске или Купить товар по скидке в магазине Яша в регионе Челябинск). В инфоблоках отсутствует.
Формирование текста вместо мета тэгов. При желании можно выводить сгенерированный текст не в мета тэги а на странице (Например сформировать продающий текст внизу страницы на основании тех же правил). В инфоблоках - нужно будет лезть и программировать вывод.
ORM. Модуль написан с использованием ORM D7. Работа с таблицами модуля происходит быстрее чем с таблицами инфоблоков.
Любую переменную/ячейку массива сайта можно использовать как значение ключа (предварительно объявив её глобальной или создать статический метод, который её возвращает). А ключ можно использовать в любом шаблоне для формирования значение тэгов. В инфоблоках - всё что не связано с ними невозможно использовать не влезая в код.
Не секрет, что документация по битриксу очень не успевает, я подумал может быть куча наработок, открою миру и в массу примеров работы с новым ядром покажу здесь (особенно по интернет магазину):
Если вас напрягает передавать свойства в массиве $properties? то подайте туда ID заказа (например последнего) и тогда профиль будет создан по данным последнего заказа
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».