fix: improve doctor search performance by optimizing query filters in findWithFilters method

This commit is contained in:
hamed
2026-06-21 16:41:59 +03:30
parent 8b9130011a
commit 91cfb64217
2 changed files with 217 additions and 6 deletions
+39 -6
View File
@@ -49,17 +49,25 @@ class DoctorRepository extends ServiceEntityRepository
->leftJoin('d.specialties', 's')
->leftJoin('d.provinces', 'pr')
->leftJoin('d.cities', 'ci')
->leftJoin(Clinic::class, 'cl', Join::WITH, 'd MEMBER OF cl.doctors')
->leftJoin(DoctorAddress::class, 'ca', Join::WITH, 'ca.clinicId = cl.id AND ca.doctor IS NULL')
->distinct();
if (!empty($filters['state'])) {
$qb->andWhere('pr.id = :state OR IDENTITY(ca.province) = :state')
->setParameter('state', (int) $filters['state']);
$stateId = (int) $filters['state'];
$clinicIds = $this->doctorIdsViaClinicLocation('province', $stateId);
$qb->andWhere('pr.id = :state' . ($clinicIds ? ' OR d.id IN (:stateClinicDoctorIds)' : ''))
->setParameter('state', $stateId);
if ($clinicIds) {
$qb->setParameter('stateClinicDoctorIds', $clinicIds);
}
}
if (!empty($filters['city'])) {
$qb->andWhere('ci.id = :city OR IDENTITY(ca.city) = :city')
->setParameter('city', (int) $filters['city']);
$cityId = (int) $filters['city'];
$clinicIds = $this->doctorIdsViaClinicLocation('city', $cityId);
$qb->andWhere('ci.id = :city' . ($clinicIds ? ' OR d.id IN (:cityClinicDoctorIds)' : ''))
->setParameter('city', $cityId);
if ($clinicIds) {
$qb->setParameter('cityClinicDoctorIds', $clinicIds);
}
}
if (!empty($filters['specialty'])) {
$qb->andWhere('s.id = :specialty')->setParameter('specialty', (int) $filters['specialty']);
@@ -95,6 +103,31 @@ class DoctorRepository extends ServiceEntityRepository
];
}
/**
* IDs of doctors who belong to a clinic whose own address (DoctorAddress with
* doctor IS NULL) is in the given city/province. Used so doctors without a
* direct address still surface under their clinic's location, without a
* per-row correlated subquery on the main search.
*
* @return int[]
*/
private function doctorIdsViaClinicLocation(string $field, int $locationId): array
{
$column = $field === 'city' ? 'ca.city' : 'ca.province';
$rows = $this->getEntityManager()->createQueryBuilder()
->select('cd.id AS doctorId')
->from(Clinic::class, 'cl')
->join('cl.doctors', 'cd')
->join(DoctorAddress::class, 'ca', Join::WITH, 'ca.clinicId = cl.id AND ca.doctor IS NULL')
->where(sprintf('IDENTITY(%s) = :loc', $column))
->setParameter('loc', $locationId)
->getQuery()
->getScalarResult();
return array_values(array_unique(array_map('intval', array_column($rows, 'doctorId'))));
}
public function findByClinicWithFilters(int $clinicId, array $filters): array
{
$page = max(1, (int) ($filters['page'] ?? 1));