feat: Implement SMS sending functionality with KavehNegar and Rangineh providers
- Add SendSmsMessage class for encapsulating SMS message data. - Create KavehNegarProvider and RanginehProvider classes implementing SmsProviderInterface for sending SMS. - Implement SmsLogRepository and SmsTemplateRepository for managing SMS logs and templates. - Develop SendSmsHandler for handling SMS sending messages. - Create SmsService to manage SMS dispatching and logging. - Add UserProfileController for managing user profiles with CRUD operations. - Implement UserProfile entity and repository for user profile data management. - Update symfony.lock and bootstrap.php for project dependencies and environment setup.
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
# نکات پیادهسازی — تسک ۰۴: ماژول بلاگ
|
||||
|
||||
## نگاشت فیلدهای Request → Response (مهم!)
|
||||
|
||||
در Drupal نام فیلدهای **ارسالی** با نام فیلدهای **دریافتی** متفاوت است:
|
||||
|
||||
| فیلد در Request | فیلد در Response | توضیح |
|
||||
|----------------|-----------------|-------|
|
||||
| `label` | `title` | عنوان مقاله |
|
||||
| `description` (string) | `body: {value, format}` | متن مقاله — در response به object تبدیل میشود |
|
||||
| `field_image: [{target_id}]` | `images: [{url, fid, filename, filemime, filesize}]` | تصاویر — ID ارسال، object دریافت |
|
||||
| — | `author` | نام نویسنده (computed از realname کاربر) |
|
||||
| — | `uuid` | شناسه یکتا |
|
||||
| — | `status` | وضعیت انتشار (string: "1") |
|
||||
| — | `created` / `changed` | Unix timestamp به صورت string |
|
||||
|
||||
## فرمت واقعی Response بلاگ (از سرور Drupal — endpoint 93)
|
||||
```json
|
||||
{
|
||||
"uuid": "95f6acb0-3331-4141-801e-004e8460edac",
|
||||
"title": "روش های خانگی محافظت از پوست در تابستان",
|
||||
"status": "1",
|
||||
"body": {
|
||||
"value": "متن کامل مقاله...",
|
||||
"format": "full_html"
|
||||
},
|
||||
"created": "1763536163",
|
||||
"changed": "1763537699",
|
||||
"author": "single doctor",
|
||||
"images": [
|
||||
{
|
||||
"url": "https://domain.com/sites/default/files/blog/image.png",
|
||||
"fid": "97",
|
||||
"filename": "image.png",
|
||||
"filemime": "image/png",
|
||||
"filesize": 320787
|
||||
}
|
||||
],
|
||||
"tag": [
|
||||
{
|
||||
"uuid": "24926497-fc2d-47d7-82ae-26cbbc4d6468",
|
||||
"id": "2501",
|
||||
"name": "مجله"
|
||||
},
|
||||
{
|
||||
"uuid": "6c6a488b-1051-43a2-887b-0ec7a05e52d5",
|
||||
"id": "2500",
|
||||
"name": "سلامتی"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
> **نکات مهم response:**
|
||||
> - `body` یک **object** است با کلیدهای `value` و `format` — نه string ساده!
|
||||
> - `format` معمولاً `"full_html"` یا `"basic_html"` است
|
||||
> - `author` از `realname` کاربر نویسنده computed میشود
|
||||
> - `created` و `changed` به صورت **string** برگردانده میشوند (نه integer)
|
||||
> - `status` به صورت string `"1"` برگردانده میشود (نه boolean)
|
||||
> - `images` و `tag` ممکن است آرایه خالی `[]` باشند
|
||||
> - response دارای `id` نیست — فقط `uuid`
|
||||
|
||||
## فرمت Request ایجاد/ویرایش بلاگ
|
||||
|
||||
### POST /api/v1/blog/
|
||||
```json
|
||||
{
|
||||
"label": "عنوان مقاله",
|
||||
"description": "متن کامل مقاله...",
|
||||
"field_image": [
|
||||
{ "target_id": 97 },
|
||||
{ "target_id": 98 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### PATCH /api/v1/blog/{uuid}
|
||||
```json
|
||||
{
|
||||
"label": "عنوان ویرایششده",
|
||||
"description": "متن ویرایششده"
|
||||
}
|
||||
```
|
||||
|
||||
## آپلود تصویر بلاگ (endpoint 99)
|
||||
قبل از ایجاد بلاگ، تصویر باید آپلود شود و `fid` آن در `field_image` استفاده شود:
|
||||
|
||||
```
|
||||
POST /file/upload/blog/blog/field_image
|
||||
Headers:
|
||||
Content-Type: application/octet-stream
|
||||
Content-Disposition: file; filename="image.png"
|
||||
X-CSRF-Token: {token}
|
||||
Authorization: Bearer {token}
|
||||
Response → fid که در field_image استفاده میشود
|
||||
```
|
||||
|
||||
## تولید Slug
|
||||
- از عنوان فارسی slug تولید کن
|
||||
- پکیج `cocur/slugify` را نصب کن:
|
||||
```bash
|
||||
ddev composer require cocur/slugify
|
||||
```
|
||||
- اگر slug تکراری بود، عدد به انتهای آن اضافه کن: `rahnamai-diabet-2`
|
||||
|
||||
## بلاگهای برتر (Top Blogs)
|
||||
- endpoint: `GET /api/v1/blogs/top` (نیاز به auth دارد)
|
||||
- پاسخ: آرایه مستقیم (نه object با pagination) از بلاگهایی که `is_top = 1` هستند
|
||||
- فرمت هر آیتم دقیقاً مشابه response معمولی بلاگ است
|
||||
|
||||
## لیست بلاگها با فیلتر
|
||||
```
|
||||
GET /api/v1/blogs?page=1&limit=10&title=نشانه&tag=3637
|
||||
```
|
||||
- `title`: جستجو در عنوان
|
||||
- `tag`: فیلتر بر اساس ID تگ
|
||||
|
||||
## Pagination
|
||||
```php
|
||||
$offset = ($page - 1) * $limit;
|
||||
// در Repository با limit/offset
|
||||
```
|
||||
|
||||
## مجوزها
|
||||
```
|
||||
POST → احراز هویت الزامی (ROLE_DOCTOR یا ROLE_ADMIN)
|
||||
PATCH → احراز هویت الزامی (owner یا ROLE_ADMIN)
|
||||
DELETE → احراز هویت الزامی (owner یا ROLE_ADMIN)
|
||||
GET → عمومی (بدون auth)
|
||||
GET /api/v1/blogs/top → احراز هویت الزامی
|
||||
```
|
||||
|
||||
## بهینهسازی
|
||||
- view_count با یک query atomic آپدیت کن تا race condition نباشد:
|
||||
```php
|
||||
$this->em->createQuery('UPDATE Blog b SET b.viewCount = b.viewCount + 1 WHERE b.id = :id')
|
||||
->setParameter('id', $blog->getId())
|
||||
->execute();
|
||||
```
|
||||
Reference in New Issue
Block a user