Свой тип свойства инфоблока - Таблицы, Сохранение значений полей нескольких таблиц в одном свойстве элемента инфоблока. Возможность правки отдельных полей таблицы из общего свойства
Всем привет! Недавно столкнулся с такой задачей: Необходимо было добавлять по 4е таблицы для элементов ифоблока (Документов). Ну как обычно решил добавить дополнительное свойство к инфоблоку. Выбрал оптимальный тип свойства инфоблока - HTML/текст. Из минусов: - приходилось каждый раз копировать код одной и той же таблицы (шапка, структура, и т.п.) - тому кто будет наполнять эти таблицы необходимо знать верстку таблиц - неудобно редактировать поля - что делать если нужно добавить дополнительное поле/строку для таблицы?
Вообщем решил, что это очень неудобный механизм наполнения информацией элементов. А создавать отдельное свойство под каждое поле таблицы - тоже не выход.
Создал свой тип свойства инфоблока - Таблицы. Что он нам дает? - задать неограниченное количество таблиц с разным количеством столбцов и строк для каждой таблицы - возможность задавать разное количество строк таблиц для каждого элемента ифоблока по отдельности - удобство редактирования каждого поля таблицы (нет необходимости знать верстку таблицы) - а самое главное, значения всех этих таблиц записываются в одно свойство в виде сериализованного массива.
Что для этого необходимо? 1) Создать обработчик событий OnIBlockPropertyBuildList со своим типом свойства ифоблока: Для этого прописываем в файле /bitrix/php_interface/init.php следующий код:
Код
<?
//тип свойства "Таблицы" для инфоблока
AddEventHandler('iblock', 'OnIBlockPropertyBuildList', array('IdListDoc', 'GetUserTypeDescription')); //построение списка свойств инфоблока
class IdListDoc
{
//шапка таблицы
public function getHeaderTable(){
$arHeaderTable = array();
$arHeaderTable['tbl-1']['header'][] = '<table id="tbl-1" class="identific_doc"> <tr class="id_h"> <td>Название документа</td> <td>Код документа</td> <td>Дата создания</td> <td>Подразделение</td> <td>Действие регламентного документа распространяется на подразделения</td> </tr>'; //шапка таблицы 1
$arHeaderTable['tbl-2']['header'][] = '<table id="tbl-2" class="identific_doc"> <tr class="id_h"> <td>Разработчик</td> <td>Должность</td> <td>Ф.И.О.</td> <td>Внутренний телефон</td> </tr>'; //шапка таблицы 2
$arHeaderTable['tbl-3']['header'][] = '<table id="tbl-3" class="identific_doc"> <tr class="id_h"> <td>История документа</td> <td>Версия документа</td> <td>Дата последнего изменения версии</td> <td>Описание</td> </tr>'; //шапка таблицы 3
$arHeaderTable['tbl-4']['header'][] = '<table id="tbl-4" class="identific_doc"> <tr class="id_h"> <td>№</td> <td>Подразделение</td> <td>Должность</td> </tr>'; //шапка таблицы 4
$arHeaderTable['tbl-1']['cols'] = 5; //количество столбцов, 4 - по умолчанию
$arHeaderTable['tbl-1']['textarea'][4] = 'Y';
$arHeaderTable['tbl-4']['textarea'][1] = 'Y';
$arHeaderTable['tbl-4']['textarea'][2] = 'Y';
$arHeaderTable['tbl-4']['cols'] = 3;
return $arHeaderTable;
}
function GetUserTypeDescription()
{
return array(
"PROPERTY_TYPE" => "S",
"USER_TYPE" => "custom_table",
"DESCRIPTION" => 'Таблицы',
"GetPublicViewHTML" => array("IdListDoc","GetPublicViewHTML"),
"GetAdminListViewHTML" => array("IdListDoc","GetAdminListViewHTML"),
"GetPropertyFieldHtml" => array("IdListDoc","GetPropertyFieldHtml"),
"ConvertToDB" => array("IdListDoc","ConvertToDB"),
"ConvertFromDB" => array("IdListDoc","ConvertFromDB"),
);
}
//отображение таблиц на странице
function GetPublicViewHTML($arProperty, $value, $strHTMLControlName)
{
return self::ShowTable(self::BuildTable($value['VALUE'])); //построение таблицы (построение структуры таблицы)
}
function GetAdminListViewHTML($arProperty, $value, $strHTMLControlName)
{
return;
}
//отображение формы редактирования в админке и в режиме правки
function GetPropertyFieldHtml($arProperty, $value, $strHTMLControlName)
{
$arTable = self::BuildTable($value['VALUE']); //получаем структуру таблицы
ob_start();
?>
<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript" src="/js/functions.js"></script>
<link rel="stylesheet" href="/bitrix/components/sbb/main.interface.form/templates/.default/style.css">
<link rel="stylesheet" href="/css/IdListDoc.css">
<div class="edit_identific_doc">
<?
foreach($arTable as $table_name => $ar_table){
if(!empty($arTable[$table_name]['header'][0]) && is_array($arTable[$table_name]['body'])){ //если установлены шапка таблицы
//шапка таблицы
foreach($arTable[$table_name]['header'] as $header){ echo $header; }
//содержание таблицы
...
...
...
//футер таблицы
echo '</table>';
?>
<p class="mngnt"><input type="button" value="Добавить строку" OnClick="addRow('<?=$table_name;?>', '<?=$arProperty['ID']?>'); return false;"> <input type="button" value="Удалить строку" OnClick="removeRow('<?=$table_name;?>'); return false;"></p>
<?
}
}
?>
</div>
<?
$return = ob_get_contents();
ob_end_clean();
return $return;
}
//Сохранение в БД
function ConvertToDB($arProperty, $value)
{
$return = false;
if(is_array($value)&& array_key_exists("VALUE", $value))
{
$return = array("VALUE" => serialize($value["VALUE"]),);
if(strlen(trim($value["DESCRIPTION"])) > 0)$return["DESCRIPTION"] = trim($value["DESCRIPTION"]);
}
return $return;
}
//Извлечение из БД
function ConvertFromDB($arProperty, $value)
{
$return = false;
if(!is_array($value["VALUE"]))
{
$return = array("VALUE" => unserialize($value["VALUE"]),);
if($value["DESCRIPTION"])$return["DESCRIPTION"] = trim($value["DESCRIPTION"]);
}
return $return;
}
//построение структуры таблиц (шапка + содержание)
function BuildTable($arBodyTable){
$arTable = self::getHeaderTable(); //шапка таблиц
$arTable = //содержание таблиц данные из БД
if(is_array($arBodyTable)){ //содержание таблиц данные из БД
foreach($arTable as $TABLE_NAME => $SET_TABLE){
...
...
...
}
}else{ //заполняем данныу по дефолту
...
...
...
}
return $arTable;
}
//показа таблиц с содержанием
function ShowTable($arTable){
$TableList = '';
foreach($arTable as $table_name => $ar_table){
if(!empty($arTable[$table_name]['header'][0]) && is_array($arTable[$table_name]['body'])){ //если установлены шапка таблицы
...
...
...
}
}
return $TableList;
}
//показа таблиц с содержанием по ID элементу
function ShowTableByEl($prID, $elID){
$TableList = '';
$qStruct = mysql_query("SELECT VALUE FROM `b_iblock_element_property` WHERE IBLOCK_PROPERTY_ID=".$prID." AND IBLOCK_ELEMENT_ID=".$elID." ");
if($rStruct = mysql_fetch_assoc($qStruct)){ if(!empty($rStruct['VALUE'])){ $TableList = self::ShowTable(self::BuildTable(unserialize($rStruct['VALUE'])));} }
return $TableList;
}
}
?>
задается шаблон (шапка) наших таблиц. Количество столбцов таблиц по умолчанию -4. Что бы указать свое значение, прописываем для нужно таблицы значение в массиве, например 3 столбца для 4ой таблицы $arHeaderTable['tbl-4']['cols'] = 3; Поля таблицы редактируются через <input type="text">. Что бы задать <textarea>, нужно добавить параметр в массив $arHeaderTable['tbl-4']['textarea'][1] = 'Y';, т.е. в 4ой таблице во втором поле будет поле <textarea> для редактирования (т.к. исчисление начинается с 0, 1, 2, 3 и т.д.)
JavaScript функции для кнопок "Добавить строку", "Удалить строку". Файл /js/functions.js
Код
//замена подстроки в строке
function str_replace(search, replace, subject) {
return subject.split(search).join(replace);
}
//добавление строки таблицы
function addRow(tID,prID){
var row = $('#' + tID + ' tr.' + tID + '-row');
if($(row).html()){
var previewRow = $(row).html();
var input_name = $(previewRow).find('input').attr('name');
var cnt = $('#'+tID+' tr').size() - 1;
previewRow = str_replace(input_name, 'PROP[' + prID + '][n0][' + tID + ']' + '[body][' + cnt + '][]', previewRow);
$('#'+tID).append('<tr>' + previewRow + '</tr>'); //добавляем новую строку таблицы
$('#'+tID+' tr:last input').each(function(){ this.value = ''; }); //обнуляем значения добавленных input_name
$('#'+tID+' tr:last textarea').each(function(){ this.value = ''; }); //обнуляем значения добавленных texarea
}else{
alert('Строка не найдена!');
}
}
//удаляем последнюю строку таблицы
function removeRow(tID){
if($('#'+tID+' tr').size() > 2){ //запрет на удаление последней строки
document.getElementById(tID).deleteRow(-1);
}
}
2) Добавить новое свойство для элементов инфоблока - Таблицы
3) Открыть на редактирование элемент инфоблока и заполнить созданные нами таблицы
4) Теперь можно посмотреть как будут выглядеть наши таблицы при выводе элемента через компонент (незабываем включить отображение созданного свойства "ID_LIST_DOC" )
Редактировать свойство "Таблицы" можно и в режиме правки.
Добавлять и удалять неограниченное количество строк для каждой таблицы по отдельности можно кнопками "Добавить строку" и "Удалить строку"
Если у Вас есть более оптимальный вариант, пишите, добавлю для своей задачи
Здорово, по-моему, и очень востребованно - в частности в интернет-магазинах одежды - там часто приходится где-то хранить разные размерные сетки для разных брендов. А вы не оформляли свое решение для маркетплейс?
Суперски можно сделать - вот загляните в маркетплейс http://marketplace.1c-bitrix.ru/ - там многие разработчики свои решения выкладывают. Можно делать, чтобы их бесплатно скачивали, можно чтобы покупали. А у вас решение классное - идея востребованная. Вот тут описаны условия размещения http://marketplace.1c-bitrix.ru/for-dev/
Вообще, если не разберетесь - можем вместе замутить - я умею оформлять под маркетплейс, но вот с такими прикольными идеями у меня туго, и мне жаль, что ваша может пропасть.
Для маркетплейса нужно стать партнёром битрикса. Сможете продавать подобные решения, если оформите соответствующим образом. Если хотите просто поделиться - лучше разместить в блог, там решение будет лучше заметно людям, тут потеряется.
В код и организацию не вникал, но думаю, подобное решение может быть достаточно востребованным.
Переделал данное решение в виде модуля. Протестировал на корпоративном портале (совместная работа), и на управление сайтом (Стандард). Модуль ставится и работает как нужно. Модуль размещу в маркетплейс, когда подтвердят мою регистрацию.
15.04.2013 14:32:57 я писал "Модуль размещу в маркетплейс, когда подтвердят мою регистрацию." Регистрация мою не подтвердили в маркетплейс, так как не являюсь ни юриком, ни ИП, а просто физ.лицо.
Добрый день! Денис, могу предложить разместить от имени нашей веб студии. все доходы (за вычетам налогов) готов перечислять вам(Естественно мы с Вами составим договор). Так же предоставлю вам доступ до моей партнерской программы , где вы будите видеть статистику по маркетплейсу. Я не хочу на этом заработать *(почти). я предлагаю партнерство - вам деньги , мне баллы (если вы не партнер то они вам все равно без надобности). НО основная идея- это помочь вам в размещении, а не получить каких нибудь 10 баллов - дороже возиться с налогами- кто знает , тот поймет.
Разработка, поддержка сайтов. Консультация по работе. От 950 руб/час. Sunweb.pro
R A, вот Вам и более универсальное решение!!! Какая разница корпортал это, либо управление сайтом, или еще какое то решение. Если изначально заложить УНИВЕРСАЛЬНУЮ логику, подстраивающуюся под свойства инфоблоков элементов, то оно и будет работать везде
Отправил повторно заявку на партнерство через организацию. Как будет готово, выложу свое решение в маркетплейс.