Разработка собственного источника данных списка

Разработка собственного источника данных для модуля "Универсальные свойства привязки" позволяет использовать свой список элементов в свойствах типа "Универсальная привязка", а также при использовании компонента "grain:links.edit" для замены html-тега "<select>" на динамический список. Разработка собственного источника данных оправдана в случае отсутствия необходимого источника среди стандартных источников, либо необходима их небольшая доработка.

При необходимости доработки стандартного источника, его нужно скопировать из папки с системными источниками в папку с пользовательскими источниками данных.

Папки системных источников данных находятся по следующему пути: /bitrix/modules/grain.links/lists
Папки пользовательских источников данных должны располагаться по следующему пути: /bitrix/php_interface/grain.links

Если при создании собственного источника данных папки с пользовательскими источниками не существует, то вы должны ее создать, а потом расположить в ней папку собственного источника. Если в папке и с пользовательскими источниками, и с системными, находятся 2 папки источников с одинаковым именем, предпочтение будет отдаваться пользовательскому источнику.

Системные источники изменять нельзя, т.к. изменения могут быть затерты при обновлении модуля.

Структура папки источника данных

Структура файлов источника данных списка аналогична структуре файлов компонентов битрикс, но гораздо проще и имеет всего 3 файла: .description.php, .parameters.php (необязательный) и основной файл источника - list.php.

Структура папки источника данных списка

Структура языковых файлов также аналогична компонентам битрикс, языковые файлы должны располагаться в подпапках lang/идентификатор_языка.

Файл .description.php

Файл .description.php содержит наименование источника данных, а также некоторые дополнительные параметры. Внутри файла должно находиться объявление массива $arListDescription. Массив должен иметь следующие ключи:

  • "NAME" - название источника данных, которое выводиться в интерфейсе выбора источника в параметрах свойств и в окошке параметров компонента "grain:links.edit"
  • "SORT" - необязательный, индекс сортировки источника данных в административном интерфейсе
  • "USE_IN_PROPERTIES" - необязательный, если источник будет использоваться в свойствах привязки, то значение данного параметра должно быть "Y"
  • "REQUIRED_MODULES" - необязательный, если источнику данных требуется наличие каких-либо модулей, установленных в системе, то они должны быть перечислены в этом параметре. Значение параметра должно являться массивом символьных идентификаторов необходимых модулей.

Пример файла .description.php:

$arListDescription = Array(

    
"NAME" => GetMessage("MY_DATA_SOURCE_NAME"),
    
"SORT" => "500",
    
"USE_IN_PROPERTIES" => "Y"// источник данных будет использоваться в свойствах привязки
    
"REQUIRED_MODULES" => Array("iblock","catalog"), // источник данных требует наличия модулей iblock и catalog
);

Файл .parameters.php

Файл .parameters.php содержит описание параметров источника, которые выводятся в настройках свойств привязки, а также в окошке параметров компонента "grain:links.edit". Файл необязательный, источник может не иметь настраиваемых параметров. Использование файла оправдано, если вы хотите сделать универсальный источник данных, который будет использоваться в нескольких местах или на разных сайтах.

Формат описания параметров аналогичен формату описания параметров для компонентов битрикс, но с некоторыми ограничениями:

  1. Не должно быть объявления массива $arComponentParameters["PARAMETERS"], только добавление в него данных
  2. При описании каждого параметра в ключе "PARENT" должно быть значение "DATA_SOURCE"


// создание параметра типа "список"

$arComponentParameters["PARAMETERS"]["SORT_BY1"] = Array(
    
"PARENT" => "DATA_SOURCE"// в общих случаях должно быть "DATA_SOURCE"
    
"NAME" => GetMessage("MY_DATA_SOURCE PARAMETER_SORT_BY1"), // название параметра
    
"TYPE" => "LIST"// тип параметра
    
"DEFAULT" => "ACTIVE_FROM"// значение параметра
    
"VALUES" => $arSortFields// переменная $arSortFields содержит варианты значений списка
    
"ADDITIONAL_VALUES" => "Y",// флаг разрешения ввода дополнительных значений
);

Файл list.php

Файл list.php является основным файлом источника данных, в котором непосредственно формируется список элементов.

