- Created new AST JSON file for the doctor service API documentation, detailing endpoints, parameters, and responses. - Added AST JSON file for the TagController, including methods and their relationships with imported classes. - Introduced AST JSON file for the SmsLog entity, outlining its methods and dependencies.
8.7 KiB
ارسال پیامک خوشآمد هنگام تعریف منشی جدید
پروژه
clinicpro (backend — Symfony)
زمینه
هنگام تعریف منشی جدید از طریق POST /api/v1/secretary، یک User با نقش ROLE_SECRETARY ساخته (یا کاربر موجود بازاستفاده) میشود، اما هیچ پیامکی به منشی ارسال نمیشود. منشی هیچ اطلاعی از شمارهکاربری، رمز و لینک ورود ندارد.
الگوی مشابه در پروژه از قبل وجود دارد: هنگام تأیید پیشثبتنام (PreRegistrationController با تگ TAG_PRE_REGISTRATION) و دعوت پزشک به کلینیک (ClinicInvitationService::sendSms با تگ TAG_CLINIC_INVITATION). این تسک همان الگو را برای منشی پیاده میکند.
هدف
بعد از ساخت موفق منشی جدید، یک پیامک خوشآمد به شماره منشی ارسال شود. متن پیامک باید از سیستم template پیامک بیاید (تگ اختصاصی + SmsMessageTemplate::DEFAULTS بهعنوان fallback، قابل ویرایش از DB)، نه hard-code داخل کنترلر.
فایلهای مرتبط
| فایل | نقش |
|---|---|
src/Secretary/Controller/SecretaryController.php |
endpoint ساخت منشی — محل تزریق ارسال پیامک |
src/Sms/Entity/SmsLog.php |
ثابتهای تگ (TAG_*) — افزودن تگ جدید |
src/Sms/Entity/SmsMessageTemplate.php |
آرایه DEFAULTS — افزودن متن پیشفرض template |
src/Sms/Service/SmsService.php |
dispatchAsync(...) — ارسال async پیامک |
src/Sms/Service/SmsTextResolver.php |
resolve(tag, vars) — resolve متن template و جایگزینی {key} |
src/ClinicInvitation/Service/ClinicInvitationService.php |
الگوی مرجع ارسال پیامک با template |
docs/api/secretary.md + docs/api/sms.md |
مستندات — باید بهروز شوند |
وضعیت فعلی
در SecretaryController::create() بعد از ساخت user، فقط ذخیره میشود و هیچ پیامکی نمیرود:
// Assign ROLE_SECRETARY
$roles = $secretaryUser->getRoles();
if (!in_array('ROLE_SECRETARY', $roles, true)) {
$roles[] = 'ROLE_SECRETARY';
$secretaryUser->setRoles(array_values(array_unique($roles)));
}
$this->userRepo->save($secretaryUser);
// ... check duplicate ...
$secretary = new DoctorSecretary($doctor, $secretaryUser, $ownerType, $ownerClinic);
// ...
$this->secretaryRepo->save($secretary);
return $this->success(['data' => $secretary->toArray()], 201);
الگوی مرجع ارسال پیامک با template (از ClinicInvitationService):
$message = $this->smsText->resolve(\App\Sms\Entity\SmsLog::TAG_CLINIC_INVITATION, [
'clinic' => $clinicName,
'link' => $link,
]);
$this->smsService->dispatchAsync($inv->getMobile(), $message, tag: \App\Sms\Entity\SmsLog::TAG_CLINIC_INVITATION);
ساختار DEFAULTS در SmsMessageTemplate (هر تگ: title, body با placeholderهای {key}, variables[]):
SmsLog::TAG_PRE_REGISTRATION => [
'title' => 'پیشثبتنام',
'body' => 'به کلینیک پرو خوش آمدید! شمارهکاربری: {username} | رمز عبور: {password} | لینک ورود: {link}',
'variables' => ['username', 'password', 'link'],
],
وظایف
۱. افزودن تگ جدید در SmsLog
در src/Sms/Entity/SmsLog.php یک ثابت تگ جدید اضافه کن (همسبک بقیه تگها):
public const TAG_SECRETARY = 'secretary';
نکته: investigator گزارش داد تگی به نام
TAG_WELCOMEهم موجود است — قبل از افزودن، فایل را بخوان؛ اگر تگ عمومی خوشآمد مناسب بود از همان استفاده کن، در غیر این صورتTAG_SECRETARYرا اضافه کن. یک تگ اختصاصی «منشی» بهتر است چون متن template مستقل و قابل ویرایش میشود.
۲. افزودن template پیشفرض در SmsMessageTemplate::DEFAULTS
یک entry جدید برای تگ منشی اضافه کن. متن باید شامل نام کلینیک/دکتر و اطلاعات ورود باشد:
SmsLog::TAG_SECRETARY => [
'title' => 'دعوت بهعنوان منشی',
'body' => "شما بهعنوان منشی {owner} در کلینیکپرو تعریف شدید.\nشمارهکاربری: {username}\nلینک ورود: {link}",
'variables' => ['owner', 'username', 'link'],
],
{owner}= نام دکتر یا نام کلینیک (بسته به$ownerType).{username}= شماره موبایل منشی ($mobile).{link}= لینک ورود پنل (از سرویس$appUrlمثل بقیه، rtrim + مسیر ورود).- اگر رمز عبور در body لازم شد، فقط زمانی که کاربر جدید ساخته شده و
passwordدر ورودی آمده — رمز خام را نگهدار و در vars بگذار (متغیر محلی، نه از دیتابیس؛ hash قابل بازگشت نیست).
۳. تزریق سرویسهای SMS در کنترلر
در constructor SecretaryController اینها را اضافه کن (همسبک ClinicInvitationService):
private readonly \App\Sms\Service\SmsService $smsService,
private readonly \App\Sms\Service\SmsTextResolver $smsText,
private readonly string $appUrl, // همان param که ClinicInvitationService میگیرد
$appUrlرا از همان جایی bind کن کهClinicInvitationServiceمیگیرد —config/services.yamlرا بررسی کن و همان$appUrlرا برایSecretaryControllerهم bind کن (یا اگر global bind است، خودکار تزریق میشود).
۴. ارسال پیامک بعد از ساخت موفق منشی
در create()، بعد از $this->secretaryRepo->save($secretary); و قبل از return، پیامک را resolve و dispatch کن:
$ownerName = $ownerClinic !== null
? ($ownerClinic->getName() ?? 'کلینیک')
: ($doctor->getUser()->getRealName() ?? 'پزشک');
$link = rtrim($this->appUrl, '/') . '/login';
$message = $this->smsText->resolve(\App\Sms\Entity\SmsLog::TAG_SECRETARY, [
'owner' => $ownerName,
'username' => $mobile,
'link' => $link,
]);
$this->smsService->dispatchAsync($mobile, $message, tag: \App\Sms\Entity\SmsLog::TAG_SECRETARY);
نکات مهم
- ارسال async است —
dispatchAsyncفقط در صف Messenger میگذارد؛ ارسال واقعی توسط worker (messenger:consume async) انجام میشود. برای تست local باید worker در حال اجرا باشد. - متن hard-code نکن — همیشه از
SmsTextResolver::resolve(tag, vars)استفاده کن تا ادمین بتواند از DB متن را ویرایش کند.DEFAULTSفقط fallback است. - placeholderها دقیقاً
{key}باشند و کلیدهایvariables[]با کلیدهای آرایهvarsکه بهresolveمیدهی یکی باشند. - duplicate/خطا — اگر منشی تکراری بود (خط ۱۰۱–۱۰۳) یا هر خطای زودهنگام،
returnقبل از رسیدن به کد ارسال رخ میدهد؛ پس پیامک فقط روی مسیر موفق ساخت میرود. درست است — همین رفتار مطلوب است. - کاربر موجود بازاستفادهشده: تصمیم بگیر آیا برای کاربری که از قبل وجود داشت (
findByMobileغیر null) هم پیامک برود یا فقط برای کاربر تازهساخته. پیشنهاد: چون این یک «دعوت به نقش منشی» است، برای هر دو حالت (چون رابطه منشی جدید ساخته میشود) پیامک منطقی است؛ ولی اگر رمز در body هست، رمز را فقط برای کاربر جدید بگذار. - مستندات (Standing Rule): چون
src/Secretary/*وsrc/Sms/*تغییر میکنند، در همین session همdocs/api/secretary.md(ذکر ارسال پیامک هنگام create) و همdocs/api/sms.md(تگ جدید + template پیشفرض) را بهروز کن. - بعد از تغییر کد:
ddev exec php bin/console cache:clear. اگر Entity تغییری در schema نداشت (فقط ثابت/آرایهDEFAULTS)، migration لازم نیست — ولی اگر template را seed میکنی، از همان مسیر seed موجود پروژه استفاده کن.