bp/app/Services/EventManager.php

242 lines
7.6 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Services;
use CodeIgniter\Events\Events;
/**
* EventManager - обертка над событиями CodeIgniter 4
*
* Предоставляет два типа подписок на события:
* - moduleOn(): выполняется только если модуль активен и подписка оплачена
* - systemOn(): выполняется всегда, без проверки подписки
*
* Используется для создания интеграций между модулями, которые должны
* работать только при наличии активной подписки на соответствующий модуль.
*/
class EventManager
{
/**
* Сервис подписок на модули
*
* @var ModuleSubscriptionService|null
*/
private ?ModuleSubscriptionService $moduleSubscriptionService = null;
/**
* Конфигурация модулей
*
* @var \Config\BusinessModules|null
*/
private ?\Config\BusinessModules $modulesConfig = null;
/**
* Код модуля, к которому привязаны события
*
* @var string|null
*/
private ?string $moduleCode = null;
/**
* Кэш подписки на модуль
*
* @var bool|null
*/
private ?bool $moduleActive = null;
/**
* Получить экземпляр сервиса подписок
*
* @return ModuleSubscriptionService
*/
private function getModuleSubscriptionService(): ModuleSubscriptionService
{
if ($this->moduleSubscriptionService === null) {
$this->moduleSubscriptionService = service('moduleSubscription');
}
return $this->moduleSubscriptionService;
}
/**
* Получить конфигурацию модулей
*
* @return \Config\BusinessModules
*/
private function getModulesConfig(): \Config\BusinessModules
{
if ($this->modulesConfig === null) {
$this->modulesConfig = config('BusinessModules');
}
return $this->modulesConfig;
}
/**
* Привязать события к конкретному модулю
*
* Все последующие вызовы moduleOn() будут проверять
* подписку на указанный модуль.
*
* @param string $moduleCode Код модуля
* @return $this
*/
public function forModule(string $moduleCode): self
{
$this->moduleCode = $moduleCode;
$this->moduleActive = null;
return $this;
}
/**
* Проверить, активен ли модуль
*
* @return bool
*/
private function isModuleActive(): bool
{
if ($this->moduleCode === null) {
return false;
}
if ($this->moduleActive === null) {
$orgId = session('org_id') ?? null;
$this->moduleActive = $this->getModuleSubscriptionService()
->isModuleActive($this->moduleCode, $orgId);
}
return $this->moduleActive;
}
/**
* Подписаться на событие с проверкой подписки на модуль
*
* Обработчик будет выполнен только если:
* 1. Модуль глобально включен в конфигурации
* 2. У организации есть активная подписка на модуль
*
* @param string $event Имя события
* @param callable $callback Обработчик события
* @param int $priority Приоритет события (по умолчанию 100)
* @return bool True если подписка создана, False если модуль не активен
*/
public function moduleOn(
string $event,
callable $callback,
int $priority = 100
): bool {
if ($this->moduleCode === null) {
throw new \RuntimeException(
'Module code not set. Use forModule() method first.'
);
}
$modulesConfig = $this->getModulesConfig();
// Проверяем, что модуль существует в конфигурации
if (!isset($modulesConfig->modules[$this->moduleCode])) {
log_message(
'error',
"EventManager: Module '{$this->moduleCode}' not found in config"
);
return false;
}
// Если модуль отключен глобально, не подписываемся
// Проверяем наличие поля enabled (опционально)
if (isset($modulesConfig->modules[$this->moduleCode]['enabled']) &&
empty($modulesConfig->modules[$this->moduleCode]['enabled'])) {
log_message(
'info',
"EventManager: Module '{$this->moduleCode}' is disabled globally"
);
return false;
}
// Проверяем подписку организации
if (!$this->isModuleActive()) {
log_message(
'debug',
"EventManager: Organization subscription not active for module '{$this->moduleCode}'"
);
return false;
}
// Подписываемся на событие
Events::on($event, $callback, $priority);
log_message(
'debug',
"EventManager: Subscribed to event '{$event}' for module '{$this->moduleCode}'"
);
return true;
}
/**
* Подписаться на событие без проверки подписки
*
* Обработчик будет выполнен всегда, независимо
* от статуса подписки на модуль.
*
* Используется для системных событий, которые должны
* работать для всех организаций.
*
* @param string $event Имя события
* @param callable $callback Обработчик события
* @param int $priority Приоритет события (по умолчанию 100)
* @return void
*/
public function systemOn(
string $event,
callable $callback,
int $priority = 100
): void {
Events::on($event, $callback, $priority);
log_message(
'debug',
"EventManager: System event subscribed: '{$event}'"
);
}
/**
* Отписаться от события
*
* @param string $event Имя события
* @param callable|null $callback Конкретный обработчик (если null - все обработчики)
* @return void
*/
public function off(string $event, ?callable $callback = null): void
{
if ($callback === null) {
Events::off($event);
} else {
Events::off($event, $callback);
}
}
/**
* Проверить, активен ли текущий модуль
*
* Удобный метод для использования внутри обработчиков событий.
*
* @return bool
*/
public function currentModuleActive(): bool
{
return $this->isModuleActive();
}
/**
* Получить код текущего модуля
*
* @return string|null
*/
public function getCurrentModuleCode(): ?string
{
return $this->moduleCode;
}
}