# نکات پیاده‌سازی — تسک ۱۲: ماژول امتیاز و نظرات ## ⚠ تناقض نام فیلدها: API vs DB (بسیار مهم!) فیلدهایی که **کلاینت ارسال می‌کند** با نام فیلدهای **پایگاه داده** متفاوت هستند: | نام در Request (API) | نام در DB (Drupal field) | توضیح | |---------------------|------------------------|-------| | `correct_diagnosis` | `accuracy_of_diagnosis` | دقت تشخیص | | `doctor_skill` | `doctor_expertise` | مهارت پزشک | | `behavior_doctor` | `doctor_behavior` | برخورد پزشک | | `office_cleaning` | `clinic_cleanliness` | نظافت مطب | | `time_in_office` | `waiting_time_at_clinic` | زمان انتظار | | `doctor` | `doctor_id` | شناسه دکتر (integer) | | `rate` | `starts` | امتیاز ستاره‌ای (DECIMAL 10,2) | **در Symfony باید:** - ورودی را با نام‌های API دریافت کن (`correct_diagnosis`, ...) - در Entity و DB با نام‌های Drupal ذخیره کن (`accuracy_of_diagnosis`, ...) ## نمونه واقعی Request — POST /api/v1/clinicpro/rate ```json { "correct_diagnosis": 100, "doctor_skill": 100, "behavior_doctor": 100, "office_cleaning": 100, "time_in_office": 100, "doctor": 1, "rate": 2 } ``` ## نمونه واقعی Request — PATCH /api/v1/clinicpro/rate/{uuid} ```json { "correct_diagnosis": 50, "doctor_skill": 60, "behavior_doctor": 70, "office_cleaning": 80, "time_in_office": 90, "doctor": 1, "rate": 2 } ``` --- ## سیستم امتیازدهی وزنی Rating در Drupal **5 معیار جداگانه** دارد که هر کدام مقدار 0-100 می‌گیرند و با وزن‌های متفاوت محاسبه می‌شوند: ```php $weights = [ "doctor_behavior" => 1.5, // behavior_doctor در API "accuracy_of_diagnosis" => 3.0, // correct_diagnosis در API "waiting_time_at_clinic" => 1.0, // time_in_office در API "doctor_expertise" => 2.0, // doctor_skill در API "clinic_cleanliness" => 1.0, // office_cleaning در API ]; // فرمول محاسبه: $weightedAverage = SUM(value * weight) / SUM(weights); // از 100 $stars = ($weightedAverage / 100) * 5; // از 5 ``` ### پیاده‌سازی calculateDoctorRating در Symfony ```php public function calculateRating(array $apiScores): array { // نگاشت نام‌های API به نام‌های DB $mapped = [ 'accuracy_of_diagnosis' => $apiScores['correct_diagnosis'] ?? 0, 'doctor_expertise' => $apiScores['doctor_skill'] ?? 0, 'doctor_behavior' => $apiScores['behavior_doctor'] ?? 0, 'clinic_cleanliness' => $apiScores['office_cleaning'] ?? 0, 'waiting_time_at_clinic' => $apiScores['time_in_office'] ?? 0, ]; $weights = [ 'doctor_behavior' => 1.5, 'accuracy_of_diagnosis' => 3.0, 'waiting_time_at_clinic' => 1.0, 'doctor_expertise' => 2.0, 'clinic_cleanliness' => 1.0, ]; $totalScore = 0.0; $totalWeight = 0.0; foreach ($weights as $key => $weight) { $totalScore += $mapped[$key] * $weight; $totalWeight += $weight; } $weightedAverage = $totalWeight > 0 ? $totalScore / $totalWeight : 0; $stars = ($weightedAverage / 100) * 5; return [ 'percent' => round($weightedAverage, 1), 'starts' => round(min(5.0, max(0.0, $stars)), 2), // ⚠️ نام فیلد DB: "starts" است نه "stars"! ]; } ``` --- ## آمار دکتر — GET /api/v1/clinicpro-comment/doctor-rate/{doctorUuid} ``` URL: /api/v1/clinicpro-comment/doctor-rate/{uuid_دکتر} Auth: عمومی (بدون احراز هویت) ``` ```json { "average_stars": 4.3, "total_rates": 87, "averages": { "average_doctor_behavior": 82.1, "average_accuracy_of_diagnosis": 88.5, "average_waiting_time_at_clinic": 65.3, "average_doctor_expertise": 90.2, "average_clinic_cleanliness": 78.4 } } ``` --- ## تأیید نظرات نظرات با `approved=0` ذخیره می‌شوند. ادمین آن‌ها را از `GET /api/v1/clinicpro/unverified-comments/{doctorId}` می‌بیند. سپس با `PATCH /api/v1/clinicpro/unverified-comments/{commentId}` تأیید می‌کند. --- ## اعتبارسنجی مقادیر Rating هر معیار باید بین 0 تا 100 باشد: ```php #[Assert\Range(min: 0, max: 100)] ``` --- ## مجوزها ``` POST /api/v1/clinicpro/rate → احراز هویت‌شده PATCH /api/v1/clinicpro/rate/{uuid} → owner (هر کاربر فقط یک امتیاز برای هر دکتر) DELETE /api/v1/rate/doctor/{uuid} → ROLE_ADMIN GET /api/v1/clinicpro/rate/{uuid} → owner (امتیاز کاربر برای دکتر مشخص) GET /api/v1/clinicpro-comment/doctor-rate/{uuid} → عمومی (آمار کلی دکتر) POST /api/v1/clinicpro/comment → احراز هویت‌شده PATCH /api/v1/clinicpro/comment/{uuid} → owner یا ROLE_ADMIN DELETE /api/v1/clinicpro/comment/{uuid} → owner یا ROLE_ADMIN GET /api/v1/clinicpro/comment/{uuid} → احراز هویت‌شده GET /api/v1/clinicpro/comments/{doctorId} → احراز هویت‌شده (فقط approved) GET /api/v1/clinicpro/unverified-comments/{doctorId} → ROLE_ADMIN PATCH /api/v1/clinicpro/unverified-comments/{id} → ROLE_ADMIN (تأیید/رد نظر) POST /api/v1/clinicpro/like → احراز هویت‌شده PATCH /api/v1/clinicpro/like/{uuid} → owner ```