146 lines
3.7 KiB
PHP
146 lines
3.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tez\Utils\Enum;
|
|
|
|
/**
|
|
* Base trait for pure (unit) enums.
|
|
* Provides identity checks, lookup, filtering, and ordering helpers.
|
|
* Use BackedEnumTrait instead when your enum has backing values.
|
|
*
|
|
* @phpstan-require-implements \UnitEnum
|
|
*
|
|
* @method static list<static> cases()
|
|
*/
|
|
trait EnumTrait
|
|
{
|
|
/**
|
|
* Returns true if this case matches the given value by identity or name.
|
|
* Null always returns false.
|
|
*/
|
|
public function is(int|string|\UnitEnum|null $value): bool
|
|
{
|
|
if ($value === null) {
|
|
return false;
|
|
}
|
|
|
|
if ($value === $this) {
|
|
return true;
|
|
}
|
|
|
|
if (is_string($value)) {
|
|
return $this->name === $value;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/** @return array<string, string> */
|
|
public static function toArray(): array
|
|
{
|
|
return array_reduce(
|
|
static::cases(),
|
|
static fn($carry, $case) => $carry + [$case->name => $case->name],
|
|
[],
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns true if this case matches any value in the given list.
|
|
*
|
|
* @param int[]|string[]|\UnitEnum[]|null $values
|
|
*/
|
|
public function isOneOf(?array $values): bool
|
|
{
|
|
foreach ($values ?? [] as $value) {
|
|
if ($this->is($value)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns true if this case does not match any value in the given list.
|
|
*
|
|
* @param int[]|string[]|\UnitEnum[]|null $values
|
|
*/
|
|
public function isNoneOf(?array $values): bool
|
|
{
|
|
return !$this->isOneOf($values);
|
|
}
|
|
|
|
/**
|
|
* Finds a case by identity, name, or (for BackedEnums) backing value.
|
|
* Returns null when no match is found or when $value is null.
|
|
* Set $ignoreCase to true for case-insensitive name and string-value matching.
|
|
*/
|
|
public static function find(\UnitEnum|string|int|null $value, bool $ignoreCase = false): ?static
|
|
{
|
|
if ($value === null) {
|
|
return null;
|
|
}
|
|
|
|
if ($value instanceof static) {
|
|
return $value;
|
|
}
|
|
|
|
foreach (self::cases() as $case) {
|
|
if ($case instanceof \BackedEnum && !($value instanceof \UnitEnum)) {
|
|
$caseVal = $ignoreCase && is_string($case->value) ? strtoupper($case->value) : $case->value;
|
|
$searchVal = $ignoreCase && is_string($value) ? strtoupper($value) : $value;
|
|
|
|
if ($caseVal === $searchVal) {
|
|
return $case;
|
|
}
|
|
}
|
|
|
|
if (is_string($value)) {
|
|
$caseName = $ignoreCase ? strtoupper($case->name) : $case->name;
|
|
$searchName = $ignoreCase ? strtoupper($value) : $value;
|
|
|
|
if ($caseName === $searchName) {
|
|
return $case;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Returns all cases for which the callback returns true.
|
|
*
|
|
* @return list<static>
|
|
*/
|
|
public static function filter(callable $callback): array
|
|
{
|
|
return array_values(array_filter(static::cases(), $callback));
|
|
}
|
|
|
|
/** Returns the zero-based position of this case in the enum definition. */
|
|
public function ordinal(): int
|
|
{
|
|
$index = array_search($this, static::cases(), true);
|
|
assert($index !== false);
|
|
|
|
return $index;
|
|
}
|
|
|
|
/** Returns the first defined case. */
|
|
public static function first(): static
|
|
{
|
|
return static::cases()[0];
|
|
}
|
|
|
|
/** Returns the last defined case. */
|
|
public static function last(): static
|
|
{
|
|
$cases = static::cases();
|
|
|
|
return $cases[count($cases) - 1];
|
|
}
|
|
}
|