- 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.
177 lines
6.5 KiB
Markdown
177 lines
6.5 KiB
Markdown
# معماری — تسک ۰۵: ماژول دکتر
|
||
|
||
## ساختار فایلها
|
||
```
|
||
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
|