137  /  328

Работа с пользовательскими свойствами инфоблоков

Просмотров: 9061 (Статистика ведётся с 06.02.2017)
Дата последнего изменения: 30.09.2015

Примеры решения задач, возникающих при работе с элементами, разделами и свойствами инфоблоков.

  • Получить значения всех свойств элемента, зная его ID
  • Получить свойства элементов, используя метод CIBlockElement::GetList
  • Добавить свойство типа TEXT/html для элемента
  • Заполнить множественное свойство типа Файл
  • Заполнить множественное свойство типа Список
  • Получить пользовательское свойство раздела
  • Пример создания своего типа данных для пользовательского свойства
  • Использование пользовательских свойств на примере дополнительных полей в подписке
  • Как удалить файл в свойстве элемента инфоблока

  • Задача 1:
    Получить значения всех свойств элемента, зная его ID.

    1	<? $db_props = CIBlockElement::GetProperty(IBLOCK_ID, ELEMENT_ID, "sort", "asc", array());
    2	$PROPS = array();
    3	while($ar_props = $db_props->Fetch())
    4	$PROPS[$ar_props['CODE']] = $ar_props['VALUE'];?>

    Теперь символьный код свойства является ключом ассоциативного массива $PROPS, то есть, если вам нужно значение свойства с кодом price, то оно будет храниться в $PROPS['price'].


    Задача 2:
    Получить свойства элементов, используя метод CIBlockElement::GetList

    1	<? $arSelect = array("ID", "NAME", "PROPERTY_prop_code_1", "PROPERTY_prop_code_2");
    2	$res = CIBlockElement::GetList(array(), array(), false, array(), $arSelect);?>

    Дальше использовать цикл и получить свойства с символьными кодами prop_code_1 и prop_code_2.

    Советы веб-разработчиков.

    Антон Долганин: Если для какого-либо изменения в БД предусмотрен специальный метод, следует использовать именно его, а не более общий метод изменения БД.

    Хороший пример: модуль интернет-магазина и работа с заказом. Можно изменить флаг оплаты заказа путем CSaleOrder::Update, а можно путем CSaleOrder::PayOrder. Так вот, следует применять именно PayOrder, потому что в нем произойдет вызов соответствующих обработчиков.


    Задача 3:
    Добавить свойство типа TEXT/html для элемента.

    Если свойство не множественное:

    01	<? $element = new CIBlockElement;
    02	$PROP = array();
    03	$PROP['символьный код свойства']['VALUE']['TYPE'] = 'text'; // или html
    04	$PROP['символьный код свойства']['VALUE']['TEXT'] = 'значение, которое нужно забить';
    05	$arLoadArray = array(
    06	  "IBLOCK_ID"      => IBLOCK_ID,
    07	  "PROPERTY_VALUES"=> $PROP,
    08	  "NAME"           => "Название элемента"
    09	  );
    10	$element->Add($arLoadArray);?>

    Если свойство множественное:

    01	<? // В $ITEMS хранятся значения множественного свойства, которое нужно забить
    02	foreach($ITEMS as $item)
    03	{
    04	    $VALUES[]['VALUE'] = array(
    05	     'TYPE' => 'text', // или html
    06           'TEXT' => $item,
    07           );
    08	}
    09	$element = new CIBlockElement;
    10	$PROPS = array();
    11	$PROPS['символьный код свойства'] = $VALUES;
    12	$arLoadArray = array(
    13	  "IBLOCK_ID"      => IBLOCK_ID,
    14	  "PROPERTY_VALUES"=> $PROPS,
    15	  "NAME"           => "Название элемента"
    16	  );
    17	$element->Add($arLoadArray);?>


    Задача 4: Заполнить множественное свойство типа Файл. Довольно часто при добавлении элемента в инфоблок может понадобиться привязать к нему несколько файлов. Для этого удобно создать у инфоблока множественное свойство типа Файл и хранить файлы в нём. Пример заполнения свойства:

    01	<?
    02	$arFiles = array();
    03	for($i = 1; $i < 10; $i++)
    04	{
    05	    if(file_exists($_SERVER['DOCUMENT_ROOT'].'/images/image_'.$i.'.jpg'))
    06	    {
    07	        $arFiles[] = array('VALUE' => CFile::MakeFileArray($_SERVER["DOCUMENT_ROOT"].'/images/image_'.$i.'.jpg'), 'DESCRIPTION' => '');
    08	    }
    09	}
    10	?>

    После этого массив $arFiles передается как значение свойства при добавлении элемента.


    Задача 5:
    Заполнить множественное свойство типа Список с отображением в виде флажков. В данном случае у каждого элемента списка значений есть свой ID. Посмотреть их можно, зайдя в детальное редактирование свойства. Заполняется свойство следующим образом:

    1	<?
    2	if($first_condition == true) $values[] = array('VALUE' => 1);
    3	if($second_condition == true) $values[] = array('VALUE' => 2);
    4	CIBlockElement::SetPropertyValuesEx($ELEMENT_ID, $IBLOCK_ID, array('property_code' => $values));
    5	?>

    В данном случае при выполнении первого и второго условий мы отмечаем флажками элементы списка с ID =1 и ID=2 соответственно. Заменить следует $ELEMENT_ID, $IBLOCK_ID и property_code на нужные значения.


    Задача 6:
    Получить пользовательское свойство раздела

    1	<? $section_props = CIBlockSection::GetList(array(), array('IBLOCK_ID' => IBLOCK_ID, 'ID' => SECTION_ID), 
                                   true, array("UF_ADDITIONAL_PRICE"));
    2	$props_array = $section_props->GetNext(); ?>

    Теперь в $props_array['UF_ADDITIONAL_PRICE'] лежит значение свойства UF_ADDITIONAL_PRICE раздела инфоблока.

    Совет от веб-разработчиков.

    Алексей Коваленко: При работе с инфоблоками удобнее все коды свойств именовать заглавными буквами. В таком случае вы сможете избежать небольших несостыковок в своей работе.

    Например, значение свойства с кодом foto при работе с компонентами часто доступно через [PROPERTIES][foto][VALUE]?, а при использовании метода GetList вы можете получить PROPERTY_FOTO_VALUE.


    Пример создания своего типа данных для пользовательского свойства

    В качестве значения свойства попробуем завести картинку с превью. Это могут быть например фотографии гостиницы на туристическом сайте или что-то подобное. В варианте такого применения и рассмотрим решение задачи.

    Один из вариантов реализации: хранить изображения в отдельном инфоблоке и показывать как привязку к элементу. Пример кода:

    AddEventHandler("iblock", "OnIBlockPropertyBuildList", array("CIBlockPropertyPicture", "GetUserTypeDescription"));
    AddEventHandler("iblock", "OnBeforeIBlockElementDelete", array("CIBlockPropertyPicture", "OnBeforeIBlockElementDelete"));
    class CIBlockPropertyPicture
    {
       function GetUserTypeDescription()
       {
          return array(
             "PROPERTY_TYPE"      =>"E",
             "USER_TYPE"      =>"Picture",
             "DESCRIPTION"      =>"Картинка",
             "GetPropertyFieldHtml" =>array("CIBlockPropertyPicture", "GetPropertyFieldHtml"),
             "GetPublicViewHTML" =>array("CIBlockPropertyPicture", "GetPublicViewHTML"),
             "ConvertToDB" =>array("CIBlockPropertyPicture", "ConvertToDB"),
    
             //"GetPublicEditHTML" =>array("CIBlockPropertyPicture","GetPublicEditHTML"),
             //"GetAdminListViewHTML" =>array("CIBlockPropertyPicture","GetAdminListViewHTML"),
             //"CheckFields" =>array("CIBlockPropertyPicture","CheckFields"),
             //"ConvertFromDB" =>array("CIBlockPropertyPicture","ConvertFromDB"),
             //"GetLength" =>array("CIBlockPropertyPicture","GetLength"),
          );
       }
    
       function GetPropertyFieldHtml($arProperty, $value, $strHTMLControlName)
       {
          $LINK_IBLOCK_ID = intval($arProperty["LINK_IBLOCK_ID"]);
          if($LINK_IBLOCK_ID)
          {
             $ELEMENT_ID = intval($value["VALUE"]);
             if($ELEMENT_ID)
             {
                $rsElement = CIBlockElement::GetList(array(), array("IBLOCK_ID" => $arProperty["LINK_IBLOCK_ID"],
                              "ID" => $value["VALUE"]), false, false, array("ID", "PREVIEW_PICTURE", "DETAIL_PICTURE"));
                $arElement = $rsElement->Fetch();
                if(is_array($arElement))
                   $file_id = $arElement["DETAIL_PICTURE"];
                else
                   $file_id = 0;
             }
             else
             {
                $file_id = 0;
             }
    
             if($file_id)
             {
                $db_img = CFile::GetByID($file_id);
                $db_img_arr = $db_img->Fetch();
                if($db_img_arr)
                {
                   $strImageStorePath = COption::GetOptionString("main", "upload_dir", "upload");
                   $sImagePath = "/".$strImageStorePath."/".$db_img_arr["SUBDIR"]."/".$db_img_arr["FILE_NAME"];
                   return '<label><input name="'.$strHTMLControlName["VALUE"].'[del]" value="Y" type="checkbox"> 
                            Удалить файл '.$sImagePath.'</label>'
                   .'<input name="'.$strHTMLControlName["VALUE"].'[old]" value="'.$ELEMENT_ID.'" type="hidden">';
                }
             }
             return '<input type="file" size="'.$arProperty["COL_COUNT"].'" name="'.$strHTMLControlName["VALUE"].'"/>';
          }
          else
          {
             return "Ошибка настройки свойства. Укажите инфоблок в котором будут храниться картинки.";
          }
       }
    
       function GetPublicViewHTML($arProperty, $value, $strHTMLControlName)
       {
          $LINK_IBLOCK_ID = intval($arProperty["LINK_IBLOCK_ID"]);
          if($LINK_IBLOCK_ID)
          {
             $ELEMENT_ID = intval($value["VALUE"]);
             if($ELEMENT_ID)
             {
                $rsElement = CIBlockElement::GetList(array(), array("IBLOCK_ID" => $arProperty["LINK_IBLOCK_ID"], 
                              "ID" => $value["VALUE"]), false, false, array("ID", "PREVIEW_PICTURE", "DETAIL_PICTURE"));
                $arElement = $rsElement->Fetch();
                if(is_array($arElement))
                   return CFile::Show2Images($arElement["PREVIEW_PICTURE"], $arElement["DETAIL_PICTURE"]);
             }
          }
          return "";
       }
    
       function ConvertToDB($arProperty, $value)
       {
          $arResult = array("VALUE" => "", "DESCRIPTION" => "");
          $LINK_IBLOCK_ID = intval($arProperty["LINK_IBLOCK_ID"]);
          if($LINK_IBLOCK_ID)
          {
             if(
                is_array($value["VALUE"])
                && is_array($value["VALUE"]["error"])
                && $value["VALUE"]["error"]["VALUE"] == 0
                && $value["VALUE"]["size"]["VALUE"] > 0
             )
             {
                $arDetailPicture =  array(
                   "name" => $value["VALUE"]["name"]["VALUE"],
                   "type" => $value["VALUE"]["type"]["VALUE"],
                   "tmp_name" => $value["VALUE"]["tmp_name"]["VALUE"],
                   "error" => $value["VALUE"]["error"]["VALUE"],
                   "size" => $value["VALUE"]["size"]["VALUE"],
                );
                $obElement = new CIBlockElement;
                $arResult["VALUE"] = $obElement->Add(array(
                   "IBLOCK_ID" => $LINK_IBLOCK_ID,
                   "NAME" => $arDetailPicture["name"],
                   "DETAIL_PICTURE" => $arDetailPicture,
                ), false, false, true);
             }
             elseif(
                is_array($value["VALUE"])
                && isset($value["VALUE"]["size"])
                && !is_array($value["VALUE"]["size"])
                && $value["VALUE"]["size"] > 0
             )
             {
                $arDetailPicture =  array(
                   "name" => $value["VALUE"]["name"],
                   "type" => $value["VALUE"]["type"],
                   "tmp_name" => $value["VALUE"]["tmp_name"],
                   "error" => intval($value["VALUE"]["error"]),
                   "size" => $value["VALUE"]["size"],
                );
                $obElement = new CIBlockElement;
                $arResult["VALUE"] = $obElement->Add(array(
                   "IBLOCK_ID" => $LINK_IBLOCK_ID,
                   "NAME" => $arDetailPicture["name"],
                   "DETAIL_PICTURE" => $arDetailPicture,
                ), false, false, true);
             }
             elseif($value["VALUE"]["del"])
             {
                $obElement = new CIBlockElement;
                $obElement->Delete($value["VALUE"]["old"]);
             }
             elseif($value["VALUE"]["old"])
             {
                $arResult["VALUE"] = $value["VALUE"]["old"];
             }
             elseif(!is_array($value["VALUE"]) && intval($value["VALUE"]))
             {
                $arResult["VALUE"] = $value["VALUE"];
             }
          }
          return $arResult;
       }
    
       function OnBeforeIBlockElementDelete($ELEMENT_ID)
       {
          $arProperties = array();
          $rsElement = CIBlockElement::GetList(array(), array("ID" => $ELEMENT_ID), false, false, array("ID", "IBLOCK_ID"));
          $arElement = $rsElement->Fetch();
          if($arElement)
          {
             $rsProperties = CIBlockProperty::GetList(array(), array("IBLOCK_ID" => $arElement["IBLOCK_ID"], "USER_TYPE" => "Picture"));
             while($arProperty = $rsProperties->Fetch())
                $arProperties[] = $arProperty;
          }
    
          $arElements = array();
          foreach($arProperties as $arProperty)
          {
             $rsPropValues = CIBlockElement::GetProperty($arElement["IBLOCK_ID"], $arElement["ID"], array(), array(
                "EMPTY" => "N",
                "ID" => $arProperty["ID"],
             ));
             while($arPropValue = $rsPropValues->Fetch())
             {
                $ID = intval($arPropValue["VALUE"]);
                if($ID > 0)
                   $arElements[$ID] = $ID;
             }
          }
    
          foreach($arElements as $to_delete)
          {
             CIBlockElement::Delete($to_delete);
          }
       }
    }

    Что мы в итоге имеем:

    • Интерфейс редактирования элемента с возможностью добавления и удаления изображений.
    • При удалении элемента связанная с ним информация удаляется.
    • Поддержка компонент публичной части.

    Инструкция по применению:

    • Этот код разместите в файле /bitrix/php_interface/init.php.
    • Создайте инфоблок для хранения изображений и в его настройках укажите параметры генерации картинки предварительного просмотра из детальной (на вкладке Поля).
    • В инфоблоке Гостиницы добавьте свойство типа Картинка и в дополнительных настройках этого свойства укажите созданный на первом шаге инфоблок. Не забудьте указать символьный код свойства.
    • Создайте элемент и "поиграйтесь" со значениями этого свойства.
    • В публичной части, например в компоненте news, в параметрах настройки списка элементов выбрать это свойство.


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

    Задача: подписчиком будет указываться пол, и в зависимости от этого выбора в письме рассылки она или он получит "Уважаемая" или "Уважаемый" в качестве обращения.

    В решении используется демо дистрибутив с настроенным функционалом рассылки. Для использования описанного функционала на ваших проектах нужно провести работы:

    • Размещение компонента Форма подписки (bitrix:subscribe.form) в шаблоне сайта.
    • Настройка компонента на страницу редактирования подписки пользователя.
    • Создание, при необходимости, рубрик подписки.
    • Создать раздел управления подписками.
    • Размещение компонента Страница рассылок (bitrix:subscribe.index) и настройка ее на страницу редактирования подписки пользователя
    • Создание страницы редактирования подписки пользователя и размещение на ней компонента Страница редактирования подписки (bitrix:subscribe.edit).
    • Настройка модуля Подписка

    Решение. Зададим идентификатор сущности к которой будут привязываться значения дополнительных свойств: MY_SUBSCRIPTION. В качестве уникального идентификатора объектов этой сущности будут выступать b_subscription.ID.

    На странице Пользовательские поля (Настройки > Настройки продукта > Пользовательские поля) откроем форму создания нового поля.

    Заполните поля:

    • Тип данных - Список
    • Объект - MY_SUBSCRIPTION
    • Код поля - UF_GENDER

    Остальные поля не заполняем, нажимаем кнопку Применить.

    На вкладке Список задаем возможные значения: Женский и Мужской. Применяем внесенные изменения.

    Кастомизиция компонента subscribe.edit

    После копирования компонента в свое пространство имён заменяем вызов на странице /personal/subscribe/subscr_edit.php на путь к копированному компоненту.

    Для вывода значения пользовательских свойств подписки в файле component.php после

    $arResult["ALLOW_REGISTER"] = $bAllowRegister?"Y":"N"; 
    добавляем чтение значений из базы данных
    $arResult["USER_PROPERTIES"] = $GLOBALS["USER_FIELD_MANAGER"]->GetUserFields(
    	"MY_SUBSCRIPTION",
    	$arResult["ID"],
    	LANGUAGE_ID
    ); 

    В файле setting.php шаблона выводим примерно следующее:

    <table> 
    <?foreach ($arResult["USER_PROPERTIES"] as $FIELD_NAME => $arUserField):?> 
    	<tr> 
    	<td><?echo $arUserField["EDIT_FORM_LABEL"]?>:</td> 
    	<td><?$APPLICATION->IncludeComponent( 
    		"bitrix:system.field.edit", 
    		$arUserField["USER_TYPE"]["USER_TYPE_ID"], 
    		array(
    			"bVarsFromForm" => false,
    			"arUserField" => $arUserField
    		),
    		null,
    		array("HIDE_ICONS"=>"Y"));?></td> 
    	</tr> 
    <?endforeach;?> 
    </table> 
    
    Для сохранения значений в базе данных в файле component.php после строк
    if($ID>0) 
    { 
    	... 
    	$res = $obSubscription->Update($ID, $arFields); 
    	... 
    } 
    else 
    { 
    	... 
    	$ID = $obSubscription->Add($arFields); 
    	... 
    } 
    добавляем код установки значений свойств
    if($res && $ID > 0) 
    { 
    	global $USER_FIELD_MANAGER; 
    	$arUserFields = $USER_FIELD_MANAGER->GetUserFields("MY_SUBSCRIPTION"); 
    	$arFields = array(); 
    	foreach($arUserFields as $FIELD_ID => $arField) 
    		$arFields[$FIELD_ID] = $_REQUEST[$FIELD_ID]; 
    	$USER_FIELD_MANAGER->Update("MY_SUBSCRIPTION", $ID, $arFields); 
    } 

    Для полноты действий у данного поля в административной части указываем:

    • Обязательное - Да
    • Подпись - Пол

    Создайте новую подписку (или отредактируйте уже существующую) и укажите пол подписчика.

    Теперь надо сделать так, чтобы #GENDER_HELLO# будет заменяться на Уважаемая/Уважаемый в зависимости от пола. Создаем обработчик события BeforePostingSendMail:

    <? 
    // файл /bitrix/php_interface/init.php 
    // регистрируем обработчик 
    AddEventHandler("subscribe", "BeforePostingSendMail", Array("MyClass", "BeforePostingSendMailHandler")); 
    class MyClass 
    { 
    	// создаем обработчик события "BeforePostingSendMail" 
    	function BeforePostingSendMailHandler($arFields) 
    	{ 
    		$rs = CSubscription::GetByEmail($arFields["EMAIL"]); 
    		if($ar = $rs->Fetch()) 
    		{ 
    			global $USER_FIELD_MANAGER; 
    			$arUserFields = $USER_FIELD_MANAGER->GetUserFields("MY_SUBSCRIPTION", $ar["ID"]); 
    
    			if($arUserFields["UF_GENDER"]["VALUE"] == 1) 
    				$arFields["BODY"] = str_replace("#GENDER_HELLO#", "Уважаемая", $arFields["BODY"]); 
    			elseif($arUserFields["UF_GENDER"]["VALUE"] == 2) 
    				$arFields["BODY"] = str_replace("#GENDER_HELLO#", "Уважаемый", $arFields["BODY"]); 
    			else 
    				$arFields["BODY"] = str_replace("#GENDER_HELLO#", "", $arFields["BODY"]); 
    		}
    		else 
    		{ 
    			$arFields["BODY"] = str_replace("#GENDER_HELLO#", "", $arFields["BODY"]); 
    		} 
    		return $arFields; 
    	} 
    } 
    ?>


    Как удалить файл в свойстве элемента инфоблока

    Обновить любое свойство можно с помощью методов:

    При использовании любого метода на ключ массива обновления идет код свойства, а значение - новое значение. Для удаления файла нам надо передать вот такой простой массивчик:

    array('MY_FILE' => array('XXX' => array('del' => 'Y')));

    Способ универсален и подходит что для инфоблоков, что для инфоблоков 2.0, что для документооборота. MY_FILE - это код вашего свойства типа Файл. А что такое ХХХ? В нём содержится ID значения_ свойства. То есть не ID свойства, а именно ID значения.

    CModule::IncludeModule('iblock');
    $IB = 24;
    $ID = 220304;
    $CODE = 'ONE_FL';
    if ($arProp = CIBlockElement::GetProperty($IB, $ID, 'ID', 'DESC', array('CODE' => $CODE))->fetch()) {
       $XXX = $arProp['PROPERTY_VALUE_ID'];
       CIBlockElement::SetPropertyValueCode($ID, $CODE, array($XXX => array('del' => 'Y')));
    }

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

    Что делать в случае множественного файла? Как удалить конкретный файл в списке? Все просто - используем в примере выше не if, а while, ну и дополнительно фильтруем, какой файл надо удалить.

    29
    Курсы разработаны в компании «1С-Битрикс»

    Если вы нашли неточность в тексте, непонятное объяснение, пожалуйста, сообщите нам об этом в комментариях.
    Развернуть комментарии