, categories: list}> */ private const FIELDS = [ 'item_count' => [ 'label' => 'تعداد موارد انتخابی', 'type' => 'int', 'categories' => [Policy::CATEGORY_SELECTION, Policy::CATEGORY_RESOURCE, Policy::CATEGORY_TIMING, Policy::CATEGORY_PRICING], ], 'item_uuids' => [ 'label' => 'موارد انتخابی', 'type' => 'list', 'categories' => [Policy::CATEGORY_SELECTION], ], 'catalog_category' => [ 'label' => 'دستهٔ کاتالوگ', 'type' => 'uuid', 'categories' => [Policy::CATEGORY_SELECTION, Policy::CATEGORY_RESOURCE, Policy::CATEGORY_TIMING, Policy::CATEGORY_SPACING], ], 'service_uuid' => [ 'label' => 'سرویس', 'type' => 'uuid', 'categories' => [Policy::CATEGORY_RESOURCE, Policy::CATEGORY_TIMING, Policy::CATEGORY_SPACING], ], 'patient_age' => [ 'label' => 'سن بیمار', 'type' => 'int', 'categories' => [Policy::CATEGORY_ELIGIBILITY, Policy::CATEGORY_TIMING], ], 'patient_gender' => [ 'label' => 'جنسیت بیمار', 'type' => 'enum', 'values' => ['male', 'female'], 'categories' => [Policy::CATEGORY_ELIGIBILITY], ], 'patient_tags' => [ 'label' => 'برچسب‌های بیمار', 'type' => 'list', 'categories' => [Policy::CATEGORY_ELIGIBILITY, Policy::CATEGORY_PRICING], ], 'has_parental_consent' => [ 'label' => 'رضایت والدین', 'type' => 'bool', 'categories' => [Policy::CATEGORY_ELIGIBILITY], ], 'visit_count' => [ 'label' => 'تعداد ویزیت قبلی', 'type' => 'int', 'categories' => [Policy::CATEGORY_ELIGIBILITY, Policy::CATEGORY_PRICING], ], 'subtotal_rials' => [ 'label' => 'جمع مبلغ (ریال)', 'type' => 'int', 'categories' => [Policy::CATEGORY_PRICING], ], 'last_visit_at' => [ 'label' => 'آخرین ویزیت', 'type' => 'timestamp', 'categories' => [Policy::CATEGORY_ELIGIBILITY, Policy::CATEGORY_SPACING, Policy::CATEGORY_PRICING], ], ]; public function __construct(private readonly OperatorRegistry $operators) {} public function has(string $field): bool { return isset(self::FIELDS[$field]); } public function allowedIn(string $field, string $category): bool { return in_array($category, self::FIELDS[$field]['categories'] ?? [], true); } /** @return list */ public function forCategory(string $category): array { $out = []; foreach (self::FIELDS as $name => $meta) { if (in_array($category, $meta['categories'], true)) { $out[] = $name; } } return $out; } public function typeOf(string $field): string { return self::FIELDS[$field]['type'] ?? 'int'; } /** * فرادادهٔ فیلدهای یک دسته — همان چیزی که فرم ساخت قانون از آن ساخته می‌شود. * * عملگرها **فیلترشده per نوع** می‌آیند: اگر فرم همهٔ یازده عملگر را نشان بدهد، کاربر * `patient_tags > 5` می‌سازد و ۴۲۲ می‌گیرد بدون اینکه بفهمد چرا. * * @return array> */ public function describeCategory(string $category): array { $out = []; foreach ($this->forCategory($category) as $field) { $meta = self::FIELDS[$field]; $out[$field] = [ 'label' => $meta['label'], 'type' => $meta['type'], 'operators' => $this->operators->forType($meta['type']), ] + (isset($meta['values']) ? ['values' => $meta['values']] : []); } return $out; } /** * مقدار یک فیلد از حقایق درخواست. * * `null` در آرایه با «غایب» فرق دارد: اولی یعنی «می‌دانیم که ندارد» (سنِ ثبت‌نشده) و * دومی یعنی «این نقطه اصلاً این فیلد را نمی‌سازد». هر دو شرط را رد می‌کنند، ولی فقط * دومی نشانهٔ خطای پیکربندی است و باید لاگ شود. * * @param array $facts */ public function extract(string $field, array $facts): mixed { return $facts[$field] ?? null; } /** @param array $facts */ public function supplies(string $field, array $facts): bool { return array_key_exists($field, $facts); } }