Вчера при разработке модуля использующего HLB и свои UserType поля наткнулся на интересный баг.
После добавления своего типа пользовательского поля, и добавление его в HL блок, стало появляться исключение описанное в сабже. ORM никак не желал верить в то что поле UF_MY_FIELD существует. Пришлось одевать чистые сапоги и лезть в ядро.
Решение
Не компилировать свои HLBTable (использующие ваши UserType поля подключаемые в модуле) через HighloadBlockTable::compileEntity(), a создавать их вручную.
Причина
Расследование началось именно с метода компиляции сущности HLB:
,так как мой HLBTable::getMap() возвращал только поле ID (это не типичный признак ошибки, может возвращать все поля до написанного вами поля). Там мы видим что запрос полей по идентификатору HLB так же, возвращает только поля до кастомного UserType поля.
Далее пришел к тому что в методе:
CUserTypeManager::GetUserFields();
, не формируется полный список полей так как для определённых типов возвращается FALSE
И вот мы подобрались багу, метод CUserTypeManager::GetUserType(); что бы было понятно вот скрин:
Другими словами тип кастомного пользовательского поля ищется в списке типов, до того как он туда попадает, было бы хуже если бы список не кэшировался, тогда бы нас ожидала рекурсия.
Именно поэтому нельзя компилировать HLBTable имеющие кастомные поля при include модуля.
А ещё...
Эта ошибка может возникнуть даже если кастомное поле не присвоено компилируемому HLB, причем пропасть может даже поле со стандартным типом, например string.
Причина вся в сортировке обработчиков события OnUserTypeBuildList, по умолчанию стандартные типы имеют сортировку 100, с такой же сортировкой добавляются ваши обработчики, в которых она не задана. В итоге обработчик созданного вами типа может быть вызван ранее обработки стандартных типов, и компиляция HLB произойдёт по не полному списку типов свойств.
Наткнулся на такую ошибку при наследовании от класса, полученного после HighloadBlockTable::compileEntity()
Однако есть решение. Необходимо переопределить все методы, которые будут использоваться и в которых возникает ошибка и организовать в них прямой вызов метода наследуемого класса
пример
namespace My\Entity;
class OrderTable extends \AOrderTable{
public static $parentClass = "\AOrderTable";
public static function getList($arParams){
return self::$parentClass::getList($arParams);
}
}
class Order extends OrderTable{}
где "\AOrderTable" - это результат компиляции highload блока
Якимов Антон, не делайте так никогда, изучите подробно статьи по ORM Битрикса, объявляйте сущности и их поля вручную, компиляция сущностей через HighloadBlockTable это плохо
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».