feat: add export functionality for JSON data in CategoriesPage and update TabActions component
This commit is contained in:
@@ -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 تغییر کرده).
|
||||
Reference in New Issue
Block a user