--- name: bitrix-best-practice-core description: Use when designing, reviewing, or implementing any PHP code. --- # Bitrix Core Best Practice Скилл помогает понять, какие нужно использовать Bitrix/PHP best practices. ## Как использовать 1. Определи архитектурный слой, который затрагивает задача. 2. Открой только те rule-файлы, которые напрямую относятся к этому слою. 3. Сначала следуй более строгим правилам репозитория и ограничениям модуля. 4. Предпочитай framework-native паттерны Bitrix вместо собственных абстракций. ## Выбор rule-файла ### Когда читать controller.md Читай [controller.md](rules/controller.md), если задача затрагивает хотя бы одну из этих областей: - класс, наследующий `Bitrix\Main\Engine\Controller` или его наследника; - любой `*Action()`-метод; - filters, attributes, prefilters и ответы Engine Controller. ### Когда читать error.md Читай [error.md](rules/error.md), если задача затрагивает хотя бы одну из этих областей: - `Bitrix\Main\Error`, `Bitrix\Main\ErrorCollection` или прикладные error-классы поверх них; - `getErrors()`, `getError()`, `getErrorCollection()` или `getErrorByCode()` в service, controller или response flow; - выбор `code`, `customData` и публичного error-contract для UI, AJAX или другого клиента; - перенос уже созданных ошибок между `Result`, controller lifecycle и `AjaxJson`. ### Когда читать result.md Читай [result.md](rules/result.md), если задача затрагивает хотя бы одну из этих областей: - `Bitrix\Main\Result`, `isSuccess()`, `setData()`, `getData()`, `addError()` или `addErrors()`; - возврат `Result` из service, command, handler или integration layer как outcome-contract; - выбор между `Bitrix\Main\Result`, самодельным `*Result`-классом и неявным массивом как return DTO; - состав payload в `Result::setData()` и граница между success-data и error flow. ### Когда читать request.md Читай [request.md](rules/request.md), если задача затрагивает хотя бы одну из этих областей: - `Bitrix\Main\Request`, `HttpRequest`, `$this->getRequest()` или `Context::getCurrent()->getRequest()`; - выбор между `get()`, `getQuery()`, `getPost()`, `getHeader()`, `getCookie()` или `getJsonList()`; - замена `$_REQUEST`, `$_GET`, `$_POST`, `$_COOKIE` и `php://input` на framework-native request API; - JSON body, `JsonPayload`, `decodeJson()` или `decodeJsonStrict()`. ### Когда читать response.md Читай [response.md](rules/response.md), если задача затрагивает хотя бы одну из этих областей: - `Bitrix\Main\Response`, `HttpResponse`, `addHeader()`, `setStatus()`, `addCookie()` или `redirectTo()`; - `Bitrix\Main\Engine\Response\Json`, `AjaxJson`, `Redirect`, `File`, `HtmlContent` или render-response helper'ы; - замена ручного `header()`, `Set-Cookie`, `setcookie()` или `json_encode()` на штатный response layer Bitrix; - выбор типа HTTP-ответа для controller action или другого infrastructure endpoint. ### Когда читать routing.md Читай [routing.md](rules/routing.md), если задача затрагивает хотя бы одну из этих областей: - файл в `/install/routes/` или регистрация маршрутов в `/bitrix/routes/` и `/local/routes/`; - `RoutingConfigurator`, `prefix`, `group`, HTTP-методы маршрута, `where`, `default`, `name`; - `PublicPageController` или перенос legacy URL с `urlrewrite.php` на modern routing; - site-guard и маршруты для конкретного сайта в мультисайтовой установке; - массив `[Controller::class, 'action']` в маршруте. ### Когда читать loader.md Читай [loader.md](rules/loader.md), если задача затрагивает хотя бы одну из этих областей: - `Loader::includeModule()` или `Loader::requireModule()`; - `CModule::IncludeModule()` или `CModule::IncludeModuleEx()`; - optional module integration с fallback при отсутствии модуля; - fail-fast dependency, где отсутствие модуля должно привести к ошибке, а не к тихому пропуску. ### Когда читать geo-ip.md Читай [geo-ip.md](rules/geo-ip.md), если задача затрагивает хотя бы одну из этих областей: - `Bitrix\Main\Service\GeoIp\Manager`, `getRealIp()`, `getDataResult()` или convenience getters вроде `getCountryCode()` / `getCityName()`; - `Bitrix\Main\Web\IpAddress` в контексте GeoIP lookup, range cache или различий между IPv4 и IPv6 для geodata; - custom GeoIP handler, наследник `Bitrix\Main\Service\GeoIp\Base` или регистрация через `onMainGeoIpHandlersBuildList`; - post-processing GeoIP результата через `onGeoIpGetResult`; - выбор между простым string lookup и полным `Result`-based GeoIP lookup. - определение геолокации ### Когда читать uri.md Читай [uri.md](rules/uri.md), если задача затрагивает хотя бы одну из этих областей: - `Bitrix\Main\Web\Uri`, `new Uri($url)`, `getQuery()`, `addParams()`, `deleteParams()`, `toAbsolute()` или `resolveRelativeUri()`; - разбор, изменение или пересборка URL / URI / redirect URL в Bitrix-коде; - выбор между `Uri`, `parse_url()` и `parse_str()` для query string, host, path, fragment или absolute URL; - query-параметры с точками или пробелами, где важен `preserveDots`. ### Когда читать http-client.md Читай [http-client.md](rules/http-client.md), если задача затрагивает хотя бы одну из этих областей: - `Bitrix\Main\Web\HttpClient`, `new HttpClient()`, `get()`, `post()`, `query()` или `download()`; - outbound HTTP(S)-запросы, webhook sender, remote download/upload или external API integration; - замена `file_get_contents($url)` / `stream_context_create()` для remote `http`/`https` URL; - замена `curl_init`, `curl_setopt`, `curl_exec` и других raw `curl_*` вызовов на framework-native transport. ### Когда читать jwt.md Читай [jwt.md](rules/jwt.md), если задача затрагивает хотя бы одну из этих областей: - `Bitrix\Main\Web\JWT`, `JWT::encode()`, `JWT::decode()`, `JWT::urlsafeB64Encode()` или `JWT::urlsafeB64Decode()`; - `Bitrix\Main\Web\JWK`, `JWK::parseKeySet()` или `JWK::parseKey()`; - выпуск, проверка или разбор JWT / JWK / JWKS / JOSE-compatible данных; - выбор между framework-native JWT/JWK API и ручной сборкой токена, key parsing или Base64 URL-safe helper-ом. ### Когда читать date-time.md Читай [date-time.md](rules/date-time.md), если задача затрагивает хотя бы одну из этих областей: - `Bitrix\Main\Type\Date` или `Bitrix\Main\Type\DateTime`; - `createFromUserTime()`, `tryParse()`, `toUserTime()`, `toString()`, `createFromTimestamp()` или `createFromPhp()`; - parsing, formatting или timestamp conversion для даты и времени в Bitrix-коде; - выбор между Bitrix date types и `\DateTime` / `\DateTimeImmutable`. ### Когда читать option.md Читай [option.md](rules/option.md), если задача затрагивает хотя бы одну из этих областей: - `Bitrix\Main\Config\Option`, `Option::get()`, `set()`, `getRealValue()`, `getForModule()` или `delete()`; - `COption::GetOptionString()`, `SetOptionString()`, `GetOptionInt()` или `RemoveOption()` как legacy trigger; - `default_option.php`, module `options.php`, site-specific setting или feature flag / policy в БД; - выбор между постоянной конфигурацией в `Option`, deploy-time config в `.settings.php` и временным runtime-state. ### Когда читать logger.md Читай [logger.md](rules/logger.md), если задача затрагивает хотя бы одну из этих областей: - `Bitrix\Main\Diag\Logger`, `Bitrix\Main\Diag\LoggerFactory`, `LoggerRegistry`, `FileLogger` или `LogFormatter`; - `Psr\Log\LoggerInterface`, PSR-3 levels (`info`, `warning`, `error`, `debug`) и structured `context`; - регистрацию logger id в `.settings.php` через секцию `loggers` или DI через `constructorParams`; - замену `AddMessage2Log()`, `Logger::create()` или ad hoc `file_put_contents()` / `error_log()` на framework-native logging path; - выбор между именованным logger id, default logger fallback и legacy logging boundary. ### Когда читать uuid-generator.md Читай [uuid-generator.md](rules/uuid-generator.md), если задача затрагивает хотя бы одну из этих областей: - `Bitrix\Main\UuidGenerator` или `UuidGenerator::generateV4()`; - генерацию UUID v4 для session id, correlation id, upload token, public proxy id или другого random opaque identifier; - выбор между `UuidGenerator`, `uniqid()`, `Random::getBytes()`, ручной сборкой UUID или локальным helper-генератором; - legacy boundary, где нужен UUID в обертке вроде `{uuid}`, но canonical generator должен остаться единым. ### Когда читать validation.md Читай [validation.md](rules/validation.md), если задача затрагивает хотя бы одну из этих областей: - `Bitrix\Main\Validation\Rule\...` на параметрах `*Action()` или свойствах input object; - `ValidationParameter`, `ValidationService`, `ValidationResult`, `ValidationError` или `ValidationGroup`; - автоматическая валидация входа до входа в action или ручная валидация DTO / command в service layer; - выбор между validation attributes, `ValidationParameter` и явным `ValidationService::validate()`; - custom validators и custom validation attributes поверх `Bitrix\Main\Validation`. ### Когда читать service-locator.md Читай [service-locator.md](rules/service-locator.md), если задача затрагивает хотя бы одну из этих областей: - `Bitrix\Main\DI\ServiceLocator`, `ServiceLocator::getInstance()`, `get()`, `has()`, `addInstance()` или `addInstanceLazy()`; - `{module}/.settings.php`, service registration, service id, FQCN binding или interface binding для DI; - выбор между action autowiring, explicit `ServiceLocator::get(...)` и ручным `new MyService()` для shared service; - замена ad hoc создания service-класса на framework-native container path. ### Когда читать persistent-storage.md Читай [persistent-storage.md](rules/persistent-storage.md), если задача затрагивает хотя бы одну из этих областей: - `Bitrix\Main\Data\Storage\PersistentStorageInterface`, `StorageInterface`, `DeferredStorageDecorator` или `ServiceLocator::get(PersistentStorageInterface::class)`; - `Bitrix\Main\Config\Option::get()` / `Option::set()` в сценарии, где нужно понять, конфигурация это или временное runtime-state; - TTL state, progress/checkpoint, one-time token, upload/import session, rate-limit counter или другой временный server-side state между запросами; - выбор между `Option`, persistent storage и cache (`Bitrix\Main\Data\Cache` / `ManagedCache`) для хранения данных. ### Когда читать cache.md Читай [cache.md](rules/cache.md), если задача затрагивает хотя бы одну из этих областей: - `Bitrix\Main\Data\Cache`, `ManagedCache`, `TaggedCache`, `Cache::createInstance()`, `initCache()`, `startDataCache()`, `endDataCache()` или `abortDataCache()`; - `Application::getInstance()->getCache()`, `getManagedCache()`, `getTaggedCache()` или container binding cache-сервисов в `main/.settings.php`; - выбор между простым TTL-cache, managed invalidation по key/dir и tag-based invalidation; - `CPHPCache`, `CCacheManager`, `$CACHE_MANAGER` или `CStackCacheManager` как legacy trigger; - derived read-cache, который можно потерять и пересчитать, в отличие от runtime-state и постоянной конфигурации. ### Когда читать event.md Читай [event.md](rules/event.md), если задача затрагивает хотя бы одну из этих областей: - `Bitrix\Main\Event`, `EventResult`, `EventManager`, `send()` или `getResults()`; - генерацию классов событий и обработчиков через Bitrix CLI; - создание собственного события, контракт параметров и ответов обработчиков или отмену операции по результатам события; - `addEventHandler()`, `registerEventHandler()`, compatible-варианты, порядок вызова и снятие подписок; - `AddEventHandler()` или `RegisterModuleDependences()` как legacy trigger и перенос позиционных обработчиков на D7.