Бывает что на проекте создано очень много правил для ЧПУ страниц: разделы, подразделы, детальная товара, сортировки, фильтры, постраничка и т.д. + различные их комбинации, например третья страница раздела с выбранной сортировкой и наложенным фильтром..
При этом очень важно чтобы все правила в файле urlrewrite.php располагались в строго определенном порядке от частных к общим, так как срабатывает первое подошедшее.
Проблема в том что в "Настройка правил обработки адресов" нет поля сортировки и после пересохранения файла, например, автоматического, комплексным компонентом с включенным ЧПУ после редактирования какого-нибудь параметра -- вся логика ЧПУ сайта рушится, вплоть до того что перестают отображаться страницы.
Я придумал такое решение (не затирается при обновлении системы): [spoiler]
1. создаем файл /my_urlrewrite.php, в который переносим все наши правила.
Если есть другое решение использования комплексного компонента catalog для чпу такого вида, при этом urlrewrite.php будет создаваться системой (те настройки компонента можно сохранять), хотелось бы с ним ознакомиться. Спасибо.
Трудно было не заметить ваше обсуждение по этой теме, пришлось реализовать свое решение http://marketplace.1c-bitrix.ru/solut...rlrewrite/ Нам будет приятно, если оно доставит радость пользователям Битрикса.
И снова здравствуйте. По ходу работы, часто приходится производить отладку и прочие замеры, и руками писать всякие записи в файлы не очень-то оптимально. Бывает, вижу что кто-то подключает свои файлы, и использует функции оттуда, для упрощения отладки. Но в продукте есть отдельные инструменты, которые могут упростить данную операцию.
Вывод данных Итак, есть у нас вызов АПИ, и хочется увидеть, с какими параметры в данном месте производится вызов. Лично я предпочитаю запись в файл, чтобы никак не влиять на работу сайта (разные проверки ip и прочее лениво писать). Код для записи в файл получится компактным:
тут у нас первым параметром идет сами данные, которые мы хотим увидеть, вторым идет название переменной, а третьим - имя файла (можно указывать путь, к примеру /bitrix/log.txt)
я лично сразу пишу много данных и сразу в массиве указываю подходящие ключи, поэтому второй параметр не использую
Учет времени Если же надоучесть время выполнения того или иного участка кода, то и для этого есть подходящие функции. В начале исследуемого участка кода, добавляем:
Bitrix\Main\Diag\Debug::startTimeLabel('test');
в конец:
Bitrix\Main\Diag\Debug::endTimeLabel('test');
И для вывода используем:
Bitrix\Main\Diag\Debug::getTimeLabels();
метод возвращаем массив со всеми включенными учетами времени
Helper Также есть вспомогательный класс Helper (Bitrix\Main\Diag\Helper), в котором всего пару функций:
Есть следующий кейс: Компонент news.list выводит элементы из инфоблока. У элементов инфоблока есть множественное свойство типа "Привязка к пользователю" под названием "Пользователи, которым понравилась новость". Задача: выводить логины пользователей, которым понравилась новость. Если пользователь авторизован, и он поставил "лайк", то выводить кнопку "Не нравится", если он не ставил "лайк", то выводить кнопку "Нравится". Ну т.е. типичный функционал оценки контента. Мне пришло в голову несколько вариантов того, как можно организовать этот функционал в рамках штатного news.list и увязать его работу с управляемым кэшем компонента, некоторые варианты мне показались вполне приемлемыми, некоторые - не очень. 1) Добавить к news.list параметр "USER_ID" и скармливать ему id авторизованного пользователя. А в template уже работаем с $arParams["USER_ID"] . Серьёзный недостаток в том, что управляемый кэш зависит от id пользователя, что является очень нежелательной ситуацией, ибо для каждого авторизованного пользователя будет создаваться свой экземпляр кэша. Вес файлов кэша будет очень большой.
2) Добавить к news.list параметр "LIKED_NEWS_IDS" , который будет содержать id статей, лайкнутых авторизованным пользователем. Т.к. возможен такой вариант, когда несколько разных пользователей полайкали один и тот-же набор статей, то объём кэша должен быть меньше (ну по крайней мере не больше), чем в реализации, описанной в первом варианте. Вариант считаю неидеальным, зависимость управляемого кэша от id пользователя всё-равно присутствует, но на этот раз косвенная. Нутром чую, что можно сделать как-то проще, но пока остановился на этом варианте. Вот код:
$(function () {
(function () {
$(document).on("click", ".js-like", function () {
var $button = $(this);
var $parent = $button.closest(".js-news-wrap__item");
var $blockUsers = $parent.find(".js-news-item__line");
$.post($button.data("handler-path"), { newId: $button.data("new-id"), iblockId: $button.data("iblock-id") }, function (data) {
if (data.content){ $blockUsers.html(data.content); }
if (data.action === "like") {
$button.addClass("btn_red");
$button.removeClass("btn_green");
$button.html($button.data("dislike-label"));
} else if (data.action === "dislike") {
$button.removeClass("btn_red");
$button.addClass("btn_green");
$button.html($button.data("like-label"));
}
}, "json");
});
})();
});
в обработчике меняем цвет и надпись кнопки , а так-же содержимое блока, в котором выведены логины пользователей, лайкнувших новость.
like.php. обработчик лайка, который вызываем ajax-ом :
<?require_once($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
CModule::IncludeModule('iblock');
$newId = intVal(htmlspecialchars($_POST['newId']));
$iblockId = intVal(htmlspecialchars($_POST['iblockId']));
if(empty($newId)) die();
if(empty($iblockId)) die();
global $USER;
if ($USER->IsAuthorized()) {
$arAllRegisteredUsersLogins = array();
$arAllRegisteredUsersLogins = HelperUsers::getAllRegisteredUsers();
$arFilter = array(
"IBLOCK_ID" => $iblockId,
"ID" => $newId
);
$rsElement = CIBlockElement::GetList(
array(),
$arFilter,
false,
false,
array("ID", "IBLOCK_ID", "PROPERTY_LIKED_USERS")
);
$PROPERTY_LIKED_USERS = array();
while ($arElement = $rsElement->GetNext()) {
/** PROPERTY_LIKED_USERS - это множественное свойство, поэтому вместо if
* используется while */
$PROPERTY_LIKED_USERS[] = $arElement["PROPERTY_LIKED_USERS_VALUE"];
}
sort($PROPERTY_LIKED_USERS);
$strActionType = "like";
if (in_array($USER->GetID(), $PROPERTY_LIKED_USERS)) {
$PROPERTY_LIKED_USERS = array_diff($PROPERTY_LIKED_USERS, array($USER->GetID()));
$strActionType = "dislike";
} else {
$PROPERTY_LIKED_USERS = array_merge($PROPERTY_LIKED_USERS, array($USER->GetID()));
}
sort($PROPERTY_LIKED_USERS);
CIBlockElement::SetPropertyValueCode($newId, "LIKED_USERS", $PROPERTY_LIKED_USERS);
if (defined('BX_COMP_MANAGED_CACHE')) {
$GLOBALS['CACHE_MANAGER']->ClearByTag('iblock_id_' . $iblockId);
$GLOBALS['CACHE_MANAGER']->ClearByTag('LikedNewID_' . $newId); // подозреваю, что эта строка здесь избыточна, но не стал проверять, оставил на всякий случай.
//Сброса кэша по стандартному тэгу iblock_id_ должно быть вполне достаточно.
}
$arLikedUsersLogins = array();
foreach ($PROPERTY_LIKED_USERS as $intLikedUserID) {
$arLikedUsersLogins[] = $arAllRegisteredUsersLogins[$intLikedUserID];
}
$VALUE_LOGINS_STR = implode(", ", $arLikedUsersLogins);
$result = array(
'action' => $strActionType,
'content' => $VALUE_LOGINS_STR
);
echo json_encode($result);
}else{
die();
}
Вот собственно и всё.
3) Ещё один вариант, который я спроектировал, но на практике не реализовывал. Отказывается от параметра LIKED_NEWS_IDS и задействуем component_epilog. В нём через HelperIblock::getLikedNews получаем список id новостей, которые лайкнул текущий пользователь. Далее js-ом меняем цвет и надпись кнопок. js обработчик и ajax-обработчик лайка остаются такими-же, как в предыдущем варианте.
4) Посмотреть, как реализованы лайки в forum.topic.list
Гнидий Вадим, классы-хелперы можно положить в папку local/php_interface/classes , например http://prntscr.com/jqy9rx , имя файла должно совпадать с именем класса . А в local/php_interface/init.php нужно положить автозагрузчик :
Доброго времени суток. Я новичок в работе с Битриксом. Есть задача реализовать возможность оценивать (лайки/дизлайки) книги на корпоративном сайте в разделе корп.библиотека. Как я понимаю, Ваш код содержит настройку данного функционала для элементов инфоблока, но сама статья не про это. Скажите, пожалуйста, что нужно сделать, чтобы добавить данный функционал к элементам инфоблока?
внимательно смотрите код прежде чем писать что ниче не работает. Автор сам не очень понял что создал. Суть в том, что если в скидке четко выделяется id товара (ВНИМАНИЕ) по одному из условий - тогда да, код имеет место быть. Если же применение скидки идёт по, например, значению свойсвта - код НЕ будет работать
Привет всем , кто подскажет как создать новый тип свойства для РАЗДЕЛА инфоблока, чтобы в нем отображался список из свойств этого или другого ИБ Нужен код Заранее спасибо
А остальные наверняка заметили, что в стандартной поставке есть пользовательское поле для установки связи с секциями инфоблоков, но нет пользовательских полей для установки связи с элементами инфоблоков, а они бывают нужны. Давайте добавим их сами.
Итак, два варианта добавления этих типов полей: 1. Сокращенный вариант, без поддержки публичной части. Просто скопируйте приведенный ниже код в файл /bitrix/php_interface/init.php
2. Полный вариант, с поддержкой публичной части. Скачайте и распакуйте архив. Содержимое соответствующих папок архива скопируйте на сайт. Для сайта в кодировке UTF-8 нужно копировать файлы, содержащиеся в директории "utf8" архива, для сайта в кодировке Windows-1251 - в директории "windows1251". И, наконец, в файл /bitrix/php_interface/init.php добавьте код подключения скриптов пользовательских полей:
Код пользовательского свойства главного модуля "Связь с элементом":
// Регистрируем обработчик события главного модуля OnUserTypeBuildList
// Событие создается при построении списка типов пользовательских свойств
AddEventHandler('main', 'OnUserTypeBuildList', array('CUserTypeIBlockElement', 'GetUserTypeDescription'), 5000);
class CUserTypeIBlockElement {
// ---------------------------------------------------------------------
// Общие параметры методов класса:
// @param array $arUserField - метаданные (настройки) свойства
// @param array $arHtmlControl - массив управления из формы (значения свойств, имена полей веб-форм и т.п.)
// ---------------------------------------------------------------------
// Функция регистрируется в качестве обработчика события OnUserTypeBuildList
function GetUserTypeDescription() {
return array(
// уникальный идентификатор
'USER_TYPE_ID' => 'iblock_element',
// имя класса, методы которого формируют поведение типа
'CLASS_NAME' => 'CUserTypeIBlockElement',
// название для показа в списке типов пользовательских свойств
'DESCRIPTION' => 'Связь с элементами инфоблока',
// базовый тип на котором будут основаны операции фильтра
'BASE_TYPE' => 'int',
);
}
// Функция вызывается при добавлении нового свойства
// для конструирования SQL запроса создания столбца значений свойства
// @return string - SQL
function GetDBColumnType($arUserField) {
switch(strtolower($GLOBALS['DB']->type)) {
case 'mysql':
return 'int(18)';
break;
case 'oracle':
return 'number(18)';
break;
case 'mssql':
return "int";
break;
}
}
// Функция вызывается перед сохранением метаданных (настроек) свойства в БД
// @return array - массив уникальных метаданных для свойства, будет сериализован и сохранен в БД
function PrepareSettings($arUserField) {
// инфоблок, с элементами которого будет выполняться связь
$iIBlockId = intval($arUserField['SETTINGS']['IBLOCK_ID']);
return array(
'IBLOCK_ID' => $iIBlockId > 0 ? $iIBlockId : 0
);
}
// Функция вызывается при выводе формы метаданных (настроек) свойства
// @param bool $bVarsFromForm - флаг отправки формы
// @return string - HTML для вывода
function GetSettingsHTML($arUserField = false, $arHtmlControl, $bVarsFromForm) {
$result = '';
// добавлено 2010-12-08 (YYYY-MM-DD)
if(!CModule::IncludeModule('iblock')) {
return $result;
}
// текущие значения настроек
if($bVarsFromForm) {
$value = $GLOBALS[$arHtmlControl['NAME']]['IBLOCK_ID'];
} elseif(is_array($arUserField)) {
$value = $arUserField['SETTINGS']['IBLOCK_ID'];
} else {
$value = '';
}
// выведем выпадающий список выбора связываемого инфоблока
$result .= '
<tr style="vertical-align: top;">
<td>Информационный блок по умолчанию:</td>
<td>
'.GetIBlockDropDownList($value, $arHtmlControl['NAME'].'[IBLOCK_TYPE_ID]', $arHtmlControl['NAME'].'[IBLOCK_ID]').'
</td>
</tr>
';
return $result;
}
// Функция валидатор значений свойства
// вызвается в $GLOBALS['USER_FIELD_MANAGER']->CheckField() при добавлении/изменении
// @param array $value значение для проверки на валидность
// @return array массив массивов ("id","text") ошибок
function CheckFields($arUserField, $value) {
$aMsg = array();
return $aMsg;
}
// Функция вызывается при выводе формы редактирования значения свойства
// @return string - HTML для вывода
function GetEditFormHTML($arUserField, $arHtmlControl) {
$iIBlockId = intval($arUserField['SETTINGS']['IBLOCK_ID']);
$sReturn = '';
// получим элементы инфоблока по значению свойства, передаваемым в $arHtmlControl['VALUE']
$arElements = CUserTypeIBlockElement::_getElements($arHtmlControl['VALUE']);
// html поля веб-формы для текущего значения
$sReturn .= '<div>'.CUserTypeIBlockElement::_getItemFieldHTML($arHtmlControl['VALUE'], $iIBlockId, $arElements, $arHtmlControl['NAME']).'</div>';
return $sReturn;
}
// Функция вызывается при выводе формы редактирования значения множественного свойства
// @return string - HTML для вывода
function GetEditFormHTMLMulty($arUserField, $arHtmlControl) {
$iIBlockId = intval($arUserField['SETTINGS']['IBLOCK_ID']);
// получим элементы инфоблока по значениям свойства, передаваемым в массиве значений $arHtmlControl['VALUE']
$arElements = CUserTypeIBlockElement::_getElements($arHtmlControl['VALUE']);
$sReturn = '<table cellspacing="0" id="tb'.md5($arHtmlControl['NAME']).'">';
// html поля веб-формы для каждого значения свойства
foreach($arHtmlControl['VALUE'] as $iKey => $iValue) {
$sReturn .= '<tr><td><div>'.CUserTypeIBlockElement::_getItemFieldHTML($iValue, $iIBlockId, $arElements, $arHtmlControl['NAME']).'</div></td></tr>';
}
// html поля веб-формы для добавления нового значения свойства
$sReturn .= '<tr><td><div>'.CUserTypeIBlockElement::_getItemFieldHTML(0, $iIBlockId, array(), $arHtmlControl['NAME']).'</div></td></tr>';
// html полей для кнопки Добавить... (режим множественного выбора элементов)
$sReturn .= '<tr><td><div>'.CUserTypeIBlockElement::_getItemFieldHTML(0, $iIBlockId, array(), $arHtmlControl['NAME'], 'y').'</div></td></tr>';
$sReturn .= '</table>';
return $sReturn;
}
// Функция вызывается при выводе фильтра на странице списка
// @return string - HTML для вывода
function GetFilterHTML($arUserField, $arHtmlControl) {
//$sVal = intval($arHtmlControl['VALUE']);
//$sVal = $sVal > 0 ? $sVal : '';
//return '<input type="text" name="'.$arHtmlControl['NAME'].'" size="20" value="'.$sVal.'" />';
return CUserTypeIBlockElement::GetEditFormHTML($arUserField, $arHtmlControl);
}
// Функция вызывается при выводе значения свойства в списке элементов
// @return string - HTML для вывода
function GetAdminListViewHTML($arUserField, $arHtmlControl) {
$iElementId = intval($arHtmlControl['VALUE']);
if($iElementId > 0) {
$arElements = CUserTypeIBlockElement::_getElements($iElementId);
// выводим в формате: [ID элемента] имя элемента (если найдено)
return '['.$iElementId.'] '.(isset($arElements[$iElementId]) ? $arElements[$iElementId]['NAME'] : '');
} else {
return ' ';
}
}
// Функция вызывается при выводе значения множественного свойства в списке элементов
// @return string - HTML для вывода
function GetAdminListViewHTMLMulty($arUserField, $arHtmlControl) {
$sReturn = '';
static $bWasJs = false;
// костыль для добавления js-функции, отвечающей за добавление новых полей значения множественного свойства
// т.к. в режиме массового редактирования значений свойства из-за ajax изменяется область видимости функций js
// добавляется один раз на странице
if(!$bWasJs) {
$bWasJs = true;
// здесь пляски с бубном из-за гениальности передачи данных
// из попап-окна /bitrix/admin/iblock_element_search.php на вызывающую страницу
ob_start();
?><script type="text/javascript">
var oIBListUF = {
oCounter: {},
addNewRowIBListUF: function(mFieldCounterName, sTableId, sFieldName, sOpenWindowUrl, sSpanId) {
var oTbl = document.getElementById(sTableId);
var oRow = oTbl.insertRow(oTbl.rows.length-1);
var oCell = oRow.insertCell(-1);
if(!this.oCounter.mFieldCounterName) {
this.oCounter.mFieldCounterName = 0;
}
var sK = 'n'+this.oCounter.mFieldCounterName;
this.oCounter.mFieldCounterName = parseInt(this.oCounter.mFieldCounterName) + 1;
sOpenWindowUrl += '&k='+sK;
sSpanId += '_'+sK;
oCell.innerHTML = '<input type="text" id="'+sFieldName+'['+sK+']" name="'+sFieldName+'['+sK+']" value="" size="5" />';
oCell.innerHTML += '<input type="button" value="..." onclick="jsUtils.OpenWindow(\''+sOpenWindowUrl+'\', 600, 500);" />';
oCell.innerHTML += ' <span id="'+sSpanId+'"></span>';
}
};
</script><?
$sReturn .= ob_get_clean();
}
if(!empty($arHtmlControl['VALUE']) && is_array($arHtmlControl['VALUE'])) {
$arElements = CUserTypeIBlockElement::_getElements($arHtmlControl['VALUE']);
$arPrint = array();
// выводим в формате: [ID элемента] имя элемента (если найдено) с разделителем " / " для каждого значения
foreach($arHtmlControl['VALUE'] as $iElementId) {
$arPrint[] = '['.$iElementId.'] '.(isset($arElements[$iElementId]) ? $arElements[$iElementId]['NAME'] : '');
}
$sReturn .= implode(' / ', $arPrint);
} else {
$sReturn .= ' ';
}
return $sReturn;
}
// Функция вызывается при выводе значения свойства в списке элементов в режиме редактирования
// @return string - HTML для вывода
function GetAdminListEditHTML($arUserField, $arHtmlControl) {
return CUserTypeIBlockElement::GetEditFormHTML($arUserField, $arHtmlControl);
}
// Функция вызывается при выводе множественного значения свойства в списке элементов в режиме редактирования
// @return string - HTML для вывода
function GetAdminListEditHTMLMulty($arUserField, $arHtmlControl) {
$iIBlockId = intval($arUserField['SETTINGS']['IBLOCK_ID']);
$arElements = CUserTypeIBlockElement::_getElements($arHtmlControl['VALUE']);
// поля редактирования значений свойства
$sTableId = 'tb'.md5($arHtmlControl['NAME']);
$sReturn = '<table cellspacing="0" id="'.$sTableId.'">';
foreach($arHtmlControl['VALUE'] as $iKey => $iValue) {
$sReturn .= '<tr><td><div>'.CUserTypeIBlockElement::_getItemFieldHTML($iValue, $iIBlockId, $arElements, $arHtmlControl['NAME']).'</div></td></tr>';
}
// поле добавления нового значения свойства
$sReturn .= '<tr><td><div>'.CUserTypeIBlockElement::_getItemFieldHTML(0, $iIBlockId, array(), $arHtmlControl['NAME']).'</div></td></tr>';
// кнопка Добавить... (вызывает js-функцию, которая была добавлена методом GetAdminListViewHTMLMulty)
$sFieldName_ = str_replace('[]', '', $arHtmlControl['NAME']);
$mFieldCounterName = md5($sFieldName_);
$sOpenWindowUrl = '/bitrix/admin/iblock_element_search.php?lang='.LANG.'&IBLOCK_ID='.$iIBlockId.'&n='.$sFieldName_.'&m=n';
$sSpanId = 'sp_'.$mFieldCounterName;
$sReturn .= '<tr><td><div><input type="button" onclick="oIBListUF.addNewRowIBListUF(\''.$mFieldCounterName.'\', \''.$sTableId.'\', \''.$sFieldName_.'\', \''.$sOpenWindowUrl.'\', \''.$sSpanId.'\')" value="Добавить" /></div></td></tr>';
$sReturn .= '</table>';
return $sReturn;
}
// Функция должна вернуть представление значения поля для поиска
// @return string - посковое содержимое
function OnSearchIndex($arUserField) {
if(is_array($arUserField['VALUE'])) {
return implode("\r\n", $arUserField['VALUE']);
} else {
return $arUserField['VALUE'];
}
}
// Функция вызывается перед сохранением значений в БД
// @param mixed $value - значение свойства
// @return string - значение для вставки в БД
function OnBeforeSave($arUserField, $value) {
if(intval($value) > 0) {
return intval($value);
}
}
// Функция генерации html для поля редактирования свойства
// @param int $iValue - значение свойства
// @param int $iIBlockId - ID информационного блока для поиска элементов по умолчанию
// @param array $arElements - массив элементов инфоблока с ключами = идентификаторам элементов инфоблока
// @param string $sFieldName - имя для поля веб-формы
// @param string $sMulty - n|y - поэлементная (n) или множественная вставка значений
// @return string - HTML для вывода
// @private
function _getItemFieldHTML($iValue, $iIBlockId, $arElements, $sFieldName, $sMulty = 'n') {
$sReturn = '';
$iValue = intval($iValue);
$sKey = randstring(3);
$sName = 'UF_IBELEMENT_'.randstring(3);
$sRandId = $sName.'_'.$sKey;
$sElementName = '';
if(!empty($arElements[$iValue])) {
$sElementName = '<a href="'.BX_PERSONAL_ROOT.'/admin/iblock_element_edit.php?ID='.$arElements[$iValue]['ID'].'&type='.$arElements[$iValue]['IBLOCK_TYPE_ID'].'&lang='.LANG.'&IBLOCK_ID='.$arElements[$iValue]['IBLOCK_ID'].'&find_section_section=-1">'.$arElements[$iValue]['NAME'].'</a>';
}
$md5Name = md5($sName);
$sValue = $iValue > 0 ? $iValue : '';
$sButtonValue = $sMulty == 'y' ? 'Добавить ...' : '...';
$sReturn .= '<input type="text" name="'.$sFieldName.'" id="'.$sName.'" value="'.$sValue.'" size="5" />';
$sReturn .= '<input type="button" value="'.$sButtonValue.'" onclick="jsUtils.OpenWindow(\'/bitrix/admin/iblock_element_search.php?lang='.LANG.'&IBLOCK_ID='.$iIBlockId.'&n='.$sName.'&m='.$sMulty.'&k='.$sKey.'\', 600, 500);" />';
$sReturn .= ' <span id="sp_'.$md5Name.'_'.$sKey.'" >'.$sElementName.'</span>';
if($sMulty == 'y') {
$sJsMV = 'MV_'.$md5Name;
// уберем пустые скобки
$sFieldName_ = str_replace('[]', '', $sFieldName);
$sJsFuncName = 'InS'.$md5Name;
ob_start();
?><script type="text/javascript">
var <?=$sJsMV?> = 0;
var <?=$sJsFuncName?> = function(sId, sName) {
var oTbl = document.getElementById('tb<?=md5($sFieldName)?>');
var oRow = oTbl.insertRow(oTbl.rows.length-1);
var oCell = oRow.insertCell(-1);
var sK = 'n'+<?=$sJsMV?>;
oCell.innerHTML = '<input type="text" id="<?=$sFieldName_?>['+sK+']" name="<?=$sFieldName_?>['+sK+']" value="'+sId+'" size="5" />';
oCell.innerHTML += '<input type="button" value="..." onclick="jsUtils.OpenWindow(\'/bitrix/admin/iblock_element_search.php?lang=<?=LANG?>&IBLOCK_ID=<?=$iIBlockId?>&n=<?=$sFieldName_?>&k='+sK+'\', 600, 500);" />';
oCell.innerHTML += ' <span id="sp_<?=md5($sFieldName_)?>_'+<?=sK?>+'">'+sName+'</span>';
<?=$sJsMV?>++;
};
</script><?
$sReturn .= ob_get_clean();
}
return $sReturn;
}
// Функция генерации массива элементов по значениям свойства
// @param mixed $mElementId - значение свойства (массив или целое число)
// @return array - массив элементов инфоблока с ключами = идентификаторам элементов инфоблока
// @private
function _getElements($mElementId = array()) {
$arReturn = array();
if(!empty($mElementId)) {
// добавлено 2010-12-08 (YYYY-MM-DD)
if(!CModule::IncludeModule('iblock')) {
return $arReturn;
}
$arFilter = array(
'ID' => array()
);
$mElementId = is_array($mElementId) ? $mElementId : array($mElementId);
foreach($mElementId as $iValue) {
$iValue = intval($iValue);
if($iValue > 0) {
$arFilter['ID'][] = $iValue;
}
}
if(!empty($arFilter['ID'])) {
$arSelect = array(
'ID',
'NAME',
'IBLOCK_ID',
'IBLOCK_TYPE_ID'
);
$rsItems = CIBlockElement::GetList(array(), $arFilter, false, false, $arSelect);
while($arItem = $rsItems->GetNext(false, false)) {
$arReturn[$arItem['ID']] = $arItem;
}
}
}
return $arReturn;
}
}
Код пользовательского свойства главного модуля "Связь с элементом в виде списка":
// Регистрируем обработчик события главного модуля OnUserTypeBuildList
// Событие создается при построении списка типов пользовательских свойств
AddEventHandler('main', 'OnUserTypeBuildList', array('CUserTypeIBlockElementList', 'GetUserTypeDescription'), 5000);
class CUserTypeIBlockElementList {
// ---------------------------------------------------------------------
// Общие параметры методов класса:
// @param array $arUserField - метаданные (настройки) свойства
// @param array $arHtmlControl - массив управления из формы (значения свойств, имена полей веб-форм и т.п.)
// ---------------------------------------------------------------------
// Функция регистрируется в качестве обработчика события OnUserTypeBuildList
function GetUserTypeDescription() {
return array(
// уникальный идентификатор
'USER_TYPE_ID' => 'iblock_element_list',
// имя класса, методы которого формируют поведение типа
'CLASS_NAME' => 'CUserTypeIBlockElementList',
// название для показа в списке типов пользовательских свойств
'DESCRIPTION' => 'Связь с элементами инфоблока в виде списка',
// базовый тип на котором будут основаны операции фильтра
'BASE_TYPE' => 'int',
);
}
// Функция вызывается при добавлении нового свойства
// для конструирования SQL запроса создания столбца значений свойства
// @return string - SQL
function GetDBColumnType($arUserField) {
switch(strtolower($GLOBALS['DB']->type)) {
case 'mysql':
return 'int(18)';
break;
case 'oracle':
return 'number(18)';
break;
case 'mssql':
return "int";
break;
}
}
// Функция вызывается перед сохранением метаданных (настроек) свойства в БД
// @return array - массив уникальных метаданных для свойства, будет сериализован и сохранен в БД
function PrepareSettings($arUserField) {
// инфоблок, с элементами которого будет выполняться связь
$iIBlockId = intval($arUserField['SETTINGS']['IBLOCK_ID']);
return array(
'IBLOCK_ID' => $iIBlockId > 0 ? $iIBlockId : 0
);
}
// Функция вызывается при выводе формы метаданных (настроек) свойства
// @param bool $bVarsFromForm - флаг отправки формы
// @return string - HTML для вывода
function GetSettingsHTML($arUserField = false, $arHtmlControl, $bVarsFromForm) {
$result = '';
// добавлено 2010-12-08 (YYYY-MM-DD)
if(!CModule::IncludeModule('iblock')) {
return $result;
}
// текущие значения настроек
if($bVarsFromForm) {
$value = $GLOBALS[$arHtmlControl['NAME']]['IBLOCK_ID'];
} elseif(is_array($arUserField)) {
$value = $arUserField['SETTINGS']['IBLOCK_ID'];
} else {
$value = '';
}
$result .= '
<tr style="vertical-align: top;">
<td>Информационный блок по умолчанию:</td>
<td>
'.GetIBlockDropDownList($value, $arHtmlControl['NAME'].'[IBLOCK_TYPE_ID]', $arHtmlControl['NAME'].'[IBLOCK_ID]').'
</td>
</tr>
';
return $result;
}
// Функция валидатор значений свойства
// вызвается в $GLOBALS['USER_FIELD_MANAGER']->CheckField() при добавлении/изменении
// @param array $value значение для проверки на валидность
// @return array массив массивов ("id","text") ошибок
function CheckFields($arUserField, $value) {
$aMsg = array();
return $aMsg;
}
// Функция вызывается при выводе формы редактирования значения свойства
// она же вызывается (в цикле) и при выводе формы редактирования множественного свойства
// @return string - HTML для вывода
function GetEditFormHTML($arUserField, $arHtmlControl) {
$iIBlockId = intval($arUserField['SETTINGS']['IBLOCK_ID']);
$sReturn = '';
$sReturn .= '<div>'.CUserTypeIBlockElementList::_getItemFieldHTML($arHtmlControl['VALUE'], $iIBlockId, $arHtmlControl['NAME']).'</div>';
return $sReturn;
}
// Функция вызывается при выводе фильтра на странице списка
// @return string - HTML для вывода
function GetFilterHTML($arUserField, $arHtmlControl) {
//$sVal = intval($arHtmlControl['VALUE']);
//$sVal = $sVal > 0 ? $sVal : '';
//return '<input type="text" name="'.$arHtmlControl['NAME'].'" size="20" value="'.$sVal.'" />';
return CUserTypeIBlockElementList::GetEditFormHTML($arUserField, $arHtmlControl);
}
// Функция вызывается при выводе значения свойства в списке элементов
// @return string - HTML для вывода
function GetAdminListViewHTML($arUserField, $arHtmlControl) {
$iElementId = intval($arHtmlControl['VALUE']);
if($iElementId > 0) {
$arElements = CUserTypeIBlockElementList::_getElements($arUserField['SETTINGS']['IBLOCK_ID']);
// выводим в формате: [ID элемента] имя элемента (если найдено)
return '['.$iElementId.'] '.(isset($arElements[$iElementId]) ? $arElements[$iElementId]['NAME'] : '');
} else {
return ' ';
}
}
// Функция вызывается при выводе значения множественного свойства в списке элементов
// @return string - HTML для вывода
function GetAdminListViewHTMLMulty($arUserField, $arHtmlControl) {
$sReturn = '';
if(!empty($arHtmlControl['VALUE']) && is_array($arHtmlControl['VALUE'])) {
$arElements = CUserTypeIBlockElementList::_getElements($arUserField['SETTINGS']['IBLOCK_ID']);
$arPrint = array();
// выводим в формате: [ID элемента] имя элемента (если найдено) с разделителем " / " для каждого значения
foreach($arHtmlControl['VALUE'] as $iElementId) {
$arPrint[] = '['.$iElementId.'] '.(isset($arElements[$iElementId]) ? $arElements[$iElementId]['NAME'] : '');
}
$sReturn .= implode(' / ', $arPrint);
} else {
$sReturn .= ' ';
}
return $sReturn;
}
// Функция вызывается при выводе значения свойства в списке элементов в режиме редактирования
// она же вызывается (в цикле) и для множественного свойства
// @return string - HTML для вывода
function GetAdminListEditHTML($arUserField, $arHtmlControl) {
return CUserTypeIBlockElementList::GetEditFormHTML($arUserField, $arHtmlControl);
}
// Функция должна вернуть представление значения поля для поиска
// @return string - посковое содержимое
function OnSearchIndex($arUserField) {
if(is_array($arUserField['VALUE'])) {
return implode("\r\n", $arUserField['VALUE']);
} else {
return $arUserField['VALUE'];
}
}
// Функция вызывается перед сохранением значений в БД
// @param mixed $value - значение свойства
// @return string - значение для вставки в БД
function OnBeforeSave($arUserField, $value) {
if(intval($value) > 0) {
return intval($value);
}
}
// Функция генерации html для поля редактирования свойства
// @param int $iValue - значение свойства
// @param int $iIBlockId - ID информационного блока для поиска элементов
// @param string $sFieldName - имя для поля веб-формы
// @return string - HTML для вывода
// @private
function _getItemFieldHTML($iValue, $iIBlockId, $sFieldName) {
$sReturn = '';
// получим массив всех элементов инфоблока
$arElements = CUserTypeIBlockElementList::_getElements($iIBlockId);
$sReturn = '<select size="1" name="'.$sFieldName.'">
<option value=""> </option>';
foreach($arElements as $arItem) {
$sReturn .= '<option value="'.$arItem['ID'].'"';
if($iValue == $arItem['ID']) {
$sReturn .= ' selected="selected"';
}
$sReturn .= '>'.$arItem['NAME'].'</option>';
}
$sReturn .= '</select>';
return $sReturn;
}
// Функция генерации массива элементов тнфоблока
// @param int $iIBlockId - ID информационного блока для поиска элементов
// @param bool $bResetCache - перезаписать "виртуальный кэш" для инфоблока
// @return array - массив элементов инфоблока с ключами = идентификаторам элементов инфоблока
// @private
function _getElements($iIBlockId = false, $bResetCache = false) {
static $arVirtualCache = array();
$arReturn = array();
$iIBlockId = intval($iIBlockId);
if(!isset($arVirtualCache[$iIBlockId]) || $bResetCache) {
// добавлено 2010-12-08 (YYYY-MM-DD)
if(!CModule::IncludeModule('iblock')) {
return $arReturn;
}
if($iIBlockId > 0) {
$arFilter = array(
'IBLOCK_ID' => $iIBlockId
);
$arSelect = array(
'ID',
'NAME',
'IBLOCK_ID',
'IBLOCK_TYPE_ID'
);
$rsItems = CIBlockElement::GetList(array(), $arFilter, false, false, $arSelect);
while($arItem = $rsItems->GetNext(false, false)) {
// добавлено 2011-02-15 для GetList
$arItem['VALUE'] = $arItem['NAME'];
$arReturn[$arItem['ID']] = $arItem;
}
}
$arVirtualCache[$iIBlockId] = $arReturn;
} else {
$arReturn = $arVirtualCache[$iIBlockId];
}
return $arReturn;
}
// добавлено 2011-02-15
function GetList($arUserField) {
$dbReturn = new CDBResult;
$arElements = self::_getElements($arUserField['SETTINGS']['IBLOCK_ID']);
$dbReturn->InitFromArray($arElements);
return $dbReturn;
}
}
Как это будет выглядеть.
Список доступных типов свойств на странице редактирования пользовательского поля (красным выделены наши новые типы):
Пример добавления пользовательского поля привязки к элементам инфоблока в виде списка. Поле это будет принадлежать секции выбранного инфоблока:
На этом скриншоте показаны уже добавленные три пользовательских поля для секции инфоблока:
Поле "Руководители" - множественная связь с элементами в виде списка Поле "Места проведения" - простая связь с элементами Поле "Категории участников" - множественная связь с элементами
Процесс добавления множественной связи с элементами:
Процесс группового редактирования секций инфоблока и пользовательских полей:
На скриншоте также продемонстрированы и фильтры для данных типов полей.
---- Update (08.12.2010): в методах GetSettingsHTML() и _getElements() классов пользовательских типов добавлено подключение модуля информационных блоков.
---- Update (15.02.2011): - добавлен метод CUserTypeIBlockElementList::GetList(); - добавлены шаблоны iblock_element и iblock_element_list для компонентов bitrix:system.field.edit и system.field.view. Теперь пользовательские поля доступны для вывода и редактирования в публичной части. Шаблоны находятся в архиве для скачивания.
была у меня в закладках хорошая статейка, а щас вот открыл - а ее нет:( хорошо, хоть у гугла есть сохраненная копия страницы. автор, простите за репост без подписи ...
В веб-окружении Битрикса по-умолчанию стоит msmtp для отправки писем. Если ваш домен привязан к Яндекс.Почте для домена, и вы хотите отправлять почту через реально существующий почтовый ящик с авторизацией, вам придётся внести в файл конфигурации некоторые изменения, чтобы всё работало хорошо.
Файл /home/bitrix/.msmtprc:
account default
logfile /var/log/msmtp.log
host smtp.yandex.ru #(smtp.gmail.com - для гугла) #
port 587 # именно этот порт! #lkz гугля рекомендуют ставить 465, хотя в просторах сети читал, что и 587 подходит ...#
from robot@domain.ru
keepbcc on
auth on
user robot@domain.ru
password <password>
tls on
tls_starttls on # обязательно для Яндекс.ПДД
tls_certcheck off
И не задавайте слишком длинных паролей.
P.S: при работе с GMail вторую строку (tls_starttls) наоборот включать не нужно.
UPDATE 2014-09-08
полный файлик с настройками для gmail:
account default
logfile /var/log/msmtp.log
host smtp.gmail.com
port 587
from user@gmail.com
auth on
user user@gmail.com
password password
tls on
tls_starttls on
tls_certcheck off
keepbcc on
для корректности настройки можно выполнить из сервера команду:
php -r "mail('test@email.com', 'Test', 'Test');"
UPDATE 2014-12-02
Для проверки из сайта, в командную строку можно ввести код:
if (mail("moe_mylo@gmail.com","test subject", "test body","From: otpravitel@bitrix.ru"))
echo "Сообщение передано функции mail, проверьте почту в ящике.";
else
echo "Функция mail не работает, свяжитесь с администрацией хостинга.";
Только email-адресы ставьте ваши
P.P.P.S Перенес инструкцию (вместе с дополнениями) себе на сайт
Настроил через сервер smtp.yandex.ru, почта уходит но почему то если приходит на gmail то попадает в спам, а отправителем стоит EMPTY-FROM конфиг такой
# smtp account configuration for default
account default
logfile /home/bitrix/msmtp_default.log
host smtp.yandex.ru
port 587
from simple@yandex.ru
keepbcc on
auth on
user simple@yandex.ru
password XXXXXXXXX
tls on
tls_starttls on
tls_certcheck off
Если у вас на сайте есть панелька, которая должна фиксироваться в верху сайта, то скорее всего в режиме редактирования она закрывает (или закрывается) панелькой админки битрикса.
Вот маленький js скрипт способный решить указанную проблему (используем только BitrixJS )
shef-panel - ID Вашей панельки
Переменные
minTop = '40px' - высота панельки Битрикса, когда она свернута
maxTop = '147px'; - высота панельки Битрикса, когда она развернута
Эти значения будут добавлены в style.top вашей панельки
Добрый день! Я только начал разрабатывать на битрикс и уперся в ShowPanel, закрывающую часть страницы Ваши решения не срабатывают, помогите разобраться, не хочется решать проблему margin и тп
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».