Enums
This document outlines the standards and best practices for using enums in the project. PHP 8.1 introduced native enum support, and we use them extensively to represent fixed sets of values.
Declaring Cases
Spacing
Ensure there is no space between cases, and they are all aligned under each other.
✅ Correct:
enum ProductAccessType: int
{
case Subscriber = 1;
case Private = 2;
case Organization = 3;
case Interview = 4;
}
❌ Incorrect:
enum ProductAccessType: int
{
case Subscriber = 1;
case Private = 2;
case Organization = 3;
case Interview = 4;
}
Naming
Use PascalCase for enum cases. This makes them easily distinguishable from variables and methods.
✅ Correct:
enum ProductAccessType: int
{
case Subscriber = 1;
case Private = 2;
}
❌ Incorrect:
enum ProductAccessType: int
{
case subscriber = 1;
case private = 2;
}
Helper Methods
toPersian()
Implement a toPersian() method for enums that need to display Persian text for their values. This is useful for user-facing content.
enum ProductAccessType: int
{
case Subscriber = 1;
case Private = 2;
case Organization = 3;
case Interview = 4;
public function toPersian(): string
{
return match($this) {
self::Subscriber => 'اشتراک',
self::Private => 'خصوصی',
self::Organization => 'سازمانی',
self::Interview => 'مصاحبه',
};
}
}
PersianList()
Implement a static PersianList() method to return an array of all enum cases with their Persian translations. This is useful for generating dropdown lists or other UI elements.
enum ProductAccessType: int
{
case Subscriber = 1;
case Private = 2;
case Organization = 3;
case Interview = 4;
public function toPersian(): string
{
return match($this) {
self::Subscriber => 'اشتراک',
self::Private => 'خصوصی',
self::Organization => 'سازمانی',
self::Interview => 'مصاحبه',
};
}
public static function PersianList(): array
{
return [
self::Subscriber->value => self::Subscriber->toPersian(),
self::Private->value => self::Private->toPersian(),
self::Organization->value => self::Organization->toPersian(),
self::Interview->value => self::Interview->toPersian(),
];
}
}
When to Use Enums
Use enums in the following scenarios:
- When you have a fixed set of related constants
- For status values, types, categories, or any other classification
- When you need type safety for a specific set of values
- When the values have associated behavior or properties
Benefits of Using Enums
- Type safety: The compiler ensures only valid enum values are used
- Self-documenting code: Enum cases clearly communicate the possible values
- Centralized definition: All related constants are defined in one place
- IDE support: Autocompletion for enum cases and methods
Examples
Example 1: User Roles
enum UserRole: string
{
case Admin = 'admin';
case Editor = 'editor';
case Author = 'author';
case Subscriber = 'subscriber';
public function toPersian(): string
{
return match($this) {
self::Admin => 'مدیر',
self::Editor => 'ویرایشگر',
self::Author => 'نویسنده',
self::Subscriber => 'مشترک',
};
}
public function canEditPosts(): bool
{
return match($this) {
self::Admin, self::Editor, self::Author => true,
self::Subscriber => false,
};
}
}
Example 2: Order Status
enum OrderStatus: int
{
case Pending = 1;
case Processing = 2;
case Shipped = 3;
case Delivered = 4;
case Cancelled = 5;
public function toPersian(): string
{
return match($this) {
self::Pending => 'در انتظار',
self::Processing => 'در حال پردازش',
self::Shipped => 'ارسال شده',
self::Delivered => 'تحویل داده شده',
self::Cancelled => 'لغو شده',
};
}
public function isActive(): bool
{
return match($this) {
self::Pending, self::Processing, self::Shipped => true,
self::Delivered, self::Cancelled => false,
};
}
}
How Are Enums Discovered and Identified in the System?
To make enum APIs dynamic and decoupled from hardcoded class references, we use an automated discovery and mapping mechanism:
-
Enum Discovery via Reflection
- A special command (
fetch enums) scans the entire project source code using PHP reflection. - It finds all classes that are enums and builds a mapping of enum names to their fully qualified class names.
- A special command (
-
Enum Map Cache
- The discovered mapping is stored as a key-value array in
/var/www/planet/lsp/bootstrap/cache/enums_map.php. - Example entry:
enums_map.php
return [
'StatusType' => App\\Enums\\StatusType::class,
'UserRole' => App\\Enums\\UserRole::class,
// ...
];
- The discovered mapping is stored as a key-value array in
-
Runtime Usage in EnumController
- When an API request is made (e.g.,
admin.enums.show?enum=StatusType), theEnumControllerlooks up the enum name in this cached map. - It then dynamically resolves and instantiates the correct Enum class using the fully qualified name.
- This allows the system to handle any registered enum without needing to update controller logic for each new enum.
- When an API request is made (e.g.,
This mechanism ensures that enum APIs are always up-to-date with the codebase, and new enums become available automatically after running the fetch command.
Enum API Endpoints and Automation
Admin Enum APIs
To facilitate working with enums in the admin panel, we have three dedicated API endpoints, all defined as GET routes and returning data via the standardized EnumTransformer:
-
admin.enums.index- Purpose: Retrieve data for multiple enums at once.
- Parameter:
enum(string) — Comma-separated list of enum names. - Response: A collection of enum data objects.
-
admin.enums.show- Purpose: Retrieve data for a single enum.
- Parameter: Enum name (string).
- Response: Enum data object.
-
admin.enums.keyValList- Purpose: Retrieve key-value pairs for a single enum, suitable for populating select inputs.
- Parameter: Enum name (string).
- Response: Key-value list of enum options.
All these routes are part of the admin API and return data using the EnumTransformer standard.
Example Usage
GET /api/admin/enums/index?enum=StatusType,UserRole
[
{
"name": "StatusType",
"values": [ ... ]
},
{
"name": "UserRole",
"values": [ ... ]
}
]