providers = [ 'kavenegar' => $kavenegar, 'rangineh' => $rangineh, ]; } /** * ارسال یک پیامک سیستمی از طریق تمپلت VerifyLookup کاوه‌نگار. * فقط تگ + متغیرهای منطقی می‌گیرد؛ نام تمپلت و نگاشت token از SmsMessageTemplate (یا DEFAULTS) خوانده می‌شود. * * @param array $vars متغیرهای منطقی (کلیدهای {...} بدنه) */ public function dispatchTemplate(string $tag, string $mobile, array $vars = [], string $provider = 'kavenegar'): void { $tpl = $this->messageTemplateRepo->findByTag($tag); $kaveTemplate = $tpl?->getKavenegarTemplate() ?? (SmsMessageTemplate::DEFAULTS[$tag]['kavenegar_template'] ?? null); $tokenMap = $tpl?->getTokenMap() ?: (SmsMessageTemplate::DEFAULTS[$tag]['token_map'] ?? []); $message = $this->textResolver->resolve($tag, $vars); // سیاست lookup-only: بدون الگوی کاوه‌نگار نباید با sms/send.json خام ارسال شود. if ($kaveTemplate === null || $tokenMap === []) { $this->logger->error(sprintf('SMS tag "%s" has no Kavenegar template/token_map; refusing raw send', $tag), [ 'tag' => $tag, 'mobile' => $mobile, ]); $this->logRepo->save(new SmsLog($mobile, $message, $provider, false, $tag)); return; } $slotVars = []; foreach ($tokenMap as $logicalKey => $slot) { if (array_key_exists($logicalKey, $vars)) { $slotVars[$slot] = (string) $vars[$logicalKey]; } } $this->dispatchAsync($mobile, $message, $provider, templateVars: $slotVars, templateCode: $kaveTemplate, tag: $tag); } public function dispatchAsync( string $mobile, string $message, string $provider = 'kavenegar', ?string $templateUuid = null, array $templateVars = [], ?string $templateCode = null, string $tag = SmsLog::TAG_GLOBAL, ): void { $this->bus->dispatch(new SendSmsMessage( $mobile, $message, $provider, $templateUuid, $templateVars, $templateCode, $tag )); } public function sendNow(SendSmsMessage $msg): bool { $provider = $this->resolveProvider($msg->provider); // سیاست lookup-only: پیام بدون templateCode نباید با sms/send.json خام برود. if ($msg->templateCode === null) { $this->logger->error('SMS refused: no templateCode (lookup-only policy)', [ 'mobile' => $msg->mobile, 'tag' => $msg->tag, ]); $success = false; } else { $success = $provider->sendTemplate($msg->mobile, $msg->templateCode, $msg->templateVars); } $log = new SmsLog($msg->mobile, $msg->message, $provider->getName(), $success, $msg->tag); if ($msg->templateUuid) $log->setTemplateUuid($msg->templateUuid); if ($msg->templateCode) $log->setTemplateCode($msg->templateCode); $this->logRepo->save($log); return $success; } private function resolveProvider(string $name): SmsProviderInterface { return $this->providers[$name] ?? $this->kavenegar; } }