160 lines
3.7 KiB
PHP
160 lines
3.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Shared\Enums;
|
|
|
|
/**
|
|
* @template V of string|int
|
|
*
|
|
* @mixin \BackedEnum
|
|
*/
|
|
trait BaseEnum
|
|
{
|
|
private const LABELS_CONSTANT_NAME = 'LABELS';
|
|
|
|
/**
|
|
* @return V
|
|
*/
|
|
public function value(): string | int
|
|
{
|
|
return $this->value;
|
|
}
|
|
|
|
public function label(): string
|
|
{
|
|
return self::toLabels()[$this->name] ?? ucfirst(strtolower($this->name));
|
|
}
|
|
|
|
public function name(): string
|
|
{
|
|
return $this->name;
|
|
}
|
|
|
|
/**
|
|
* @return array<string,string>
|
|
*/
|
|
public static function toLabels(): array
|
|
{
|
|
static $cache = null;
|
|
|
|
if ($cache !== null) {
|
|
return $cache;
|
|
}
|
|
|
|
$labels = defined(self::class . '::' . self::LABELS_CONSTANT_NAME)
|
|
? constant(self::class . '::' . self::LABELS_CONSTANT_NAME)
|
|
: null;
|
|
|
|
$result = [];
|
|
foreach (self::cases() as $enum) {
|
|
if ($labels !== null && ! isset($labels[$enum->name])) {
|
|
throw new \Error('Missing definition label ' . self::class . " for '{$enum->name}'");
|
|
}
|
|
$result[$enum->name] = $labels[$enum->name] ?? ucfirst(strtolower($enum->name));
|
|
}
|
|
|
|
return $cache = $result;
|
|
}
|
|
|
|
/**
|
|
* @return array<string, V>
|
|
*/
|
|
public static function toValues(): array
|
|
{
|
|
static $cache = null;
|
|
|
|
if ($cache !== null) {
|
|
return $cache;
|
|
}
|
|
|
|
return $cache = array_column(
|
|
self::cases(),
|
|
'value',
|
|
'name'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param self|V $value
|
|
*/
|
|
public static function make(self | int | string $value, string $field = 'value'): ?self
|
|
{
|
|
if ($value instanceof self) {
|
|
return $value;
|
|
}
|
|
|
|
if ($field === 'value') {
|
|
$tryValue = null;
|
|
try {
|
|
$tryValue = self::tryFrom(intval($value));
|
|
} catch (\ValueError) {
|
|
$tryValue = self::tryFrom(strval($value));
|
|
} finally {
|
|
if ($tryValue !== null) {
|
|
return $tryValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($field === 'label') {
|
|
$normalizedSearch = preg_replace('/[\W_]+/u', '', mb_strtolower((string) $value));
|
|
|
|
foreach (self::cases() as $enum) {
|
|
$normalizedLabel = preg_replace('/[\W_]+/u', '', mb_strtolower($enum->label()));
|
|
if ($normalizedLabel === $normalizedSearch) {
|
|
return $enum;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
foreach (self::cases() as $enum) {
|
|
if ($enum->{$field} === $value) {
|
|
return $enum;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function equals(object ...$others): bool
|
|
{
|
|
return in_array($this, $others, true);
|
|
}
|
|
|
|
public function jsonSerialize(): mixed
|
|
{
|
|
return $this->value;
|
|
}
|
|
|
|
// * PRIVATE
|
|
|
|
/**
|
|
* @return array<string, array<string, mixed>>
|
|
*/
|
|
private static function getCustomDefinitions(): array
|
|
{
|
|
static $cache = null;
|
|
|
|
if ($cache !== null) {
|
|
return $cache;
|
|
}
|
|
|
|
$names = array_column(self::cases(), 'name', 'name');
|
|
$filteredConstants = [];
|
|
|
|
foreach ((new \ReflectionClass(self::class))->getConstants() as $key => $constant) {
|
|
if ($key === self::LABELS_CONSTANT_NAME || ! \is_array($constant)) {
|
|
continue;
|
|
}
|
|
|
|
if (! empty(array_intersect_key($constant, $names))) {
|
|
$filteredConstants[$key] = $constant;
|
|
}
|
|
}
|
|
|
|
return $cache = $filteredConstants;
|
|
}
|
|
}
|