When a user completes their profile (POST/PATCH /api/v1/user-profile), the name was only stored on the profile (label/family) and User.real_name stayed empty — so users who registered via booking showed with no name in the admin user list. hydrate() now mirrors the profile's full name (label + family) onto the owning User.realName, persisted in the same flush. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6.5 KiB
همگامسازی نام کاربر (User.real_name) هنگام تکمیل پروفایل
پروژه
clinicpro (Backend).
کاملاً backend است. سایت عمومی
nobat724_frontهمانPATCH/POST /api/v1/user-profileرا با فیلدهایname/labelوfamilyصدا میزند؛ قرارداد API تغییر نمیکند، فقط یک side-effect سرور اضافه میشود. نیازی به تغییر frontend نیست.
زمینه
در پنل ادمین، لیست کاربران (/api/v1/admin/users) ستون «نام» را از User.realName (users.real_name) میخواند. اما وقتی کاربری از طریق نوبتدهی ثبتنام و پروفایلش را تکمیل میکند، نام فقط در UserProfile (profiles.label و profiles.family) ذخیره میشود و users.real_name خالی میماند. نتیجه: کاربرانِ ثبتنامشده از مسیر نوبتدهی در لیست ادمین بدون نام نمایش داده میشوند.
مشکل / هدف
هنگام ایجاد/بهروزرسانی پروفایل، اگر name/label یا family تغییر کند، User.realName صاحبِ پروفایل هم با «نام کامل» (ترکیب نام و نام خانوادگی) همگام شود تا در پنل ادمین و هر جای دیگری که real_name را میخواند درست نمایش داده شود.
فایلهای مرتبط
| فایل | نقش |
|---|---|
src/UserProfile/Controller/UserProfileController.php |
hydrate() فقط Profile را پر میکند؛ باید User.realName را هم sync کند |
src/UserProfile/Entity/UserProfile.php |
getUser()، getLabel()، getFamily() (مرجع داده) |
src/Auth/Entity/User.php |
setRealName() (موجود) |
وضعیت فعلی (کد واقعی)
hydrate() فقط روی UserProfile کار میکند — User.realName هرگز ست نمیشود:
private function hydrate(UserProfile $profile, array $data): void
{
if (array_key_exists('name', $data)) $profile->setLabel($data['name']);
if (array_key_exists('label', $data)) $profile->setLabel($data['label']);
if (array_key_exists('family', $data)) $profile->setFamily($data['family']);
// ... بقیه فیلدها
}
و create() / update() بعد از hydrate فقط $this->repository->save($profile) را صدا میزنند.
مرجع: لیست ادمین u.realName as name را برمیگرداند (AdminApiController::users)، پس real_name خالی = نام خالی در پنل.
وظایف
۱. همگامسازی User.realName در hydrate
در انتهای hydrate() (بعد از اعمال همهی فیلدها روی profile)، اگر name/label یا family در ورودی بود، real_name کاربر را از مقدار نهاییِ پروفایل بساز:
private function hydrate(UserProfile $profile, array $data): void
{
// ... ستکردن فیلدهای profile (بدون تغییر) ...
if (array_key_exists('name', $data) || array_key_exists('label', $data) || array_key_exists('family', $data)) {
$fullName = trim(implode(' ', array_filter([$profile->getLabel(), $profile->getFamily()])));
$profile->getUser()->setRealName($fullName !== '' ? $fullName : null);
}
}
- منبع، مقدار نهاییِ خودِ
profileاست (نه آرایهی$dataخام) تا اگر فقط یکی ازname/familyدر PATCH آمده باشد، نام کامل با مقدار موجودِ دیگری بهدرستی ساخته شود. array_filterبخشهای خالی را حذف میکند (مثلاً وقتی فقطnameپر است). اگر نتیجه خالی شد،null(هماهنگ با امضایsetRealName(?string)).
۲. اطمینان از flush شدن تغییر User
create() و update() بعد از hydrate $this->repository->save($profile) را صدا میزنند که flush=true است. چون User و UserProfile در همان Unit of Work مدیریت میشوند، تغییر realName در همان flush ذخیره میشود — نیازی به save جداگانهی User نیست. فقط تأیید کن که UserProfileRepository::save واقعاً flush میکند (میکند) و اگر جایی flush=false پاس داده شده، اصلاح کن.
نکات مهم
- قرارداد API تغییر نمیکند — همان فیلدهای
name/label/familyورودی؛ فقط side-effect رویUser.realName. - این منطق هم در ایجاد (
POST) و هم بهروزرسانی (PATCH) باید اجرا شود — چون هر دو از همانhydrateاستفاده میکنند، یکجا اصلاح کافی است. - نام کامل =
label + ' ' + family؛ اگر محصول ترجیح دیگری دارد (مثلاً فقطlabel)، در پیادهسازی همان را اعمال کن — ولی چون لیست ادمین یک ستون واحد «نام» دارد، نام کامل طبیعیتر است. - این فقط نام را روی صاحبِ پروفایل ست میکند؛ پروفایلِ «شخص دیگر» (که بیمارِ غیرِخود است) از مسیر دیگری (
patient_nameدر نوبت) مدیریت میشود و نبایدreal_nameکاربر لاگین را تغییر دهد —hydrateهمیشه روی پروفایلِ همان کاربر کار میکند، پس مشکلی نیست. - تاریخها/الگوها طبق
BaseController. بعد از تغییر:ddev exec php -lروی کنترلر. migration لازم نیست (فیلدreal_nameاز قبل وجود دارد). - تست رفتاری: یک کاربر بدون
real_nameبساز/پیدا کن →PATCH /api/v1/user-profile/{userUuid}با{name, family}→ تأیید کنusers.real_nameپر شد وGET /api/v1/admin/usersآن را درnameنشان میدهد. همچنین PATCH فقط باfamily→ نام کامل باlabelموجود ساخته شود. - مستندسازی: اگر رفتار قرارداد را تغییر نمیدهد،
docs/api/نیاز به تغییر بزرگ ندارد؛ ولی میتوان در سند پروفایل (اگر وجود دارد) یک جمله دربارهی sync نام افزود.