feat: add export functionality for JSON data in CategoriesPage and update TabActions component

This commit is contained in:
hamed
2026-06-21 15:37:24 +03:30
parent 1f9b69c121
commit 8b9130011a
4 changed files with 185 additions and 14 deletions
@@ -0,0 +1,129 @@
# فیکس نمایش دکتر در شهر از طریق کلینیک
## پروژه
`clinicpro` (backend)
## زمینه
دکتری که هیچ آدرس و city مستقیمی ندارد اما به یک کلینیک وصل است، در سایت عمومی (`nobat724_front`) در شهر آن کلینیک نمایش داده نمی‌شود. علت: query فیلتر city فقط روی `d.cities` (جدول `doctor_cities`) کار می‌کند و `Clinic.cityId` را نادیده می‌گیرد.
## مشکل
`DoctorRepository::findWithFilters()` فیلتر city:
```php
// clinicpro/src/Doctor/Repository/DoctorRepository.php خط ۵۶-۵۸
if (!empty($filters['city'])) {
$qb->andWhere('ci.id = :city')->setParameter('city', (int) $filters['city']);
}
```
`ci` از `leftJoin('d.cities', 'ci')` می‌آید — جدول `doctor_cities`. اگر دکتر در این جدول ردیفی نداشته باشد (یعنی هیچ city مستقیم ندارد)، حتی اگر عضو کلینیکی با همان city باشد، از نتایج حذف می‌شود.
## ساختار مرتبط
```php
// Doctor Entity
#[ORM\ManyToMany(targetEntity: City::class)]
#[ORM\JoinTable(name: 'doctor_cities')]
private Collection $cities; // جدول doctor_cities
// Clinic Entity
#[ORM\Column(name: 'city_id', type: 'integer', nullable: true)]
private ?int $cityId = null; // FK به categories.id
#[ORM\ManyToMany(targetEntity: Doctor::class)]
#[ORM\JoinTable(name: 'clinic_doctors')]
private Collection $doctors; // جدول clinic_doctors
```
## فایل‌های مرتبط
| فایل | نقش |
|------|-----|
| `clinicpro/src/Doctor/Repository/DoctorRepository.php` | `findWithFilters()` — باید تغییر کند |
| `clinicpro/src/Doctor/Controller/DoctorController.php` | صدا زننده `findWithFilters` |
| `clinicpro/src/Clinic/Entity/Clinic.php` | `cityId` و `doctors` collection |
| `clinicpro/src/Doctor/Entity/Doctor.php` | `cities` collection |
## وضعیت فعلی
```php
// DoctorRepository.php — findWithFilters()
$qb = $this->createQueryBuilder('d')
->leftJoin('d.specialties', 's')
->leftJoin('d.provinces', 'pr')
->leftJoin('d.cities', 'ci')
->distinct();
// ...
if (!empty($filters['city'])) {
$qb->andWhere('ci.id = :city')->setParameter('city', (int) $filters['city']);
}
```
## وظایف
### ۱. گسترش فیلتر city به clinic city
در `findWithFilters()` join کلینیک را اضافه کن و شرط city را تغییر بده تا هم `doctor_cities` هم `clinic.city_id` را پوشش دهد:
```php
$qb = $this->createQueryBuilder('d')
->leftJoin('d.specialties', 's')
->leftJoin('d.provinces', 'pr')
->leftJoin('d.cities', 'ci')
->leftJoin(Clinic::class, 'cl', Join::WITH, 'd MEMBER OF cl.doctors') // ← اضافه
->distinct();
// ...
if (!empty($filters['city'])) {
$qb->andWhere('ci.id = :city OR cl.cityId = :city')
->setParameter('city', (int) $filters['city']);
}
```
همچنین فیلتر `state` را هم بررسی کن — اگر `d.provinces` هم خالی باشد، باید از استان کلینیک گرفته شود. اما برای این باگ، city اولویت دارد.
### ۲. بررسی فیلتر state مشابه
```php
// فعلی:
if (!empty($filters['state'])) {
$qb->andWhere('pr.id = :state')->setParameter('state', (int) $filters['state']);
}
// باید:
// اگر کلینیک دارد، province آن کلینیک را هم در نظر بگیر
// اما Clinic فقط cityId دارد، نه provinceId مستقیم
// → از category join برای گرفتن province شهر کلینیک استفاده کن یا فعلاً فقط city را فیکس کن
```
### ۳. import لازم
در بالای `DoctorRepository.php` اضافه کن:
```php
use App\Clinic\Entity\Clinic;
use Doctrine\ORM\Query\Expr\Join;
```
(اگر `Join` از قبل import نشده)
### ۴. تست
```bash
ddev exec php bin/console debug:router | grep "api/v1/doctors"
# endpoint: GET /api/v1/doctors?city=<city_id>
# تست: یک دکتر که فقط از طریق کلینیک در شهر X است را با ?city=X جستجو کن
# باید در نتایج ظاهر شود
```
## نکات مهم
- `Clinic.cityId` یک integer FK است به `categories.id` (جدول categories با bundle='city') — نه یک relation object. پس `cl.cityId = :city` درست است (نه `cl.city.id`).
- `leftJoin` برای کلینیک لازم است نه `innerJoin` — دکتری که اصلاً عضو هیچ کلینیکی نیست هم باید در نتایج بماند (اگر city مستقیم دارد).
- `OR cl.cityId = :city` ممکن است با `DISTINCT` مشکل ایجاد کند — اگر دکتر هم city مستقیم دارد هم عضو کلینیک در همان city است، `DISTINCT` آن را یک‌بار نمایش می‌دهد.
- migration لازم نیست — فقط query تغییر می‌کند.
- بعد از تغییر، `docs/api/doctor.md` را update کن (رفتار فیلتر city تغییر کرده).