В коде файла доступен массив $arParams, в котором присутствуют значения параметров источника. Также в коде доступны следующие дополнительные переменные (обратите внимание, что некоторые переменные находятся в массиве $arParams, а некоторые - в $arResult):

  • $arParams["MULTIPLE"] - является ли поле множественным (true/false)
  • $arResult["SELECTED_VALUE"] - если эта переменная установлена, то необходимо выбрать элемент(ы) с определенным(и) значением(ями), может быть строкой с одним значением или массивом со строковыми значениями
  • $arParams["USE_AJAX"] - используется ли режим AJAX (true/false)
  • $arResult["AJAX_RETURN"] - флаг AJAX запроса (true/false)
  • $arResult["AJAX_SEARCH_QUERY"] - если $arResult["AJAX_RETURN"] равен true, то в этой переменной находится непосредственно текст AJAX запроса
  • $arParams["ADMIN_SECTION"] - вызывается ли источник в административной части сайта (true/false)
  • $arParams["SHOW_URL"] - нужно ли добавлять к данным URL элемента (true/false)

Результатом работы источника должен быть заполненный массив $arResult["DATA"] следующей структуры:

Array

(
    [
Значение элемента 1] => Array
        (
            [
NAME] => Заголовок элемента 1
            
[URL] => URL элемента 1 (если $arParams["SHOW_URL"равен true)
        )
    [
Значение элемента 2] => Array
        (
            [
NAME] => Заголовок элемента 2
            
[URL] => URL элемента 2 (если $arParams["SHOW_URL"равен true)
        )
        ...
)

Пример заполненного массива $arResult["DATA"]:

Array

(
    [
1234] => Array
        (
            [
NAME] => Изабелла
            
[URL] => /catalog/sofas/isabella/
        )
    [
some_value] => Array
        (
            [
NAME] => Аладдин
            
[URL] => /catalog/sofas/aladdin/
        )
)

Пример файла list.php источника данных (привязка к блогу)

<?

if(
CModule::IncludeModule("blog")) {

    
// подготавливаем параметры источника

    // параметр GROUP_ID содержит массив всех групп блогов
    
$arGroups $arParams["GROUP_ID"]; 
    
$arParams["GROUP_ID"] = Array();
    foreach(
$arGroups as $group_id)
        if(
intval($group_id)>0)
            
$arParams["GROUP_ID"][] = intval($group_id);
    
    
// параметры сортировки
    
$arParams["SORT_BY1"] = trim($arParams["SORT_BY1"]);
    if(
strlen($arParams["SORT_BY1"])<=0)
        
$arParams["SORT_BY1"] = "NAME";
    
$arParams["SORT_ORDER1"] = strtoupper($arParams["SORT_ORDER1"]);
    if(
$arParams["SORT_ORDER1"]!="DESC")
         
$arParams["SORT_ORDER1"]="ASC";
    if(
strlen($arParams["SORT_BY2"])<=0)
        
$arParams["SORT_BY2"] = "ID";
    
$arParams["SORT_ORDER2"] = strtoupper($arParams["SORT_ORDER2"]);
    if(
$arParams["SORT_ORDER2"]!="ASC")
         
$arParams["SORT_ORDER2"]="DESC";
        
    
// создаем список элементов
    
    
$arSort = array(
        
$arParams["SORT_BY1"]=>$arParams["SORT_ORDER1"],
        
$arParams["SORT_BY2"]=>$arParams["SORT_ORDER2"],
    );
    if(!
array_key_exists("ID"$arSort))
        
$arSort["ID"] = "DESC";
    
    
$arFilter = array (
        
"GROUP_ID" => $arParams["GROUP_ID"],
    );

    if(
$arParams["ACTIVE"]==["Y"])
        
$arFilter["ACTIVE"] = "Y";

    
// если идет поиск через аякс, то используем фильтрацию по имени (подстрока)
    
if($arResult["AJAX_RETURN"]) $arFilter["%NAME"] = $arResult["AJAX_SEARCH_QUERY"];

    
// если нужно отобразить выбранные значения, используем фильтрацию по ID    
    
if($arResult["SELECTED_VALUE"]) $arFilter["ID"] = $arResult["SELECTED_VALUE"];

    
// запрос к базе данных через api    
    
$rsBlogs CBlog::GetList($arSort,$arFilter);
    
    while(
$arBlog=$rsBlogs->GetNext()) {

        
// название элемента    
        
$arItem = Array(
            
"NAME" => $arBlog["NAME"],
        );

        
// если в параметрах выбрана опция "показывать ссылку", то создаем ссылку на элемент
        //по шаблону из параметров источника
        
if($arParams["SHOW_URL"] && $arParams["BLOG_URL"]) {
        
            
$arBlog["SITE_SERVER_NAME"] = defined("SITE_SERVER_NAME")?SITE_SERVER_NAME:"";
            
$arBlog["SITE_ID"] = defined("SITE_ID")?SITE_ID:"";
            
$arBlog["SITE_DIR"] = defined("SITE_DIR")?SITE_DIR:"";
            
            
$arItem["URL"] = $arParams["BLOG_URL"];
            foreach(
$arBlog as $FIELD_NAME=>$FIELD_VALUE)
                if(
substr($FIELD_NAME,0,1)!="~")
                    
$arItem["URL"] = str_replace("#".$FIELD_NAME."#",$FIELD_VALUE,$arItem["URL"]);

            
$arItem["URL"] = preg_replace("'/+'s""/"$arItem["URL"]);
            
$arItem["URL"] = htmlspecialcharsbx($arItem["URL"]);
            
        }
        
        
// сохраняем элемент в массиве $arResult["DATA"]
        
$arResult["DATA"][$arBlog["ID"]] = $arItem;
        
    }
    
}

Компонент "Выбор из списка" (grain:links.edit)

Компонент "Выбор из списка" можно использовать вместо стандартного тега <select>, при этом будет доступен либо динамический поиск, либо использование режима AJAX для выбора элементов списка. При этом список элементов может формироваться как с помощью источников данных, так и напрямую из массива со списком элементов (режим AJAX доступен только при использовании источников данных). Также список элементов может формироваться из готового html-кода тега <select> (это может быть удобно, например, в том случае, если в шаблон какого-либо компонента поступают уже сформированные теги форм).

Использование компонента с источниками данных

Для использования компонента со встроенными источниками данных списков проще всего использовать визуальный редактор для получения кода размещения компонента. Для этого перейдите в дереве компонентов в папку "Служебные" и щелкните дважды на иконке компонента "Выбор из списка". Теперь вы можете выбрать нужный источник данных и настроить прочие параметры в окошке параметров компонента, чтобы впоследствии перейти в режим исходного кода и скопировать код размещения компонента.

Использование компонента со готовым массивом списка или html кодом

В качестве источника элементов списка могут выступать как массивы разной структуры, так и уже сформированный html-код тега <select>. При этом в параметре "DATA_SOURCE" компонента "Выбор из списка" (grain:links.edit) должно находится одно из следующих значений: "array_simple","array_extended","array_bitrix" или "html_select". Сами данные (массив либо html-код) передаются через параметр "DATA".

Простой массив

Если в параметре "DATA_SOURCE" находится значение "array_simple", то в параметр "DATA" должен передаваться массив следующего вида:

Array(

    
"Значение элемента 1" => "Заголовок элемента 1"
    
"Значение элемента 2" => "Заголовок элемента 2",
    ...
 )

Сложный массив

Если в параметре "DATA_SOURCE" находится значение "array_extended", то в параметр "DATA" должен передаваться массив следующего вида:

Array(

    Array(
        
"NAME" => "Заголовок элемента 1"
        
"URL" => "URL элемента 1",
        
"VALUE" => "Значение элемента 1",
    ),
    Array(
        
"NAME" => "Заголовок элемента 2"
        
"URL" => "URL элемента 2",
        
"VALUE" => "Значение элемента 2",
    ),
    ...
 )
Из всех возможных вариантов передачи элементов списка через параметр "DATA", только этот вариант позволяет передавать URL элемента списка.

Массив для функций api битрикс SelectBoxFromArray, SelectBoxMFromArray

Если в параметре "DATA_SOURCE" находится значение "array_bitrix", то в параметр "DATA" должен передаваться массив следующего вида:

Array(

    
"REFERENCE" => Array(
        
"Заголовок элемента 1"
        
"Заголовок элемента 2",
        ...
    ),
    
"REFERENCE_ID" => Array(
        
"Значение элемента 1",
        
"Значение элемента 2",
        ...
    )
 )

Готовый html-код тега <select>

Если в параметре "DATA_SOURCE" находится значение "html_select", то в параметр "DATA" должен сформированный html-код тега <select>:

<select>

    <
option value="Значение элемента 1">Заголовок элемента 1</option>
    <
option value="Значение элемента 2">Заголовок элемента 2</option>
    ...
</
select>

Пример подключения компонента


<span style="color: red">$arData</span> = Array(

    Array(
        
"NAME" => "Заголовок элемента 1"
        
"URL" => "/element1/",
        
"VALUE" => "element1",
    ),
    Array(
        
"NAME" => "Заголовок элемента 2"
        
"URL" => "/element2/",
        
"VALUE" => "element2",
    )
);

$APPLICATION->IncludeComponent(
    
"grain:links.edit",
    
"",
    Array(
        
"DATA_SOURCE" => "array_extended",
        
"INPUT_NAME" => "MYNAME",
        
"MULTIPLE" => "N",
        
"USE_SEARCH" => "Y",
        
"USE_SEARCH_COUNT" => "",
        
"EMPTY_SHOW_ALL" => "Y",
        
"USE_AJAX" => "N",
        
"SHOW_URL" => "Y",
        
"VALUE" => $selected_value,
        
"DATA" => $arData
    
)
);

Использование JavaScript обработчиков компонента

Использование JavaScript обработчиков позволяет выполнять произвольный JavaScript код при наступлении событий в компоненте. Код для исполнения указывается в соответствующих параметрах компонента.

Обработчик ON_AFTER_SELECT

Если в параметре компонента ON_AFTER_SELECT указать JavaScript код, то он будет выполняться при выборе любого элемента списка. Код будет помещен в следующую функцию JavaScript:

function(strValue,strName,strUrl,obSelect,instance_id) {

    ...
}
где:
  • strValue - значение элемента списка
  • strName - заголовок элемента списка
  • strUrl - URL элемента списка
  • obSelect - объект компонента (может быть несколько экземпляров одного объекта)
  • instance_id - идентификатор экземпляра компонента

Обработчик ON_AFTER_REMOVE

Если в параметре компонента ON_AFTER_REMOVE указать JavaScript код, то он будет выполняться при удалении выбранного значения списка. Код будет помещен в следующую функцию JavaScript:

function(strValue,strName,strUrl,obSelect,instance_id) {

    ...
}
где:
  • strValue - значение элемента списка
  • strName - заголовок элемента списка
  • strUrl - URL элемента списка
  • obSelect - объект компонента (может быть несколько экземпляров одного объекта)
  • instance_id - идентификатор экземпляра компонента

Пример использования JavaScript обработчиков


<?$APPLICATION->IncludeComponent(

    
"grain:links.edit",
    
"",
    Array(
        
"DATA_SOURCE" => "iblock_element",
        
"INPUT_NAME" => "MYNAME",
        
"MULTIPLE" => "Y",
        
"USE_SEARCH" => "Y",
        
"EMPTY_SHOW_ALL" => "Y",
        
"NAME_TRUNCATE_LEN" => "",
        
"IBLOCK_TYPE" => "catalog",
        
"IBLOCK_ID" => "3",
        
"SORT_BY1" => "ACTIVE_FROM",
        
"SORT_ORDER1" => "DESC",
        
"SORT_BY2" => "SORT",
        
"SORT_ORDER2" => "ASC",
        
"CHECK_DATES" => "Y",
        
"USE_AJAX" => "N",
        
"SHOW_URL" => "Y",
        
"DETAIL_URL" => "",
        
"CACHE_TYPE" => "A",
        
"CACHE_TIME" => "36000000",
        
"CACHE_NOTES" => "",
        
"CACHE_GROUPS" => "Y",
        
"VALUE" => "",
        
"ON_AFTER_SELECT" => "alert('Selected: strValue='+strValue+', strName='+strName);",
        
"ON_AFTER_REMOVE" => "alert('Removed: strValue='+strValue+', strName='+strName);",
    )
);

Динамическое создание полей

Компонент "Выбор из списка" позволяет динамически создавать поля при помощи JavaScript. При этом для каждого источника данных, который будет использоваться, необходимо сначала подключить компонент с параметром "SCRIPTS_ONLY" равным "Y".

Пример динамического создания поля:

<?

// компонент возвращает $INSTANCE_IDENTIFIER - идентификатор экземпляра компонента
$INSTANCE_IDENTIFIER $APPLICATION->IncludeComponent(
    
"grain:links.edit",
    
"",
    Array(
        
"DATA_SOURCE" => "iblock_element",
        
"INPUT_NAME" => "",
        
"MULTIPLE" => "Y",
        
"USE_SEARCH" => "Y",
        
"USE_SEARCH_COUNT" => "",
        
"EMPTY_SHOW_ALL" => "Y",
        
"NAME_TRUNCATE_LEN" => "",
        
"IBLOCK_TYPE" => "sellers",
        
"IBLOCK_ID" => "3",
        
"SORT_BY1" => "ACTIVE_FROM",
        
"SORT_ORDER1" => "DESC",
        
"SORT_BY2" => "SORT",
        
"SORT_ORDER2" => "ASC",
        
"CHECK_DATES" => "Y",
        
"USE_AJAX" => "N",
        
"SHOW_URL" => "N",
        
"DETAIL_URL" => "",
        
"CACHE_TYPE" => "A",
        
"CACHE_TIME" => "36000000",
        
"CACHE_NOTES" => "",
        
"CACHE_GROUPS" => "Y",
        
"VALUE" => "",
        
"SCRIPTS_ONLY" => "Y",
    )
);
?> 
<?

// instance params
$TEMPLATE_IDENTIFIER "GRAIN_LINKS_EDIT_DEFAULT"// идентификатор шаблона
$SHOW_URL false// показывать URL
$USE_SEARCH true// использовать динамический поиск
$USE_AJAX false// использовать АЯКС
$MULTIPLE true// множественное

// field params
$FIELD_IDENTIFIER "my_field_1"// идентификатор поля, уникальный для каждого поля, даже в рамках одного подключения компонента
$INPUT_NAME "my_name_1"// атрибут NAME поля input

$SELECTED = Array( // массив выбранных значений компонента
    
array("Заголовок элемента 1","URL"=>"/element1/"),
    array(
"Заголовок элемента 2","URL"=>"/element2/"),
);

$JS_SELECTED = Array();

foreach(
$SELECTED as $value => $arItem
    
$JS_SELECTED[$value] = true;

?>

<input 
    class="<?=$TEMPLATE_IDENTIFIER?>-text <?=$TEMPLATE_IDENTIFIER?>-text-placeholded" 
    id="<?=$FIELD_IDENTIFIER?>
    value=""
    <?if(!($USE_SEARCH || $USE_AJAX)):?> readonly="readonly"<?endif?> />

<span class="<?=$TEMPLATE_IDENTIFIER?>-values<?if($MULTIPLE):?>-multiple<?endif?>" id="<?=$FIELD_IDENTIFIER?>_values">
    <?foreach($SELECTED as $value=>$arItem):?>
        <div 
            class="<?=$TEMPLATE_IDENTIFIER?>-values<?if($MULTIPLE):?>-multiple<?endif?>-value" 
            id="<?=$INSTANCE_IDENTIFIER?>_<?=$FIELD_IDENTIFIER?>_value_<?=$value?>
        >
            <?if($SHOW_URL):?><a class="<?=$TEMPLATE_IDENTIFIER?>-values<?if($MULTIPLE):?>-multiple<?endif?>-value-link" href="<?=$arItem["URL"]?>"><?endif?>
            <?=$arItem["NAME"]?>
            <?if($SHOW_URL):?></a><?endif?>
            <a 
                class="<?=$TEMPLATE_IDENTIFIER?>-values<?if($MULTIPLE):?>-multiple<?endif?>-value-delete" 
                href="#" 
                onclick="<?=$TEMPLATE_IDENTIFIER?>.deleteitem('<?=$INSTANCE_IDENTIFIER?>','<?=$FIELD_IDENTIFIER?>',this); return false;" 
                rel="<?=$value?>"
            >x</a>
            <input 
                type="hidden" 
                id="<?=$INSTANCE_IDENTIFIER?>_hidden_<?=$value?>
                name="<?=$INPUT_NAME?><?if($MULTIPLE):?>[]<?endif?>
                value="<?=$value?>" />
        </div>
    <?endforeach?>
</span>

<script type="text/javascript">

<?=$TEMPLATE_IDENTIFIER?>.ibind(
    '<?=$INSTANCE_IDENTIFIER?>',
    '<?=$FIELD_IDENTIFIER?>',
    {
        values_id: '<?=$FIELD_IDENTIFIER?>_values',
        input_name: '<?=$INPUT_NAME?>'
    },
    <?=CUtil::PhpToJsObject($JS_SELECTED)?>
);

</script>

Классы и функции

CGrain_LinksTools::GetSelected

Возвращает массив с заголовками (и URL элементов при необходимости) для определенных значений списка.

Параметры функции:
  • $arParams - массив с параметрами источника данных и прочими параметрами
  • $selected_value - значение или массив значений списка
  • $bParamsPrepared (true/false) - установите true, если массив $arParams уже подготовлен (во всех значениях уже осуществлена замена на безопасные html символы, а исходные значения скопированы в ключи, начинающиеся с "~"), необязательный, по умолчанию false

Пример использования:

$arParams = array (

    
'DATA_SOURCE' => 'iblock_element',
    
'IBLOCK_TYPE' => 'catalog',
    
'IBLOCK_ID' => '3',
    
'SORT_BY1' => 'ID',
    
'SORT_ORDER1' => 'ASC',
    
'SORT_BY2' => 'ID',
    
'SORT_ORDER2' => 'ASC',
    
'DETAIL_URL' => '',
    
'SHOW_URL' => true,
    
'MULTIPLE' => false,
    
'ADMIN_SECTION' => true,
);

$arData CGrain_LinksTools::GetSelected($arParam,"1234");

Пример возвращаемого значения:

Array

(
    [
1234] => Array
        (
            [
NAME] => Изабелла
            
[URL] => /catalog/sofas/isabella/
        )

)