- PVSM.RU - https://www.pvsm.ru -
Битрикс, как платформа, содержит в себе несколько неудобных для разработчика мест. Об одном таком месте, которое мне давно хотелось «почесать», и пойдёт повествование в данном топике. Кому интересно добро пожаловать под кат.
Я думаю ни для кого не является секретом, что использовать в вызовах API ID инфоблоков или же ID их свойств, а так же ID значений свойств типа «список», является не очень хорошей практикой разработки под Битрикс. Если это для кого-то секрет, я поясню. Дело в том, что у данной техники есть несколько неприятных минусов:
Я при первом знакомстве с Битриксом не видел в этих ограничениях особой проблемы. Ведь у инфоблоков и свойств инфоблоков есть код (CODE), а у значений свойств типа «список» есть внешний код (XML_ID), которые задаются разработчиком. Но с опытом и всё большим погружением в API Битрикса, выяснилось что и тут не обошлось без подводных камней. Поэтому идея использовать символьный код вместо числового идентификатора в вызовах API оказалась не идеальной.
Первый и наиболее серьёзный камень проявляется в том, что не все методы API модуля инфоблоков поддерживают символьные коды. Многие методы (особенно для работы со свойствами инфоблоков) поддерживают только идентификаторы, среди этих методов:
Второй подводный камень кроется в событиях модуля инфоблоков, а если быть точнее в:
В обработчики данных событий передаётся массив $arFields, содержащий в себе поля и свойства создаваемого или изменяемого элемента инфоблока. Камень же лежит в массиве $arParams['PROPERTY_VALUES'], в котором хранятся значения свойств элементов, а в виде ключей используются ID свойств инфоблоков.
[PROPERTY_VALUES] => Array
(
[33] => Array
(
[0] => Array
(
[VALUE] => 24
)
)
)
И последний камень лежит в методе CIBlockElement::GetList [10] и проявляет себя главным образом при попытке отфильтровать элементы инфоблока по значениям свойств типа «список». В документации к API описывается только 2 пути построения фильтра по значениям свойств типа «список»:
Второй вариант, по мне честно говоря, является чем-то несуразным, потому что я считаю, что строковое значение свойства создаётся в первую очередь для контент-менеджера, будущего заполнять сайт, а не для организации фильтра по данному свойству. Более того фильтрация по строковому значению будет работать значительно медленней, чем по числовому идентификатору.
Вот тут вот и возникает желание почесать затылок: получается, что использовать идентификаторы вроде как нельзя, а с другой стороны во многих задачах без их использования не обойтись.
Самое простое, что можно придумать в данной ситуации — это сделать перечисления идентификаторов инфоблоков, а их свойств и значений списков в виде статических классов со списком констант.
// Перечисление ID инфоблоков
class MyIBlocks{
const News = 1;
const Products = 2;
}
// Перечисление ID свойств
class MyProperties{
const Weight = 10;
const Photos = 11;
}
// Перечисление ID свойств типа "список"
class MyEnums{
const Prop1Yes = 1;
const Prop1No = 2;
}
$newsIBlockId = MyIBlocks::News;
$weightPropertyId = MyProperties::Weight;
$prop1YesValueId = MyEnums::Prop1Yes;
Это решение самое простое и я бы сказал идеальное, но вот только не в нашем грешном мире. Очень редко получается определить структуру инфоблоков с первого раза так, чтобы потом не изменять, не добавлять новые свойства. А после каждого изменения нам придётся в ручную править наши классики-перечисления, чтобы держать их в актуальном виде. Если же говорить о готовом решении для битрикса, то наши перечисления вообще не решают проблемы, потому что мы не можем заранее знать какие идентификаторы инфоблоков, свойств инфоблоков и значений списков будут у пользователя нашего решения.
Сталкиваясь с этой проблемой и запинаясь о её подводные камни на различных проектах, я разработал класс CIBlockTools [11], самостоятельно сканирующий структуру инфоблоков и позволяющий получить значение ID инфоблоков и т.п. в зависимости от их символьного кода.
CIBlockTools позволяет:
C помощью CIBlockTools более не надо записывать ID инфоблоков напрямую в вызовах API как магические числа, например:
$dbProducts = CIBlockElement::GetList(
false,
array(
'IBLOCK_ID' => CIBlockTools::GetIBlockId('news'),
'PROPERTY_TOPICAL' => CIBlockTools::GetPropertyEnumValueId('news', 'TOPICAL', 'yes')
)
);
Принцип работы CIBlockTools прост. При первом использовании он сканирует структуру инфоблоков и сохраняет необходимые данные в кэше битрикса. После этого класс берёт данные из кэша, не обращаясь к БД. При любом изменении инфоблоков и их свойств кэш автоматически сбрасывается.
Туториал по использованию можно посмотреть на Github [11]
Автор: xescoder
Источник [12]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/php-2/37692
Ссылки в тексте:
[1] CIBlockElement::GetProperty: http://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockelement/getproperty.php
[2] CIBlockElement::SetPropertyValues: http://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockelement/setpropertyvalues.php
[3] CIBlockElement::SetPropertyValuesEx: http://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockelement/setpropertyvaluesex.php
[4] CIBlockProperty::GetPropertyEnum: http://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockproperty/getpropertyenum.php
[5] CIBlockPropertyEnum::GetList: http://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockpropertyenum/getlist.php
[6] OnBeforeIBlockElementAdd: http://dev.1c-bitrix.ru/api_help/iblock/events/onbeforeiblockelementadd.php
[7] OnAfterIBlockElementAdd: http://dev.1c-bitrix.ru/api_help/iblock/events/onafteriblockelementadd.php
[8] OnBeforeIBlockElementUpdate: http://dev.1c-bitrix.ru/api_help/iblock/events/onbeforeiblockelementupdate.php
[9] OnAfterIBlockElementUpdate: http://dev.1c-bitrix.ru/api_help/iblock/events/onafteriblockelementupdate.php
[10] CIBlockElement::GetList: http://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockelement/getlist.php
[11] CIBlockTools: https://github.com/xescoder/bitrix-iblock-tools
[12] Источник: http://habrahabr.ru/post/185080/
Нажмите здесь для печати.