Main 26.700.0: в ядре появились фича-флаги
Битрикс выкатил main 26.700.0 — и это тот редкий случай, когда в ядре появляется целая новая подсистема: фича-флаги Bitrix\Main\Config\Feature с двумя таблицами в БД. Плюс несколько тихих поведенческих изменений, которые стоит проверить, если у вас не-UTF-8 сайт, кастомные фильтры пользователей или наследники сущностей AccessRights. Дифф — 139 файлов, +3480/−1615 строк.
Что сломается
Начнём с неприятного — с того, что молча меняет поведение.
Uri::urnEncode() больше не перекодирует по умолчанию
У Bitrix\Main\Web\Uri::urnEncode($str, $charset) дефолт второго параметра поменялся с 'UTF-8' на false, и ветки логики поменялись местами. Раньше строка по умолчанию перекодировалась из кодировки сайта в UTF-8 перед rawurlencode. Теперь по умолчанию — просто rawurlencode без перекодировки; конвертация включается, только если явно передать $charset, отличающийся от кодировки сайта.
На UTF-8-сайтах ничего не изменится. На не-UTF-8 — изменится. Ядро свои вызовы адаптировало (например, Engine\Response\Zip\EntryBuilder теперь зовёт urnEncode() без 'UTF-8'), ваш код придётся проверить руками.
CHTTP::URN2URI() переписан
Метод теперь работает через (new Uri($urn))->toAbsolute($server_name ?: null). Убрана ручная сборка протокола и срезание портов :80/:443 из HTTP_HOST; для пустого $urn результат обрезается rtrim($url, '/'). Если у вас сайт живёт на нестандартном порту — поведение может отличаться от старого.
У сущностей AccessRights пропал loadModel()
Публичный loadModel() удалён у AccessDirector, AccessTeamDirector, StructureDepartment, StructureTeam и UserAll в Bitrix\Main\UI\AccessRights\Entity\*. Логика уехала в новый трейт HrStructureModelTrait. Если вы наследовались от этих классов и переопределяли или вызывали loadModel() — это изменение контракта, готовьтесь чинить.
Фильтр пользователей стал доступнее
Bitrix\Main\Filter\UserDataProvider::getAdminAvailability() больше не проверяет $USER->canDoOperation('edit_all_users') — остались только условия по экстранету. То есть пункт фильтра теперь виден пользователям без права edit_all_users. Если вы на это право опирались — учтите.
Помельче, но тоже про контракты
UpdateSystem\Migration\Agent::__construct(): параметр переименован$cAgentClass→$agentClass. Ломает только вызовы с именованными аргументами.Web\Http\Curl\Handler: Response теперь создаётся вreceiveBody()через новый публичныйbuildResponse(), а не вreceiveHeaders();receiveBody()больше не возвращаетfalseпри отсутствии заголовков. Класс помечен@internal, но если вы от него наследовались — проверяйте.- Формат debug-лога HttpClient изменился: «шапка» с бэктрейсом больше не пишется автоматически из
Handler::log()— за неё отвечает отдельныйlogBacktrace()и новый флагHttpDebug::BACKTRACE(входит вHttpDebug::DEFAULT;ALLтеперь0b01111111). Если вы парсите логиmain.HttpClient— формат поедет.
А вот «изменения сигнатур» CDatabasePgSql::Add/Insert/PrepareUpdate из api.diff — ложная тревога: только реформат пробелов и array() → [].
Deprecated: одного добавили, одного помиловали
CHTTP::ParseAuthRequest()теперь официально@deprecated— фактически там просто починили docblock (/*→/**). Рекомендованная замена:\Bitrix\Main\Server::parseAuthRequest().- Обратный ход: с
CEventMessageпометку@deprecatedсняли. Старый API почтовых шаблонов снова «легален». Такое бывает нечасто.
Новое: фича-флаги в ядре
Главная новинка релиза — подсистема Bitrix\Main\Config\Feature: 12 новых файлов в lib/Config/Feature*. Флаг — это не строчка в опциях, а полноценный PHP-класс: его FQCN и есть код флага.
Как это устроено:
Config\Feature— статический фасад:isEnabled/isDisabled/enable/disable/allow/deny/clearRules/resetToDefault/clearCache.Feature\AbstractFlag— базовый класс флага с хукамиonEnable()/onDisable(), которые срабатывают только при фактической смене значения в БД.Feature\AbstractRule+ enumRulePolicy(allow/deny) и два готовых правила:Rules\UserIdRule(по списку ID пользователей) иRules\ModuleMinVersionRule(по минимальной версии модуля).Feature\Context(userId + params,getCurrent()),Feature\Factory, ORM-таблетыFeatureFlagTable/FeatureFlagRuleTable.- Порядок проверки в
FeatureManager: requirements → deny-правила → allow-правила → значение в БД →enabledByDefault(). Значения и правила кешируются на 86400 секунд.
Свой флаг выглядит примерно так:
<?php declare(strict_types=1);
namespace Vendor\Module\Feature;
use Bitrix\Main\Config\Feature\AbstractFlag;
final class NewCheckoutFlag extends AbstractFlag
{
public function enabledByDefault(): bool
{
return false;
}
}
А в коде — проверка и раскатка на избранных:
use Bitrix\Main\Config\Feature;
use Bitrix\Main\Config\Feature\Rules\UserIdRule;
use Vendor\Module\Feature\NewCheckoutFlag;
// пустить в новый чекаут только тестовую группу:
// правило передаётся именем класса, аргументы — конфигом
Feature::allow(NewCheckoutFlag::class, UserIdRule::class, ['userIds' => [1, 42, 137]]);
if (Feature::isEnabled(NewCheckoutFlag::class)) {
// новый флоу
}
Две детали, которые стоит знать заранее. Первая: неизвестный класс флага считается включённым — логика «feature was enabled and removed from codebase»: удалили класс — значит, фича доехала до всех. Вторая: раз в день Feature\CleanupAgent вычищает из таблиц записи флагов и правил, классов которых больше нет в коде. FeatureManager зарегистрирован сервисом в .settings.php модуля main, логгер — main.config.feature.
Новое: по мелочи, но полезно
ModuleManager::getModificationDateTime(string $moduleName): ?DateTime— дата модификацииversion.phpмодуля черезfilemtime. ЗаодноModuleManager::add()обернули вtry/catch (DuplicateEntryException)— повторная регистрация модуля больше не роняет установку.CUserFieldEnum::getDefaultValue(int $fieldId): array— статический кеш значений по умолчанию для enum-полей (сброс — через protectedcleanCache(), снаружи он не вызывается);UserField\Types\EnumType::getDefaultValue()переведён на него вместо прямого запроса.- В JS
main.coreкешBaseCacheпереехал с гологоMapна абстракциюICacheStorage(memory- и localStorage-реализации),get/setполучили дженерик-перегрузки, аTag.render— параметр типаT = HTMLElementв TS-типах.
БД
- Две новые таблицы под фича-флаги:
b_feature_flag(PKCODE, поляMODULE_ID,ENABLED,MODIFIED_AT,MODIFIED_BY, индекс поMODULE_ID) иb_feature_flag_rule(ID,FEATURE_CODE,POLICY,RULE_CODE,RULE_ARGS,MODIFIED_AT,MODIFIED_BY, индекс поFEATURE_CODE) — и в mysql, и в pgsql install.sql. - Новый индекс
ix_b_user_field_enum_defпо полюDEFтаблицыb_user_field_enum— под тот самыйCUserFieldEnum::getDefaultValue(). db.diffпуст: изменения зафиксированы только в install.sql для новых установок, на существующих их накатит апдейтер.
Мелочи и находки
- Тихий XSS-фикс: в шаблоне
main.interface.toolbarпараметры кнопокLINK,TITLE,ICON,TEXTтеперь прогоняются черезhtmlspecialcharsbx(). Если вы туда передавали готовый HTML — он перестанет быть HTML. - Фикс конкуренции очередей Messenger: ключ блокировки стал per-таблице (
queueLock_<имя_таблицы>вместо общегоqueueLock). Раньше разные очереди делили один лок и мешали друг другу. Uri::convertToPunycode()/convertToUnicode()получили быстрый выход: конвертация запускается, только если хост содержит не-ASCII символы или подстрокуxn--.punycode.phpдаёт ~1180 строк диффа — но это почти целиком реформат кодстайла без смены алгоритма. То же с sql-хелперами (mssql/oracle/pgsql/mysqli),PhoneNumber/MetadataProvider.phpиUI/Uploader/File.php:array()→[], camelCase, скобки.- Ходившая гипотеза о переезде файлов
lib/Mail/Internalна PascalCase/PSR-4 не подтвердилась: в files-added только 13 файлов (Config/Feature/*иHrStructureModelTrait.php), удалённых нет. - В
application.phpпри переименовании переменных бережно сохранён вечный TODO: «Should be transfered to where GET parameter is defined in future». Традиции. - В
xml.phpвgetAttributesNodesArray()добавили страховку от$ret, не являющегося массивом, — обходной манёвр вместо честного исправления типа переменной.
Релиз 26.700.0 датирован 2026-08-24 — предыдущий 26.650.100 вышел всего 12 дней назад. Вердикт: обновляться можно спокойно, но не-UTF-8 сайтам и владельцам кастомизаций вокруг AccessRights и фильтра пользователей — сначала прогнать тесты.
Устаревшие и удалённые API в этой версии
| Символ | Статус | Чем заменять |
|---|---|---|
CHTTP::ParseAuthRequest()
|
Deprecated |
Bitrix\Main\Server::parseAuthRequest()
|
Bitrix\Main\UI\AccessRights\Entity\AccessDirector::loadModel()
|
Удалено |
Bitrix\Main\UI\AccessRights\Entity\HrStructureModelTrait
|
Bitrix\Main\UI\AccessRights\Entity\AccessTeamDirector::loadModel()
|
Удалено |
Bitrix\Main\UI\AccessRights\Entity\HrStructureModelTrait
|
Bitrix\Main\UI\AccessRights\Entity\StructureDepartment::loadModel()
|
Удалено |
Bitrix\Main\UI\AccessRights\Entity\HrStructureModelTrait
|
Bitrix\Main\UI\AccessRights\Entity\StructureTeam::loadModel()
|
Удалено |
Bitrix\Main\UI\AccessRights\Entity\HrStructureModelTrait
|
Bitrix\Main\UI\AccessRights\Entity\UserAll::loadModel()
|
Удалено |
Bitrix\Main\UI\AccessRights\Entity\HrStructureModelTrait
|