Files
clinicpro/docs/phase2_taskes/task-10-staff/architecture.md
T

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.phpstaff_id FK → clinic_staff.id
  • src/Patient/Entity/SessionService.phpstaff_id FK → clinic_staff.id