Система прокси
ADP использует паттерн прокси для прозрачного перехвата вызовов PSR-интерфейсов. Прокси оборачивают стандартные PSR-реализации и передают перехваченные данные коллекторам без изменения кода приложения.
Как это работает
Прокси реализует тот же PSR-интерфейс, что и оригинальный сервис. Он делегирует все вызовы реальной реализации, одновременно записывая данные для парного коллектора.
Код приложения
│
▼
┌─────────────────┐
│ PSR-интерфейс │ ← Код вызывает как обычно
│ (напр. Logger) │
└────────┬────────┘
│
┌────────▼────────┐
│ Прокси │ ← Перехватывает + записывает
│ (LoggerProxy) │
└────────┬────────┘
│
┌────────▼────────┐
│ Реальный сервис │ ← Оригинальная реализация
│ (Monolog и т.д.) │
└────────┬────────┘
│
┌────────▼────────┐
│ Коллектор │ ← Получает записанные данные
│ (LogCollector) │
└─────────────────┘Встроенные прокси
Ядро предоставляет фреймворко-независимые PSR-прокси:
Прокси фреймворков
Адаптеры фреймворков предоставляют дополнительные прокси для интерфейсов, не стандартизированных PSR:
Прокси переводчика
У каждого фреймворка свой интерфейс переводчика. ADP предоставляет выделенный прокси для каждого, все они передают данные в один TranslatorCollectorAppDevPanel\Kernel\Collector\TranslatorCollectorCaptures translation lookups during request execution.. Подробности на странице Переводчик.
Symfony -- SymfonyTranslatorProxyAppDevPanel\Adapter\Symfony\Proxy\SymfonyTranslatorProxyDecorates Symfony's TranslatorInterface to feed translation lookups to TranslatorCollector. декорирует TranslatorInterfaceSymfony\Contracts\Translation\TranslatorInterfaceSymfony Translation Contract. Translates messages using message catalogs. через setDecoratedService() в compiler pass. Перехватывает вызовы trans().
Laravel -- LaravelTranslatorProxyAppDevPanel\Adapter\Laravel\Proxy\LaravelTranslatorProxyDecorates Laravel's Translator to feed translation lookups to TranslatorCollector. декорирует TranslatorIlluminate\Contracts\Translation\TranslatorLaravel Translator Contract. Provides translation services for the application. через $app->extend('translator'). Перехватывает вызовы get() и choice(). Разбирает точечную нотацию ключей Laravel (group.key) на категорию и сообщение.
Yii 3 -- TranslatorInterfaceProxyAppDevPanel\Adapter\Yii3\Collector\Translator\TranslatorInterfaceProxyDecorates Yiisoft TranslatorInterface to feed translation lookups to TranslatorCollector. регистрируется в trackedServices наряду с ValidatorInterfaceProxyAppDevPanel\Adapter\Yii3\Collector\Validator\ValidatorInterfaceProxyDecorator proxy for Validator Interface. Intercepts calls and forwards data to collectors.. Перехватывает вызовы translate(). Поддерживает иммутабельные методы withDefaultCategory() и withLocale().
Yii 2 -- I18NProxyAppDevPanel\Adapter\Yii2\Proxy\I18NProxyDecorates Yii 2's I18N component to feed translation lookups to TranslatorCollector. наследует yii\i18n\I18N и переопределяет translate(). Заменяет компонент приложения i18n при загрузке модуля.
Обнаружение отсутствующих переводов
Все прокси определяют отсутствие перевода, сравнивая возвращённое значение переводчика с исходным идентификатором сообщения. Если они совпадают, перевод помечается как missing.
Трейт ProxyDecoratedCalls
Трейт ProxyDecoratedCalls предоставляет магические методы __call, __get и __set, которые делегируют вызовы обёрнутому сервису. Прокси используют этот трейт для прозрачной переадресации неперехватываемых вызовов.
Регистрация прокси
Прокси регистрируются адаптерами фреймворков через конфигурацию DI-контейнера. Адаптер заменяет оригинальную привязку PSR-сервиса на прокси:
// Упрощённая DI-конфигурация адаптера
LoggerInterface::class => function (ContainerInterface $c) {
return new LoggerInterfaceProxy(
$c->get(LogCollector::class),
$c->get('original.logger'),
);
},Ключевые принципы
- Прозрачность -- код приложения не знает о перехвате
- Нулевые затраты при отключении -- прокси регистрируются только при активном ADP
- PSR-совместимость -- прокси реализуют тот же интерфейс, что и оригинальный сервис
- Колокация -- каждый прокси находится рядом с парным коллектором в
src/Collector/