242 lines
7.6 KiB
PHP
242 lines
7.6 KiB
PHP
<?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;
|
||
}
|
||
}
|