Files
tez-utils-enum/src/EnumTrait.php
T

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];
}
}