В предыдущей статье я описывал способ группировки элементов инфоблока на сайте под управлением «1С-Битрикс». Он заключался в следующем: элементы группировались на основе привязки к другим элементам того же инфоблока. Чтобы было понятней – таким образом можно организовать список компании (например, заказчиков) в случае, если у этих компаний есть дочерние компании. Список получился многоуровневым: на первом уровне – головные компании, на втором – дочерние. Сейчас немного усложним задачу и добавим еще 2 условия: во-первых, элементы будут находиться в разделах, «связанные» элементы, по которым будет проводиться группировка будут находиться в другом инфоблоке и их значение может быть множественным, т.е. «привязка» может содержать несколько элементов.
Так как все действия я, как обычно, буду проводить над демо-версией системы (решение «для разработчиков»), объясню все указанное выше более понятным языком, так сказать, на практическом примере. В демо-версии системы есть каталог книг. Книги в нем хранятся в одном инфоблоке («Каталог книг» → «Книги») и распределены по разделам, а авторы в другом инфоблоке («Каталог книг» → «Авторы»). Авторы привязаны к книгам через одно из свойств инфоблока с книгами. Также у книги может быть несколько авторов. Задача состоит в следующем: нужно вывести список книг с указанием разделов, таким образом, чтобы книги были сгруппированы не только по разделам, а еще и по авторам, как указано на схеме.
Задача получилась настолько нестандартная, что применением стандартных компонентов системы не решается, поэтому нам на помощь приходит Bitrix Framework. После установки демо-версии особой подготовительной работы проводить не нужно, нужно только создать новую страницу, например, в корневой папке сайта и можно начинать писать код. Код будет оформлен в виде функции с именем MakeElementsTree
, которой будут передаваться несколько параметров: ИД инфоблока с книгами, имя свойства, в котором хранится связь с автором (или авторами). Также в функцию может передаваться ИД раздела, в случае если книги будут выбираться из определенного раздела инфоблока, а не из корневого.
Функция MakeElementsTree
будет формировать массив с книгами, в соответствии с условиями задачи и выводить на страницу. Работу функции можно разделить на 3 части: первая часть - выборка данных из корневого радела и сохранение в массив, вторая – выборка данных из разделов, находящихся внутри корневого раздела и сохранение в массив, третья - вывод данных из массива на страницу.
PHP
function MakeElementsTree($prntIBid,$lnkPropName,$eltype = null){
if(!CModule::IncludeModule("iblock")){
echo "не подключается модуль инфоблоки";
}
// если номер раздела передан в функцию, добавляем его в фильтр
if (isset($eltype) && $eltype != '')
{
$arFilter=array(
"IBLOCK_ID" => $prntIBid,
"SECTION_ID" => $eltype,
"ACTIVE" => "Y",
);
}
else{
// если нет выбираем разделы верхнего уровня
$arFilter=array(
"IBLOCK_ID" => $prntIBid,
"DEPTH_LEVEL" => 1,
"ACTIVE" => "Y",
);
}
$ar_result=Array();
// ВЫБИРАЕМ ЭЛЕМЕНТЫ ИЗ КОРНЕВОГО РАЗДЕЛА
$arFilterRoot = array(
"IBLOCK_ID" => $prntIBid,
"SECTION_ID" => "",
"ACTIVE" => "Y",
);
$arProjRootElem = CIBlockElement::GetList(array("SORT"=>"ASC"),$arFilterRoot,false);
while($projResElem = $arProjRootElem->GetNextElement()){
$arElemFld = $projResElem->GetFields();
$arElemProp = $projResElem->GetProperties();
$arSelPropRoot[$arElemFld["ID"]] = $arElemProp[$lnkPropName]["VALUE"];
}
foreach($arSelPropRoot as $propkey => $propval){
//если значение свойства где хранится привязка множественное - формируем ключ и объединяем значения в одну строку
if(count($propval) > 1){
$rpppval = "";
$rpppres = "";
foreach($propval as $rppkey => $rppval){
$arLnkRootElem = CIBlockElement::GetByID($rppval);
if($arLnkRootElem_res = $arLnkRootElem->GetNext()){
$rpppval .= $rppval;
$rpppres .= $arLnkRootElem_res["NAME"]." ";
}
}
$ar_result_root["CUST_ITEMS"][$rpppval]["NAME"] = $rpppres;
$arElemVal = CIBlockElement::GetByID($propkey);
if($arLnkRootElem_res = $arElemVal->GetNext()){
$ar_result_root["CUST_ITEMS"][$rpppval]["ELEM"][$arLnkRootElem_res["ID"]]["NAME"]= $arLnkRootElem_res["NAME"];
$ar_result_root["CUST_ITEMS"][$rpppval]["ELEM"][$arLnkRootElem_res["ID"]]["PREVIEW_TEXT"] = $arLnkRootElem_res["PREVIEW_TEXT"];
$ar_result_root["CUST_ITEMS"][$rpppval]["ELEM"][$arLnkRootElem_res["ID"]]["DETAIL_TEXT"] = $arLnkRootElem_res["DETAIL_TEXT"];
$ar_result_root["CUST_ITEMS"][$rpppval]["ELEM"][$arLnkRootElem_res["ID"]]["D_TXT_LENGTH"] = strlen($arRootLnkElem_res["DETAIL_TEXT"]);
$ar_result_root["CUST_ITEMS"][$rpppval]["ELEM"][$arLnkRootElem_res["ID"]]["DETAIL_PAGE_URL"] = $arRootLnkElem_res["DETAIL_PAGE_URL"];
}
}
// иначе просто получаем ключ и значение.
else{
foreach($propval as $rppkey => $rppval){
$arLnkRootElem = CIBlockElement::GetByID($rppval);
if($arLnkRootElem_res = $arLnkRootElem->GetNext()){
$ar_result_root["CUST_ITEMS"][$rppval]["NAME"] = $arLnkRootElem_res["NAME"];
}
}
$arElemVal = CIBlockElement::GetByID($propkey);
if($arLnkRootElem_res = $arElemVal->GetNext()){
$ar_result_root["CUST_ITEMS"][$rppval]["ELEM"][$arLnkRootElem_res["ID"]]["NAME"]= $arLnkRootElem_res["NAME"];
$ar_result_root["CUST_ITEMS"][$rppval]["ELEM"][$arLnkRootElem_res["ID"]]["PREVIEW_TEXT"] = $arLnkRootElem_res["PREVIEW_TEXT"];
$ar_result_root["CUST_ITEMS"][$rppval]["ELEM"][$arLnkRootElem_res["ID"]]["DETAIL_TEXT"] = $arLnkRootElem_res["DETAIL_TEXT"];
$ar_result_root["CUST_ITEMS"][$rppval]["ELEM"][$arLnkRootElem_res["ID"]]["D_TXT_LENGTH"] = strlen($arRootLnkElem_res["DETAIL_TEXT"]);
$ar_result_root["CUST_ITEMS"][$rppval]["ELEM"][$arLnkRootElem_res["ID"]]["DETAIL_PAGE_URL"] = $arRootLnkElem_res["DETAIL_PAGE_URL"];
}
}
$ar_result_root["CUST_SUBSECT"]= $arSelPropRoot;
unset($arSelPropRoot);
}
// ВЫБИРАЕМ ЭЛЕМЕНТЫ ИЗ РАЗДЕЛОВ
$arProj = CIBlockSection::GetList(array("SORT"=>"ASC"),$arFilter,false);
while($projRes = $arProj->GetNextElement())
{
$arFields = $projRes->GetFields();
$ar_result[$arFields["ID"]]["NAME"] = $arFields["NAME"];
$ar_result[$arFields["ID"]]["CODE"] = $arFields["CODE"];
}
// узнаем ИД связанных элементов из другого инфоблока
foreach($ar_result as $arrkey => $arrvalue){
$arProjElem = CIBlockElement::GetList(array("SORT"=>"ASC"),array("SECTION_ID"=>$arrkey),false);
while($projResElem = $arProjElem->GetNextElement())
{
$arElemFld = $projResElem->GetFields();
$arElemProp = $projResElem->GetProperties();
$arSelProp[$arElemFld["ID"]] = $arElemProp[$lnkPropName]["VALUE"];
}
foreach($arSelProp as $propkey => $propval){
//если значение свойства где хранится привязка множественное - формируем ключ и объединяем значения в одну строку
if(count($propval > 1)){
$pppval = "";
$pppres = "";
foreach($propval as $ppkey => $ppval){
$arLnkElem = CIBlockElement::GetByID($ppval);
if($arLnkElem_res = $arLnkElem->GetNext()){
$pppval .= $ppval;
$pppres .= $arLnkElem_res["NAME"]." ";
}
}
$ar_result[$arrkey]["CUST_ITEMS"][$pppval]["NAME"] = $pppres;
$arElemVal = CIBlockElement::GetByID($propkey);
if($arLnkElem_res = $arElemVal->GetNext()){
$ar_result[$arrkey]["CUST_ITEMS"][$pppval]["ELEM"][$arLnkElem_res["ID"]]["NAME"]= $arLnkElem_res["NAME"];
$ar_result[$arrkey]["CUST_ITEMS"][$pppval]["ELEM"][$arLnkElem_res["ID"]]["PREVIEW_TEXT"] = $arLnkElem_res["PREVIEW_TEXT"];
$ar_result[$arrkey]["CUST_ITEMS"][$pppval]["ELEM"][$arLnkElem_res["ID"]]["DETAIL_TEXT"] = $arLnkElem_res["DETAIL_TEXT"];
$ar_result[$arrkey]["CUST_ITEMS"][$pppval]["ELEM"][$arLnkElem_res["ID"]]["D_TXT_LENGTH"] = strlen($arLnkElem_res["DETAIL_TEXT"]);
$ar_result[$arrkey]["CUST_ITEMS"][$pppval]["ELEM"][$arLnkElem_res["ID"]]["DETAIL_PAGE_URL"] = $arLnkElem_res["DETAIL_PAGE_URL"];
}
}
// иначе просто получаем ключ и значение.
else{
foreach($propval as $ppkey => $ppval){
$arLnkElem = CIBlockElement::GetByID($ppval);
if($arLnkElem_res = $arLnkElem->GetNext()){
$ar_result[$arrkey]["CUST_ITEMS"][$ppval]["NAME"] = $arLnkElem_res["NAME"];
}
}
$arElemVal = CIBlockElement::GetByID($propkey);
if($arLnkElem_res = $arElemVal->GetNext()){
$ar_result[$arrkey]["CUST_ITEMS"][$ppval]["ELEM"][$arLnkElem_res["ID"]]["NAME"]= $arLnkElem_res["NAME"];
$ar_result[$arrkey]["CUST_ITEMS"][$ppval]["ELEM"][$arLnkElem_res["ID"]]["PREVIEW_TEXT"] = $arLnkElem_res["PREVIEW_TEXT"];
$ar_result[$arrkey]["CUST_ITEMS"][$ppval]["ELEM"][$arLnkElem_res["ID"]]["DETAIL_TEXT"] = $arLnkElem_res["DETAIL_TEXT"];
$ar_result[$arrkey]["CUST_ITEMS"][$ppval]["ELEM"][$arLnkElem_res["ID"]]["D_TXT_LENGTH"] = strlen($arLnkElem_res["DETAIL_TEXT"]);
$ar_result[$arrkey]["CUST_ITEMS"][$ppval]["ELEM"][$arLnkElem_res["ID"]]["DETAIL_PAGE_URL"] = $arLnkElem_res["DETAIL_PAGE_URL"];
}
}
}
$ar_result[$arrkey]["CUST_SUBSECT"]= $arSelProp;
unset($arSelProp);
}
// ПОКАЗЫВАЕМ ЭЛЕМЕНТЫ ИЗ КОРНЕВОГО РАЗДЕЛА
if(isset($ar_result_root) && is_array($ar_result_root["CUST_ITEMS"]) && count($ar_result_root["CUST_ITEMS"]) > 0)
{
foreach($ar_result_root ["CUST_ITEMS"] as $arr_cust_items){
echo "<p class=\"surname2\">".$arr_cust_items["NAME"]."</p>";
echo "<ul style=\"margin-bottom:10px;\">";
foreach($arr_cust_items["ELEM"] as $arrItem){
echo "<li class=\"gvert\" style=\"margin-bottom:10px;\">";
echo $arrItem["NAME"];
echo "</li>";
}
echo "</ul>";
}
}
// ПОКАЗЫВАЕМ ЭЛЕМЕНТЫ ИЗ РАЗДЕЛОВ
foreach($ar_result as $key => $arrValues)
{
if(is_array($arrValues["CUST_ITEMS"]) && count($arrValues["CUST_ITEMS"]) > 0)
{
echo "<h3 class=\"title1\" id=\"".$arrValues["CODE"]."\">".$arrValues["NAME"]."</h3>";
foreach($arrValues["CUST_ITEMS"] as $arr_cust_items){
echo "<p class=\"surname2\">".$arr_cust_items["NAME"]."</p>";
echo "<ul style=\"margin-bottom:10px;\">";
foreach($arr_cust_items["ELEM"] as $arrItem){
echo "<li class=\"gvert\" style=\"margin-bottom:10px;\">";
echo $arrItem["NAME"];
echo "</li>";
}
echo "</ul>";
}
}
}
}
Функция работает следующим образом: в начале проверяется передан ли функции в качестве параметра ИД родительского раздела. В зависимости от этого формируется массив $arFilter
, который участвует в процессе выборки элементов, являясь фильтром. Создается пустой массив $ar_result
, в который будет помещаться информация, полученная в процессе работы функции. Сначала в массив помещается информация о разделах (ИД, название, символьный код). На основе этих данных получаем значение свойства элементов инфоблока «Книги», в котором хранится «привязка» к элементам инфоблока «Авторы». Узнаем информацию об авторе (авторах). Если у книги авторов несколько объединяем их всех в одну строку, разделяя пробелами, и также помещаем в массив $ar_result
. Далее получаем информацию о книгах данного автора (авторов) и снова помещаем в массив $ar_result
. В результате получается массив, показанный на скриншоте ниже.
Далее этот массив нужно привести в удобочитаемый вид, что и делает код в третьей части функции. В данном случае список на странице будет выглядеть следующим образом:
На скриншоте представлен раздел «Бизнес-литература». Вы можете скачать файлы с приведенным выше кодом. Если их скопировать в папку с демо-версией сайта и не менять значения параметров при вызове функции MakeElementsTree
, вы получите такой же результат, как описан в этой статье. Так вы сможете посмотреть как работает данная функция и ознакомиться с ней более детально для возможного применения на своем сайте.