Вчера при разработке модуля использующего HLB и свои UserType поля наткнулся на интересный баг.
После добавления своего типа пользовательского поля, и добавление его в HL блок, стало появляться исключение описанное в сабже. ORM никак не желал верить в то что поле UF_MY_FIELD существует. Пришлось одевать чистые сапоги и лезть в ядро.
Решение
Не компилировать свои HLBTable (использующие ваши UserType поля подключаемые в модуле) через HighloadBlockTable::compileEntity(), a создавать их вручную.
Причина
Расследование началось именно с метода компиляции сущности HLB:
,так как мой HLBTable::getMap() возвращал только поле ID (это не типичный признак ошибки, может возвращать все поля до написанного вами поля).
Там мы видим что запрос полей по идентификатору HLB так же, возвращает только поля до кастомного UserType поля.
Далее пришел к тому что в методе:
, не формируется полный список полей так как для определённых типов возвращается FALSE
И вот мы подобрались багу, метод CUserTypeManager::GetUserType(); что бы было понятно вот скрин:
Другими словами тип кастомного пользовательского поля ищется в списке типов, до того как он туда попадает, было бы хуже если бы список не кэшировался, тогда бы нас ожидала рекурсия.
Именно поэтому нельзя компилировать HLBTable имеющие кастомные поля при include модуля.
А ещё...
Эта ошибка может возникнуть даже если кастомное поле не присвоено компилируемому HLB, причем пропасть может даже поле со стандартным типом, например string.
Причина вся в сортировке обработчиков события OnUserTypeBuildList, по умолчанию стандартные типы имеют сортировку 100, с такой же сортировкой добавляются ваши обработчики, в которых она не задана. В итоге обработчик созданного вами типа может быть вызван ранее обработки стандартных типов, и компиляция HLB произойдёт по не полному списку типов свойств.
Не забывайте про сортировку, это 6-й параметр.
После добавления своего типа пользовательского поля, и добавление его в HL блок, стало появляться исключение описанное в сабже. ORM никак не желал верить в то что поле UF_MY_FIELD существует. Пришлось одевать чистые сапоги и лезть в ядро.
Решение
Не компилировать свои HLBTable (использующие ваши UserType поля подключаемые в модуле) через HighloadBlockTable::compileEntity(), a создавать их вручную.
Причина
Расследование началось именно с метода компиляции сущности HLB:
Bitrix\Highloadblock\HighloadBlockTable::compileEntity(); |
Там мы видим что запрос полей по идентификатору HLB так же, возвращает только поля до кастомного UserType поля.
Далее пришел к тому что в методе:
CUserTypeManager::GetUserFields(); |
И вот мы подобрались багу, метод CUserTypeManager::GetUserType(); что бы было понятно вот скрин:
Другими словами тип кастомного пользовательского поля ищется в списке типов, до того как он туда попадает, было бы хуже если бы список не кэшировался, тогда бы нас ожидала рекурсия.
Именно поэтому нельзя компилировать HLBTable имеющие кастомные поля при include модуля.
А ещё...
Эта ошибка может возникнуть даже если кастомное поле не присвоено компилируемому HLB, причем пропасть может даже поле со стандартным типом, например string.
Причина вся в сортировке обработчиков события OnUserTypeBuildList, по умолчанию стандартные типы имеют сортировку 100, с такой же сортировкой добавляются ваши обработчики, в которых она не задана. В итоге обработчик созданного вами типа может быть вызван ранее обработки стандартных типов, и компиляция HLB произойдёт по не полному списку типов свойств.
Не забывайте про сортировку, это 6-й параметр.
RegisterModuleDependences('main', 'OnUserTypeBuildList', 'my_module', '\My\UF\MyFieldType', 'GetUserTypeDescription', 9999); |