Files
portal/app/app/Services/Sms/SmsRouter.php
T

69 lines
2.3 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services\Sms;
/**
* Кто повезёт сообщение. Точный оператор выигрывает у универсала, при равных
* условиях выигрывает цена. Так билайновский номер уходит через Билайн за 4,75 ₽,
* а остальные через универсала — без ручного выбора канала начальником.
*/
final class SmsRouter
{
/** @param array<int, SmsProvider> $providers */
public function __construct(private readonly array $providers) {}
public function pick(string $operator): ?SmsProvider
{
$exact = [];
$universal = [];
foreach ($this->providers as $provider) {
$serves = $provider->servesOperators();
if ($operator !== '' && in_array($operator, $serves, true)) {
$exact[] = $provider;
} elseif (in_array('*', $serves, true)) {
$universal[] = $provider;
}
}
$candidates = $exact !== [] ? $exact : $universal;
if ($candidates === []) {
return null;
}
usort(
$candidates,
fn (SmsProvider $a, SmsProvider $b) => $a->priceKopecks($operator) <=> $b->priceKopecks($operator),
);
return $candidates[0];
}
/**
* Запасной канал, если основной отказал. Работает ТОЛЬКО при включённом
* флаге services.sms.failover_to_universal (по умолчанию ВЫКЛ). Возвращает
* универсала, отличного от основного. Точка расширения — сейчас не вызывается
* из джоба (решение владельца 23.07.2026 — без резерва).
*/
public function fallbackFor(string $operator): ?SmsProvider
{
if (! config('services.sms.failover_to_universal')) {
return null;
}
$primary = $this->pick($operator);
foreach ($this->providers as $provider) {
if (in_array('*', $provider->servesOperators(), true) && $provider !== $primary) {
return $provider;
}
}
return null;
}
}