Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ composer require k2gl/enum
## Usage

```php
use K2gl\Enum\src\ExtendedBackedEnumInterface;use K2gl\Enum\Types\ExtendedBackedEnum\ExtendedBackedEnum;
use K2gl\Enum\ExtendedBackedEnum;
use K2gl\Enum\ExtendedBackedEnumInterface;

enum CardSuit: string implements ExtendedBackedEnumInterface
{
Expand Down Expand Up @@ -54,6 +55,13 @@ $suit->isNot(ResponseCode::HTTP_I_AM_A_TEAPOT); // false

CardSuit::names(); // ['HEARTS', 'DIAMONDS', 'CLUBS', 'SPADES']
CardSuit::values(); // ['hearts', 'diamonds', 'clubs', 'spades']

// Resolve a case by its name — the counterpart of the native from()/tryFrom(),
// which only resolve by backing value.
CardSuit::fromName('SPADES'); // CardSuit::SPADES
CardSuit::tryFromName('SPADES'); // CardSuit::SPADES
CardSuit::tryFromName('joker'); // null
CardSuit::fromName('joker'); // throws \ValueError
```

## Pull requests are always welcome
Expand Down
2 changes: 1 addition & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
parameters:
level: 6
level: 9
paths:
- src
- tests/Examples
25 changes: 25 additions & 0 deletions src/ExtendedBackedEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,31 @@ public static function anyoneExcept(BackedEnum|array $except): static
return self::from($values[\array_rand($values)]);
}

/**
* Resolve a case by its name, mirroring the native from() which only
* resolves by backing value.
*
* @throws ValueError when no case has the given name
*/
public static function fromName(string $name): static
{
return self::tryFromName($name)
?? throw new ValueError(
sprintf('"%s" is not a valid name for enum %s', $name, self::class)
);
}

public static function tryFromName(string $name): ?static
{
foreach (self::cases() as $case) {
if ($case->name === $name) {
return $case;
}
}

return null;
}

public function is(mixed $value): bool
{
if ($value instanceof BackedEnum) {
Expand Down
8 changes: 8 additions & 0 deletions src/ExtendedBackedEnumInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace K2gl\Enum;

use BackedEnum;
use ValueError;

interface ExtendedBackedEnumInterface extends BackedEnum
{
Expand All @@ -15,6 +16,13 @@ public static function any(): static;
*/
public static function anyoneExcept(BackedEnum|array $except): static;

/**
* @throws ValueError when no case has the given name
*/
public static function fromName(string $name): static;

public static function tryFromName(string $name): ?static;

public function is(mixed $value): bool;

public function isNot(mixed $value): bool;
Expand Down
58 changes: 58 additions & 0 deletions tests/ExtendedBackedEnum/FromNameTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace K2gl\Enum\Tests\ExtendedBackedEnum;

use K2gl\Enum\ExtendedBackedEnumInterface;
use K2gl\Enum\Tests\Examples\CardSuit;
use K2gl\Enum\Tests\Examples\ResponseCode;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use ValueError;

use function K2gl\PHPUnitFluentAssertions\fact;

final class FromNameTest extends TestCase
{
#[DataProvider('validNameDataProvider')]
public function testResolvesCaseByName(string $name, ExtendedBackedEnumInterface $expected): void
{
// act
$case = $expected::fromName($name);

// assert
fact($case)->is($expected);
}

#[DataProvider('unknownNameDataProvider')]
public function testThrowsOnUnknownName(string $enumClass, string $name): void
{
// assert
$this->expectException(ValueError::class);

// act
$enumClass::fromName($name);
}

public static function validNameDataProvider(): array
{
return [
['HEARTS', CardSuit::HEARTS],
['SPADES', CardSuit::SPADES],
['HTTP_OK', ResponseCode::HTTP_OK],
['HTTP_I_AM_A_TEAPOT', ResponseCode::HTTP_I_AM_A_TEAPOT],
];
}

public static function unknownNameDataProvider(): array
{
return [
'missing name' => [CardSuit::class, 'JOKER'],
'wrong case' => [CardSuit::class, 'hearts'],
'backing value' => [CardSuit::class, 'spades'],
'empty string' => [CardSuit::class, ''],
'int enum, missing' => [ResponseCode::class, 'HTTP_TEAPOT'],
];
}
}
57 changes: 57 additions & 0 deletions tests/ExtendedBackedEnum/TryFromNameTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace K2gl\Enum\Tests\ExtendedBackedEnum;

use K2gl\Enum\ExtendedBackedEnumInterface;
use K2gl\Enum\Tests\Examples\CardSuit;
use K2gl\Enum\Tests\Examples\ResponseCode;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;

use function K2gl\PHPUnitFluentAssertions\fact;

final class TryFromNameTest extends TestCase
{
#[DataProvider('validNameDataProvider')]
public function testResolvesCaseByName(string $name, ExtendedBackedEnumInterface $expected): void
{
// act
$case = $expected::tryFromName($name);

// assert
fact($case)->is($expected);
}

#[DataProvider('unknownNameDataProvider')]
public function testReturnsNullOnUnknownName(string $enumClass, string $name): void
{
// act
$case = $enumClass::tryFromName($name);

// assert
fact($case)->null();
}

public static function validNameDataProvider(): array
{
return [
['HEARTS', CardSuit::HEARTS],
['SPADES', CardSuit::SPADES],
['HTTP_OK', ResponseCode::HTTP_OK],
['HTTP_I_AM_A_TEAPOT', ResponseCode::HTTP_I_AM_A_TEAPOT],
];
}

public static function unknownNameDataProvider(): array
{
return [
'missing name' => [CardSuit::class, 'JOKER'],
'wrong case' => [CardSuit::class, 'hearts'],
'backing value' => [CardSuit::class, 'spades'],
'empty string' => [CardSuit::class, ''],
'int enum, missing' => [ResponseCode::class, 'HTTP_TEAPOT'],
];
}
}