proklung / bitrix-core-symfony
Core Symfony functionality for Bitrix
Requires
- php: >=7.4 | ~8
- guzzlehttp/psr7: ^1.8 || ^2
- nyholm/psr7: ^1.4
- proklung/base-exception: ^1.0
- psr/container: 1.0.*
- psr/http-client: ^1.0
- symfony/cache: ^4.4 || ^5.0
- symfony/config: ^4.4 || ^5.0
- symfony/console: ^4.4 || ^5.0
- symfony/dependency-injection: ^4.4 || ^5.0
- symfony/dotenv: ^4.4 || ^5.0
- symfony/event-dispatcher: ^4.4 || ^5.0
- symfony/expression-language: ^4.4 || ^5.0
- symfony/filesystem: ^4.4 || ^5.0
- symfony/framework-bundle: ^4.4 || ^5.0
- symfony/http-client: ^4.4 || ^5.0
- symfony/http-foundation: ^4.4 || ^5.0
- symfony/http-kernel: ^4.4 || ^5.0
- symfony/property-access: ^4.4 || ^5.0
- symfony/proxy-manager-bridge: ^4.4 || ^5.0
- symfony/psr-http-message-bridge: ^2.1
- symfony/routing: ^4.4 || ^5.0
- symfony/serializer: ^4.4 || ^5.0
- symfony/validator: ^4.4 || ^5.0
- symfony/yaml: ^4.4 || ^5.0
- twig/twig: ~1.0 || ~2 || ~3
- vlucas/phpdotenv: 3.* || 4.*
Requires (Dev)
- dev-master
- 1.6.3
- 1.6.2
- 1.6.1
- 1.6.0
- 1.5.0
- 1.4.45
- 1.4.5
- 1.4.4
- 1.4.3
- 1.4.2
- 1.4.1
- 1.4.0
- 1.3.9
- 1.3.8
- 1.3.7
- 1.3.6
- 1.3.5
- 1.3.4
- 1.3.3
- 1.3.2
- 1.3.1
- 1.3.0
- 1.2.9
- 1.2.8
- 1.2.7
- 1.2.6
- 1.2.5
- 1.2.4
- 1.2.3
- 1.2.2
- 1.2.1
- 1.2.0
- 1.1.9
- 1.1.8
- 1.1.7
- 1.1.6
- 1.1.5
- 1.1.4
- 1.1.3
- 1.1.2
- 1.1.1
- 1.1.0
- 1.0.99
- 1.0.98
- 1.0.97
- 1.0.96
- 1.0.95
- 1.0.94
- 1.0.93
- 1.0.92
- 1.0.91
- 1.0.90
- 1.0.80
- 1.0.79
- 1.0.78
- 1.0.77
- 1.0.76
- 1.0.75
- 1.0.70
- 1.0.69
- 1.0.68
- 1.0.67
- 1.0.63
- 1.0.62
- 1.0.61
- 1.0.8
- 1.0.7
- 1.0.6
- 1.0.5
- 1.0.4
- 1.0.3
- 1.0.2
- 1.0.1
- 1.0.0
This package is auto-updated.
Last update: 2024-12-10 10:07:16 UTC
README
Установка
composer.json:
"repositories": [ { "type": "git", "url": "https://github.com/proklung/bitrix.core.symfony" } ]
composer require proklung/bitrix-core-symfony
Инициализация
В init.php
:
use Prokl\ServiceProvider\ServiceProvider; $serviceProvider = new ServiceProvider('local/configs/services.yaml');
Для обеспечения "преемственности" (похожести) с оригиналом можно задать путь к файлу конфигурации (скажем, bundles.php
)
бандлов вторым (необязательным) параметром конструктора.
Переменные среды
Предполагается, что переменные среды к моменту инициализации контейнера уже загружены тем или иным способом.
Значимые переменные среды:
-
DEBUG
(булево значение - режим отладки),APP_DEBUG
- алиасDEBUG
, но с большим приоритетом (если одновременно присустствуютDEBUG
иAPP_DEBUG
, то в дело пойдет значениеAPP_DEBUG
). -
APP_ENV
- код окружения. Если код не задан, то будет проинтерпретировано значениеDEBUG
в смысле - если в режиме отладки, то окружениеdev
, иначеprod
.
Если переменные среды не заданы, то с помощью класса Prokl\ServiceProvider\LoadEnvironment
их можно загрузить.
Скажем, в init.php
, перед инициализацией контейнера:
// Параметр конструктора - путь, где лежат файлы .env $loader = new \Prokl\ServiceProvider\LoadEnvironment($_SERVER['DOCUMENT_ROOT'] . '/../..'); $loader->load(); // Загрузка $_ENV $loader->process(); // Обработка переменных
Конфигурирование
- Опция
compile.container
в подтягиваемом конфиге - компилировать ли контейнер в файл. Если не задана, то "нет, не компилировать". Имеет смысл для окружения, не равного "dev". Т.е. опция управляет дампированием контейнера на проде.
Место, где хранятся дампы контейнеров: <значение переменной контейнера kernel.cache_dir>/<SITE_ID>/containers
Пути к кэшу и логам
Определяются классом AppKernel
. По умолчанию:
- путь к кэшу (
kernel.cache_dir
) -/bitrix/cache
- путь к логам (
kernel.logs_dir
) -'/../../logs'
(два уровня выше DOCUMENT_ROOT - особенности используемой сборки Битрикс)
Чтобы это изменить нужно отнаследоваться от класса AppKernel
и переопределить несколько переменных:
use Prokl\ServiceProvider\Services\AppKernel; class MyKernel extends AppKernel { protected $cacheDir = '/bitrix/cache/mycache'; protected $logDir = '/logs-saver'; }
(второй вариант - отнаследоваться от AppKernel
и переопределить методы getCacheDir
и getLogDir
).
Изменить через наследование класс ядра:
class MyServiceProvider extends ServiceProvider { protected $kernelServiceClass = MyKernel::class; protected $cacheDir = '/bitrix/cache/mycache'; }
Второй вариант - отнаследоваться от ServiceProvider
и заменить метод getPathCacheDirectory
своей логикой.
Поддержка бандлов
Файл конфигурации - /config/standalone_bundles.php
. Этот путь можно изменить через конструктор.
Папка, где лежат конфигурации - /local/configs
. Конфигурации бандлов - /local/configs/packages
.
Проблема с приватными сервисами
Согласно концепции Symfony все сервисы (в идеале) должны быть приватными и инжектиться. Но в кастомном случае
часто нужно получать их через хелпер-сервис-локатор. Для превращения нужных сервисов в публичные предлагается
такое решение. В общем разделе параметров контейнера появилась опция publicable_services
:
parameters: publicable_services: - 'snc_redis.default'
После компиляции контейнера приватный сервис snc_redis.default
станет публичным.
Сепаратные микро-контейнеры
Отдельные контейнеры - со своим конфигом, полностью изолированные (для модулей и т.п.).
use Symfony\Component\DependencyInjection\ContainerBuilder; use Prokl\ServiceProvider\Micro\AbstractStandaloneServiceProvider; use Prokl\ServiceProvider\Micro\ExampleAppKernel; class ExampleMicroServiceProvider extends AbstractStandaloneServiceProvider { /** * @var ContainerBuilder $containerBuilder Контейнер. */ protected static $containerBuilder; /** * @var string $pathBundlesConfig Путь к конфигурации бандлов. */ protected $pathBundlesConfig = '/src/Micro/example.config/standalone_bundles.php'; /** * @var string $configDir Папка, где лежат конфиги. */ protected $configDir = '/src/Micro/example.config/example.config/example.yaml'; /** * @var string $kernelServiceClass Класс, реализующий сервис kernel. * Нужен для того, чтобы экземпляры контейнеров в kernel сервисе не перемешивались. */ protected $kernelServiceClass = ExampleAppKernel::class; }
Пример класса ExampleAppKernel
:
use Prokl\ServiceProvider\Micro\AbstractKernel; class ExampleAppKernel extends AbstractKernel { protected static $kernelContainer; }
Где надо - инициализация:
$micro = new ExampleMicroServiceProvider('src/SymfonyDI/Micro/example.config/example.yaml');
Хэлпер container
заточен под работу с микро-сервис-провайдерами:
var_dump(container($micro)->getParameter('example'));
Автозапуск сервисов
Чтобы сервис запустился автоматически после инициализации контейнера, он должен быть помечен тэгом service.bootstrap
.
app.options: class: Prokl\Services\AppOptions arguments: ['%kernel.environment%', '@parameter_bag'] tags: ['service.bootstrap']
Поддерживается приоритет запуска. Тогда надо так:
app.options: class: Local\Services\AppOptions arguments: ['%kernel.environment%', '@parameter_bag'] tags: - { name: 'service.bootstrap', priority: 100 }
Сервис с приоритетом 100 запустится раньше сервиса с приоритетом 200.
Автоматическая подвязка на события Битрикс
Тэг: bitrix.events.init
.
event
- название события.method
- метод-обработчик в сервисеmodule
- модуль событияsort
- сортировка
admin_entity_edit.event_init: class: Local\Bitrix\PsModuleInitializer tags: - { name: bitrix.events.init, module: ps.d7, event: onGetEntityList, method: registerEntities, sort: 0 }
Автоматическое подхватывание расширений Twig
Тэг twig.extension
.
service.twig.parameter: class: Prokl\Bundles\ParameterBundle\Twig\ParameterExtension public: true arguments: - '@service.parameter' tags: - { name: twig.extension }
Сервисы по умолчанию
Автоматом регистрируются сервисы:
service_container
(и alias) - сервис-контейнер целикомapp.request
- конвертор глобалов в Request- синонимы сервиса
kernel
delegated_container_manipulator
- манипулятор делегированными контейнерами.bitrix.request.instance
- Экземпляр битриксового Requestbitrix.response.instance
- Экземпляр битриксового Responsebitrix.request
- Symfony Request, полученный из битриксовогоbitrix.request.psr7
- Битриксовый Request, приведенный к PSR-7bitrix.response
- Symfony Response, полученный из битриксовогоbitrix.response.psr7
- Битриксовый Response, приведенный к PSR-7psr17.http_factory
- HttpFactory стандарта PSR-17psr18.http_client
- Http client стандарта PSR-18
Хэлперы
container()
- отдает экземпляр контейнера (выступает в роли сервис-локатора):
$kernel = container()->get('kernel');
delegatedContainer()
- отдает экземпляр манипулятора (реализующего интерфейсSymfony\Component\DependencyInjection\ContainerInterface
) делегированными контейнерами.
$moduleService = delegatedContainer()->get('my_module_id.service');
В контейнере делегированный контейнер помечается тэгом delegated.container
(их может быть сколь угодно много):
module_notifier_container: class: Symfony\Component\DependencyInjection\ContainerInterface factory: ['Proklung\Notifier\DI\Services', 'getInstance'] tags: - { name: 'delegated.container' }
Делегированный контейнер - автономный контейнер, сформированные в модуле, плагине и тому подобных местах.
Импорт в контейнер сервисов битриксового сервис-локатора
Автоматом подтягиваются в контейнер сервисы из битриксового сервис-локатора. Формат,
секция services
из /bitrix/.settings.php
и /bitrix/.settings_extra.php
. Также загрузчик пробегает
по списку установленных модулей и подцепляет их тоже.
Для отдельных сервис-контейнеров (отнаследованных от AbstractStandaloneServiceProvider
) такая загрузка
не производится.
Если эта фича не нужна, то нужно отнаследоваться от ServiceProvider
и заглушить метод loadBitrixServiceLocatorConfigs
.
class MyServiceProvider extends ServiceProvider { /** * {@inheritDoc} */ protected function loadBitrixServiceLocatorConfigs(DelegatingLoader $loader) : void { } }
BitrixSettingsDiAdapter
Адаптер-импортер настроек битриксового сервис-локатора (.settings.php
) в симфонический контейнер.
importParameters(ContainerInterface $container, array $settings, ?string $section = null)
- импорт параметров.section
- если задано, то параметры лягут в именованную секцию параметров контейнера.importServices(ContainerInterface $container, array $services)
- импорт сервисов. Формат
Считываются конфиги в Битриксе как-то так:
use Bitrix\Main\Config\Configuration; $this->config = Configuration::getInstance()->get('my_config') ?? []; // Из модуля $this->parameters = Configuration::getInstance('my.module')->get('parameters') ?? []; $this->services = Configuration::getInstance('my.module')->get('services') ?? [];
Совместимость с новым механизмом битриксовых роутов
С версии 21.400.0
(от 16.07.2021) главного модуля в Битриксе появился сносный роутер.
Чтобы использовать в этом контексте контейнер нужно:
- В файле описания маршрутов (например,
/local/routes/web.php
) в самом верху подключить ядро.
Это важно, т.к. без этого сервис-провайдер завалится на стадии подключения файла с роутами; они подключаются раньше инициализации ядра.
И, если эту проблему еще можно решить, отключив проверку классов сервисов на существование, то запускающиеся автоматом сервисы по тэгу
service.bootstrap
обломятся стопроцентно.
use Local\ExampleBitrixActionController; use Prokl\ServiceProvider\ServiceProvider; use Bitrix\Main\Routing\Controllers\PublicPageController; use Bitrix\Main\Routing\RoutingConfigurator; require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php"); $container = ServiceProvider::instance(); return function (RoutingConfigurator $routes) use ($container) { $routes->get('/countries3/{country}/', [$container->get(ExampleBitrixActionController::class), 'cacheAction']) ->default('country', 'Russia') ->name('first_bitrix_route') ; $routes->get('/', new PublicPageController('/index.php')); // Старый роут на статике. };
Класс битриксового контроллера (ExampleBitrixActionController
) с заточкой под DI:
namespace Local; use Bitrix\Main\Engine\Contract\RoutableAction; use Bitrix\Main\Engine\Controller; use Symfony\Component\HttpKernel\KernelInterface; class ExampleBitrixActionController extends Controller implements RoutableAction { /** * @var KernelInterface $kernel */ private $kernel; public function __construct(KernelInterface $kernel) { $this->kernel = $kernel; parent::__construct(); } /** * @return string|Controller */ public static function getControllerClass() { return ExampleBitrixActionController::class; } /** * @return string */ public static function getDefaultName() { return 'testingAction'; } public function cacheAction(string $country) { return ['cacheDir' => $this->kernel->getCacheDir(), 'country' => $country]; } public function configureActions() { return [ 'cache' => [ 'prefilters' => [], 'postfilters' => [], ], ]; } }
Описывается сервисом так:
Local\ExampleBitrixActionController: arguments: ['@kernel']
Ничего революционного, но так можно получить нормально-сконфигурированный класс контроллера, со всякими зависимостями и т.п.