# نکات پیاده‌سازی — تسک ۰۴: ماژول بلاگ ## نگاشت فیلدهای 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(); ```