4.7 KiB
4.7 KiB
معماری — تسک ۱۰: مدیریت پرسنل (Staff)
ساختار فایلها
src/Staff/
├── Controller/
│ └── StaffController.php
├── Entity/
│ └── ClinicStaff.php
├── Repository/
│ └── ClinicStaffRepository.php
└── Service/
└── StaffService.php
Entity: ClinicStaff
<?php
namespace App\Staff\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: \App\Staff\Repository\ClinicStaffRepository::class)]
#[ORM\Table(name: 'clinic_staff')]
#[ORM\Index(columns: ['entity_type', 'entity_id', 'active'], name: 'idx_clinic_staff_entity')]
class ClinicStaff
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private ?int $id = null;
#[ORM\Column(type: 'string', length: 36, unique: true)]
private string $uuid;
// polymorphic — 'doctor' یا 'clinic'
#[ORM\Column(type: 'string', length: 10)]
private string $entityType;
#[ORM\Column(type: 'integer')]
private int $entityId;
#[ORM\Column(type: 'string', length: 200)]
private string $fullName;
#[ORM\Column(type: 'string', length: 20, nullable: true)]
private ?string $phone = null;
#[ORM\Column(type: 'string', length: 100, nullable: true)]
private ?string $jobTitle = null;
#[ORM\Column(type: 'text', nullable: true)]
private ?string $address = null;
#[ORM\Column(type: 'string', length: 10, nullable: true)]
private ?string $nationalCode = null;
#[ORM\Column(type: 'boolean')]
private bool $active = true;
#[ORM\Column(type: 'integer')]
private int $createdAt;
#[ORM\Column(type: 'integer')]
private int $updatedAt;
public function __construct()
{
$this->uuid = (string) Uuid::v4();
$this->createdAt = time();
$this->updatedAt = time();
}
// getters/setters ...
}
Controller: StaffController
<?php
namespace App\Staff\Controller;
use App\Shared\Controller\BaseController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Attribute\Route;
#[Route('/api/v1')]
class StaffController extends BaseController
{
#[Route('/staff', methods: ['GET'])]
public function list(): JsonResponse
{
// 1. از JWT: entity_type و entity_id (db_key + db_uuid) را بگیر
// 2. StaffRepository::findByEntity($entityType, $entityId) صدا بزن
// 3. return $this->success($items);
}
#[Route('/staff', methods: ['POST'])]
public function create(Request $request): JsonResponse
{
// 1. validate: full_name اجباری
// 2. ClinicStaff جدید با entityType/entityId از JWT بساز
// 3. persist و flush
// 4. return $this->success($staff->toArray());
}
#[Route('/staff/{uuid}', methods: ['PATCH'])]
public function update(string $uuid, Request $request): JsonResponse
{
// 1. find by uuid → 404 اگر نبود
// 2. بررسی مالکیت: staff->entityType/entityId == JWT claim → 403 اگر نبود
// 3. ویرایش فیلدهای موجود در body
// 4. return $this->success($staff->toArray());
}
#[Route('/staff/{uuid}/toggle', methods: ['PATCH'])]
public function toggle(string $uuid): JsonResponse
{
// 1. find → ownership check
// 2. active = !active
// 3. return $this->success(['active' => $staff->isActive()]);
}
}
Service: StaffService
<?php
namespace App\Staff\Service;
class StaffService
{
public function toArray(ClinicStaff $staff): array
{
return [
'uuid' => $staff->getUuid(),
'full_name' => $staff->getFullName(),
'phone' => $staff->getPhone(),
'job_title' => $staff->getJobTitle(),
'address' => $staff->getAddress(),
'national_code' => $staff->getNationalCode(),
'active' => $staff->isActive(),
'created_at' => $staff->getCreatedAt(),
];
}
}
نحوه خواندن entity_type / entity_id از JWT
// در BaseController یا trait:
// JWT payload شامل: db_key ('doctor'/'clinic') و db_uuid (uuid entity)
// باید uuid را به id تبدیل کنیم:
$entityType = $this->getUser()->getDbKey(); // 'doctor' یا 'clinic'
$entityUuid = $this->getUser()->getDbUuid();
// سپس از Repository مربوطه id واقعی را بگیریم
وابستگیهای آینده
src/ClinicService/Entity/ServiceItem.php→staff_id FK → clinic_staff.idsrc/Patient/Entity/SessionService.php→staff_id FK → clinic_staff.id