Files
clinicpro/docs/tasks/task-05-doctor/architecture.md
T
hamed de1a78a235 feat: Implement SMS sending functionality with KavehNegar and Rangineh providers
- Add SendSmsMessage class for encapsulating SMS message data.
- Create KavehNegarProvider and RanginehProvider classes implementing SmsProviderInterface for sending SMS.
- Implement SmsLogRepository and SmsTemplateRepository for managing SMS logs and templates.
- Develop SendSmsHandler for handling SMS sending messages.
- Create SmsService to manage SMS dispatching and logging.
- Add UserProfileController for managing user profiles with CRUD operations.
- Implement UserProfile entity and repository for user profile data management.
- Update symfony.lock and bootstrap.php for project dependencies and environment setup.
2026-06-09 22:00:34 +03:30

177 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# معماری — تسک ۰۵: ماژول دکتر
## ساختار فایل‌ها
```
src/Module/Doctor/
├── Controller/
│ ├── DoctorController.php ← CRUD دکتر + لیست + جستجو
│ ├── DoctorImageController.php ← آپلود تصویر
│ └── DoctorAddressController.php ← CRUD آدرس مطب
├── Service/
│ ├── DoctorService.php
│ └── DoctorAddressService.php
├── Repository/
│ ├── DoctorRepository.php
│ └── DoctorAddressRepository.php
├── Entity/
│ ├── Doctor.php
│ └── DoctorAddress.php
├── DTO/
│ ├── Request/
│ │ ├── CreateDoctorRequest.php
│ │ ├── UpdateDoctorRequest.php
│ │ ├── DoctorFilterRequest.php
│ │ ├── CreateDoctorAddressRequest.php
│ │ └── UpdateDoctorAddressRequest.php
│ └── Response/
│ ├── DoctorResponse.php ← view کامل با آمار
│ ├── DoctorListItemResponse.php ← لیست/جستجو
│ └── DoctorAddressResponse.php
└── Voter/
└── DoctorVoter.php
```
## Entity: Doctor (بر اساس فیلدهای واقعی Drupal)
```php
#[ORM\Entity]
#[ORM\Table(name: 'doctors')]
class Doctor
{
#[ORM\Id, ORM\GeneratedValue, ORM\Column]
private int $id;
#[ORM\Column(type: UuidType::NAME, unique: true)]
private Uuid $uuid;
#[ORM\OneToOne(targetEntity: User::class)]
#[ORM\JoinColumn(nullable: false)]
private User $user; // uid در Drupal
#[ORM\Column(length: 100)]
private string $name; // field_name
#[ORM\Column(length: 10, nullable: true)]
private ?string $gender; // field_gender
#[ORM\Column(length: 50)]
private string $medicalSystemCode; // field_doctor_id (شماره نظام پزشکی)
#[ORM\Column(type: 'integer', nullable: true)]
private ?int $activityTime; // field_activity_time (timestamp سال شروع)
#[ORM\Column(length: 100, nullable: true)]
private ?string $degree; // field_degree
#[ORM\Column(type: 'text', nullable: true)]
private ?string $info; // field_info
#[ORM\Column(length: 255, nullable: true)]
private ?string $imagePath; // field_image (media)
#[ORM\Column(type: 'decimal', precision: 3, scale: 1, options: ['default' => 3.5])]
private float $doctorRate = 3.5; // field_doctor_rate
#[ORM\Column(type: 'decimal', precision: 5, scale: 1, options: ['default' => 60])]
private float $doctorRatePercentage = 60; // field_doctor_rate_percentage
#[ORM\Column(type: 'boolean', options: ['default' => true])]
private bool $activeDoctorAppointment = true; // field_active_doctor_appointmen
#[ORM\ManyToOne(targetEntity: Representation::class)]
#[ORM\JoinColumn(nullable: true)]
private ?Representation $representation; // field_representation (multi-tenant)
// ManyToMany relations (field_specialty, field_doctor_services, field_state, field_city)
#[ORM\ManyToMany(targetEntity: Category::class)]
#[ORM\JoinTable(name: 'doctor_specialties')]
private Collection $specialties; // field_specialty (چند مقداری)
#[ORM\ManyToMany(targetEntity: Category::class)]
#[ORM\JoinTable(name: 'doctor_services')]
private Collection $services; // field_doctor_services (چند مقداری)
#[ORM\ManyToMany(targetEntity: Category::class)]
#[ORM\JoinTable(name: 'doctor_states')]
private Collection $states; // field_state
#[ORM\ManyToMany(targetEntity: Category::class)]
#[ORM\JoinTable(name: 'doctor_cities')]
private Collection $cities; // field_city
#[ORM\OneToMany(targetEntity: DoctorAddress::class, mappedBy: 'doctor')]
private Collection $addresses;
// TimestampableTrait
}
```
## Entity: DoctorAddress (بر اساس فیلدهای واقعی Drupal)
```php
#[ORM\Entity]
#[ORM\Table(name: 'doctor_addresses')]
class DoctorAddress
{
#[ORM\Id, ORM\GeneratedValue, ORM\Column]
private int $id;
#[ORM\Column(type: UuidType::NAME, unique: true)]
private Uuid $uuid;
#[ORM\ManyToOne(targetEntity: Doctor::class, inversedBy: 'addresses')]
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
private Doctor $doctor; // field_doctor
#[ORM\Column(length: 100, nullable: true)]
private ?string $name; // field_name (نام مطب/شعبه)
#[ORM\Column(type: 'text', nullable: true)]
private ?string $address; // field_address
#[ORM\Column(length: 20, nullable: true)]
private ?string $telephone; // field_telephone (نه phone!)
#[ORM\Column(type: 'decimal', precision: 10, scale: 8, nullable: true)]
private ?float $latitude; // field_latitude
#[ORM\Column(type: 'decimal', precision: 11, scale: 8, nullable: true)]
private ?float $longitude; // field_longitude
// TimestampableTrait
}
```
## Response کامل دکتر (finalizeData)
```json
{
"id": 5, "uuid": "...",
"name": "دکتر محمدی",
"gender": "male",
"experience": 12,
"activity_time": 1388534400,
"medical_system_code": "12345",
"detail": "متخصص قلب و عروق...",
"degree": "دکترای تخصصی",
"specialties": [{"id": 3, "uuid": "...", "name": "قلب و عروق"}],
"img": ["https://..."],
"expertise": [{"id": 10, "uuid": "...", "name": "اکوکاردیوگرافی"}],
"satisfaction": 87.5,
"point": 4.4,
"free_turn": "اولین نوبت آزاد: دوشنبه ۱۲ اردیبهشت ساعت ۱۰:۳۰",
"hours_of_work": ["شنبه", "یکشنبه", "دوشنبه"],
"address": [...],
"average_rate": {"average_stars": 4.3, "total_rates": 87},
"state": [{"id": 2, "uuid": "...", "name": "فارس"}],
"city": [{"id": 5, "uuid": "...", "name": "شیراز"}]
}
```
## منطق create دکتر (از DoctorService.php)
۱. اگر `doctor_mobile_number` داده شد:
- کاربر با این موبایل را پیدا کن
- اگر نقش `doctor` ندارد → 403
- اگر قبلاً profile دکتر دارد → 403
- اگر کاربر وجود ندارد → کاربر جدید با نقش doctor بساز
۲. اگر `doctor_mobile_number` نداده شد → کاربر جاری استفاده شود
۳. اعتبارسنجی همه فیلدهای اجباری
۴. ایجاد entity