Files
clinicpro/src/Doctor/Repository/DoctorAddressRepository.php
T
hamed f1258d206d feat(migrations): add clinic_id context to weekly_schedules, date_overrides, and holidays
- Introduced clinic_id to weekly_schedules, date_overrides, and holidays to differentiate between personal and clinic schedules.
- Updated unique constraints and indexes to accommodate the new clinic context.

feat(command): create AssignScheduleClinicCommand to move schedules

- Added a command to move a doctor's personal weekly schedule into a clinic context.
- Implemented checks to ensure sessions align with the target clinic.

feat(context): implement EntityContext and EntityContextResolver

- Created EntityContext to represent the effective working environment of a request (doctor or clinic).
- Developed EntityContextResolver to determine the execution context based on user roles and active contexts.

test: add ServiceModeContextTest for appointment scheduling

- Implemented tests to ensure service booking respects clinic and personal contexts.
- Verified that financial data is omitted in clinic contexts in InvitedDoctorDashboardScopeTest.
2026-07-18 13:32:56 +03:30

114 lines
3.8 KiB
PHP

<?php
namespace App\Doctor\Repository;
use App\Doctor\Entity\Doctor;
use App\Doctor\Entity\DoctorAddress;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class DoctorAddressRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, DoctorAddress::class);
}
public function save(DoctorAddress $address, bool $flush = true): void
{
$this->getEntityManager()->persist($address);
if ($flush) {
$this->getEntityManager()->flush();
}
}
public function remove(DoctorAddress $address, bool $flush = true): void
{
$this->getEntityManager()->remove($address);
if ($flush) {
$this->getEntityManager()->flush();
}
}
public function findByUuidAndClinic(string $uuid, int $clinicId): ?DoctorAddress
{
return $this->createQueryBuilder('a')
->where('a.uuid = :uuid')
->andWhere('a.clinicId = :clinicId')
->setParameter('uuid', $uuid)
->setParameter('clinicId', $clinicId)
->getQuery()
->getOneOrNullResult();
}
public function findOneByClinic(int $clinicId): ?DoctorAddress
{
return $this->createQueryBuilder('a')
->where('a.clinicId = :clinicId')
->setParameter('clinicId', $clinicId)
->orderBy('a.id', 'ASC')
->setMaxResults(1)
->getQuery()
->getOneOrNullResult();
}
public function countByClinic(int $clinicId): int
{
return (int) $this->createQueryBuilder('a')
->select('COUNT(a.id)')
->where('a.clinicId = :clinicId')
->setParameter('clinicId', $clinicId)
->getQuery()
->getSingleScalarResult();
}
/**
* آدرس‌های قابل‌انتخاب در یک context. مطب شخصی فقط آدرس‌های شخصی خود پزشک را
* می‌بیند و کلینیک فقط آدرس‌های خودش — این دو هرگز union نمی‌شوند.
*
* @return DoctorAddress[]
*/
public function findForContext(Doctor $doctor, ?int $clinicId): array
{
$qb = $this->createQueryBuilder('a');
if ($clinicId === null) {
$qb->where('a.doctor = :doctor')
->andWhere('a.type = :personal')
->setParameter('doctor', $doctor)
->setParameter('personal', DoctorAddress::TYPE_PERSONAL);
} else {
$qb->where('a.clinicId = :clinicId')
->andWhere('a.type = :clinic')
->setParameter('clinicId', $clinicId)
->setParameter('clinic', DoctorAddress::TYPE_CLINIC);
}
return $qb->orderBy('a.id', 'ASC')->getQuery()->getResult();
}
/** @deprecated آدرس‌های دو محیط را union می‌کند؛ از findForContext() استفاده کن. */
public function findAvailableForDoctor(Doctor $doctor, array $clinicIds): array
{
$qb = $this->createQueryBuilder('a');
$qb->where(
$qb->expr()->orX(
$qb->expr()->andX(
$qb->expr()->eq('a.doctor', ':doctor'),
$qb->expr()->eq('a.type', ':personal')
),
$qb->expr()->andX(
$qb->expr()->in('a.clinicId', ':clinicIds'),
$qb->expr()->eq('a.type', ':clinic')
)
)
)
->setParameter('doctor', $doctor)
->setParameter('personal', DoctorAddress::TYPE_PERSONAL)
->setParameter('clinicIds', empty($clinicIds) ? [0] : $clinicIds)
->setParameter('clinic', DoctorAddress::TYPE_CLINIC);
return $qb->getQuery()->getResult();
}
}