Birthday was never saved (hydrate forced null) and not returned in a form the clients use. Now: - hydrate stores the incoming `birthday` (Unix) into date_of_birth; `birthday` takes priority over a stray `date_of_birth: null` in the same payload so it can't be wiped. - toArray exposes a single `birthday` (Unix) key — drop the duplicate `date_of_birth` output to avoid overlap. - admin UserDetailPage reads profile.birthday (formatDate renders Jalali). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
79 lines
4.7 KiB
Markdown
79 lines
4.7 KiB
Markdown
# ذخیره و نمایش صحیح تاریخ تولد در پروفایل (Unix)
|
||
|
||
## پروژه
|
||
|
||
`clinicpro` (Backend — منبع حقیقت).
|
||
|
||
> **Cross-repo:** سایت عمومی `nobat724_front` تاریخ تولد را بهصورت **Unix timestamp** با کلید `birthday` میفرستد (تبدیل جلالی↔Unix کاملاً سمت فرانت با `changeDateType` انجام میشود) و انتظار دارد همان Unix را برای نمایش بگیرد. پرامپت همتای فرانت: `nobat724_front/.claude/prompt/profile-birthday-send-direction-fix.md`. این پرامپت **اول** اجرا شود.
|
||
|
||
## زمینه
|
||
|
||
در فرم اطلاعات کاربری (`/dashboard`)، فیلد «تاریخ تولد» مقدارش با کلید `birthday` بهصورت **Unix timestamp** ارسال میشود (فرانت با `moment(jalali,"jYYYY/jMM/jDD").unix()` تبدیل میکند). اما در `UserProfileController::hydrate` این مقدار **عمداً نادیده گرفته و `null` ذخیره میشود** (یک TODO نیمهکاره). در نتیجه تاریخ تولد هرگز ذخیره نمیشود؛ و `toArray` کلید `birthday` را اصلاً برنمیگرداند (فقط `date_of_birth`)، پس فرانت چیزی برای نمایش ندارد.
|
||
|
||
## مشکل / هدف
|
||
|
||
۱. ورودی: `birthday` (Unix integer) را در ستون `date_of_birth` ذخیره کن (بهجای `null`).
|
||
۲. خروجی: `toArray` کلید `birthday` = همان Unix (`date_of_birth`) را برگرداند تا فرانت با `changeDateType` به جلالی نمایش دهد.
|
||
|
||
## فایلهای مرتبط
|
||
|
||
| فایل | نقش |
|
||
|------|-----|
|
||
| `src/UserProfile/Controller/UserProfileController.php` | `hydrate` — ذخیره `birthday`(Unix) در `date_of_birth` |
|
||
| `src/UserProfile/Entity/UserProfile.php` | `toArray` — افزودن کلید `birthday` (= Unix `date_of_birth`) |
|
||
|
||
## وضعیت فعلی (کد واقعی)
|
||
|
||
`hydrate` — مقدار دور ریخته میشود:
|
||
```php
|
||
// birthday: accept Jalali string "1370-05-15" stored as-is converted to Unix
|
||
if (array_key_exists('birthday', $data) && $data['birthday'] !== null) {
|
||
// Will be replaced with JalaliDateService in Task 16
|
||
$profile->setDateOfBirth(null); // ❌ هرگز ذخیره نمیشود
|
||
}
|
||
if (array_key_exists('date_of_birth', $data)) $profile->setDateOfBirth($data['date_of_birth']);
|
||
```
|
||
|
||
`UserProfile`:
|
||
```php
|
||
#[ORM\Column(name: 'date_of_birth', type: 'integer', nullable: true)]
|
||
private ?int $dateOfBirth = null;
|
||
// toArray():
|
||
'date_of_birth' => $this->dateOfBirth, // کلید birthday وجود ندارد
|
||
```
|
||
|
||
> فرانت `birthday` را Unix میفرستد (مثلاً `-405...` یا یک integer مثبت/منفی برای تاریخهای قبل/بعد ۱۹۷۰). ممکن است بهصورت string-encoded integer هم بیاید؛ با `(int)` ایمن تبدیل کن.
|
||
|
||
## وظایف
|
||
|
||
### ۱. ذخیره `birthday` (Unix) در `hydrate`
|
||
بلوک نیمهکاره را با ذخیرهی واقعی جایگزین کن:
|
||
```php
|
||
if (array_key_exists('birthday', $data)) {
|
||
$b = $data['birthday'];
|
||
$profile->setDateOfBirth(($b === null || $b === '') ? null : (int) $b);
|
||
}
|
||
if (array_key_exists('date_of_birth', $data)) {
|
||
$profile->setDateOfBirth($data['date_of_birth'] === null ? null : (int) $data['date_of_birth']);
|
||
}
|
||
```
|
||
|
||
### ۲. خروجی `birthday` در `toArray`
|
||
در `UserProfile::toArray`، کنار `date_of_birth`، کلید `birthday` را هم برگردان (همان مقدار Unix):
|
||
```php
|
||
'date_of_birth' => $this->dateOfBirth,
|
||
'birthday' => $this->dateOfBirth,
|
||
```
|
||
> هر دو کلید همان Unixاند؛ `birthday` برای مصرف مستقیم فرانت (که `moment.unix(birthday)` میزند) و `date_of_birth` برای سازگاری عقبرو.
|
||
|
||
### ۳. مستندسازی
|
||
اگر سند پروفایلی در `docs/api/` هست، فیلد `birthday` (Unix در ورودی و خروجی) را اضافه کن. اگر نیست، نیازی به ساخت فایل جدید نیست.
|
||
|
||
## نکات مهم
|
||
|
||
- **هیچ تبدیل جلالی در بکاند لازم نیست** — `JalaliDateService` استفاده نمیشود؛ تبدیل کاملاً سمت فرانت است. ساده نگهدار.
|
||
- `birthday` ممکن است integer یا string-encoded-integer باشد → `(int)` ایمن.
|
||
- migration لازم نیست (`date_of_birth` integer از قبل هست).
|
||
- پاسخها از `BaseController`.
|
||
- تست: `PATCH /api/v1/user-profile/{uuid}` با `{"birthday": 12345678}` → در DB `date_of_birth = 12345678`؛ سپس `GET` → هم `birthday` و هم `date_of_birth` برابر `12345678`. round-trip سالم.
|