proklung/bitrix-core-symfony

Bitrix 的 Core Symfony 功能

1.6.3 2023-05-10 07:03 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 的别名,但优先级更高(如果同时存在 DEBUGAPP_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(); // Обработка переменных

配置

  1. 在包含的配置中的 compile.container 选项 - 是否将容器编译到文件。如果没有设置,则“否,不编译”。对于非 dev 环境,这是一个有意义的选项。即选项控制容器在 prod 上的导出。

容器导出的存储位置:<容器变量值 kernel.cache_dir>/<SITE_ID>/containers

缓存和日志的路径

AppKernel 类定义。默认情况下

  • 缓存路径(kernel.cache_dir) - /bitrix/cache
  • 日志路径(kernel.logs_dir) - '/../../logs'(在 DOCUMENT_ROOT 上两个级别 - 使用的 Bitrix 集成特点)

要更改这些,需要继承 AppKernel 类并重写几个变量

use Prokl\ServiceProvider\Services\AppKernel;

class MyKernel extends AppKernel
{
   protected $cacheDir = '/bitrix/cache/mycache';
    
   protected $logDir = '/logs-saver';
}

(第二种方法 - 继承 AppKernel 并重写 getCacheDirgetLogDir 方法)。

通过继承核心类进行更改

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 事件

标签: bitrix.events.init

  1. event - 事件的名称。
  2. method - 服务中的处理方法
  3. module - 事件模块
  4. 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(及其别名)- 完整的服务容器
  • app.request - 将全局变量转换为 Request
  • 服务 kernel 的同义词
  • delegated_container_manipulator - 委托容器操作器
  • bitrix.request.instance - Bitrix Request 的实例
  • bitrix.response.instance - Bitrix Response 的实例
  • bitrix.request - 从 Bitrix 获取的 Symfony Request
  • bitrix.request.psr7 - 转换为 PSR-7 的 Bitrix Request
  • bitrix.response - 从 Bitrix 获取的 Symfony Response
  • bitrix.response.psr7 - 转换为 PSR-7 的 Bitrix Response
  • psr17.http_factory - PSR-17 标准的 HttpFactory
  • psr18.http_client - PSR-18 标准的 Http client

助手

  1. container() - 返回容器实例(充当服务定位器)
$kernel = container()->get('kernel');
  1. 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' }

委托容器 - 独立容器,在模块、插件等位置形成

将 Bitrix 服务定位器服务导入容器

自动从 Bitrix 服务定位器导入服务到容器。格式为 此处,从 /bitrix/.settings.php/bitrix/.settings_extra.php 中的 services 部分导入。同时,加载器会遍历已安装的模块并也进行关联。对于继承自 AbstractStandaloneServiceProvider 的单独服务容器,则不执行此加载。

如果不需要此功能,则需要继承自 ServiceProvider 并屏蔽 loadBitrixServiceLocatorConfigs 方法。

BitrixSettingsDiAdapter

class MyServiceProvider extends ServiceProvider
{
    /**
     * {@inheritDoc}
     */
    protected function loadBitrixServiceLocatorConfigs(DelegatingLoader $loader) : void
    {
    }
}

适配器-导入 Bitrix 服务定位器(.settings.php)的设置到 Symphony 容器。

importParameters(ContainerInterface $container, array $settings, ?string $section = null) - 导入参数。如果设置了 section,则参数将放在容器的命名参数部分。

  • importServices(ContainerInterface $container, array $services) - 导入服务。
  • 在 Bitrix 中读取配置的方式如下

与新的 Bitrix 路由机制兼容

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 版本(2021 年 7 月 16 日)开始,Bitrix 主模块出现了 可用的 路由器。

为了在此上下文中使用容器,需要在路由描述文件(例如,/local/routes/web.php)的最顶部连接内核。

这是非常重要的,因为没有这样做,服务提供器会在连接路由文件时失败;它们在初始化内核之前连接。虽然可以通过关闭对服务类存在性的检查来解决此问题,但启动时自动按标签 service.bootstrap 启用的服务将完全失败。

  • 在文件描述的路由(例如,/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')); // Старый роут на статике.

};

针对 DI 优化的 Bitrix 控制器类(ExampleBitrixActionController

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']

没有什么革命性的,但这样可以得到一个正常配置的控制器类,包括依赖关系等。