Skip to content

Commit

Permalink
Merge pull request #2 from MarkBaker/Add-CasesIndexedByName-Trait
Browse files Browse the repository at this point in the history
Add cases indexed by name trait
  • Loading branch information
MarkBaker authored Jan 20, 2022
2 parents 36339a0 + ecfc24b commit f1f58aa
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 12 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

All notable changes to `EnumHelper` will be documented in this file.

## 1.0.2 - 2022-01-20

- Added `CasesIndexedByName` trait, providing a `casesIndexedByName()` method to return an associative array of cases with the case name as the index, rather than an enumerated array that is returned by `cases()`.

## 1.0.1 - 2021-12-08

- Added `EnumValidatableCase` trait, providing an `isValidCase()` method to validate a string value against the set of case names defined for an enum.
Expand Down
119 changes: 111 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ This package provides a series of traits that allows you to:
- EnumValidatableCase

Validate an enum name from a name string.
- CasesIndexedByName

Similar to the standard static `cases()` method, but returns an associative array, indexed by the case names.

## Installation

Expand All @@ -28,8 +31,7 @@ composer require markbaker/enumhelper
In PHP 8.1, it is possible to create a backed enum from a value using the enum's `from()` or `tryFrom()` methods.

```php
enum Suit: string
{
enum Suit: string {
case Hearts = 'H';
case Diamonds = 'D';
case Clubs = 'C';
Expand All @@ -43,11 +45,10 @@ $value = $suit->value; // Returns 'D'
$newSuit = Suit::from($value);
```

The `EnumHelper\EnumRestorableFromName` trait provided in this library adds a `fromName()` method to any enum where you want to create an enum from its name.
The `EnumHelper\EnumRestorableFromName` trait provided in this library adds a `fromName()` method to any enum where you want to create an enum from its name, rather than from its value.

```php
enum Suit: string
{
enum Suit: string {
use EnumHelper\EnumRestorableFromName;

case Hearts = 'H';
Expand All @@ -74,8 +75,7 @@ This works with both backed and unbacked enums.
Useful to validate if a name has been defined in the case set for an enum:

```php
enum Suit: string
{
enum Suit: string {
use EnumHelper\EnumValidatableCase;

case Hearts = 'H';
Expand All @@ -97,10 +97,113 @@ Note that names are case-sensitive.

This works with both backed and unbacked enums.

### CasesIndexedByName Trait

While PHP 8.1+ Enums already provide a standard static `cases()` method to return a list of all cases defined for that enum:
```php
enum Suit: string {
use EnumHelper\EnumValidatableCase;

case Hearts = 'H';
case Diamonds = 'D';
case Clubs = 'C';
case Spades = 'S';
}

var_dump(Suit::cases());
```
which returns an enumerated array of the defined cases.
```
array(4) {
[0]=>
enum(Suit::Hearts)
[1]=>
enum(Suit::Diamonds)
[2]=>
enum(Suit::Clubs)
[3]=>
enum(Suit::Spades)
}
```
Using the `CasesIndexedByName` Trait and the related `casesIndexedByName()` method

```php
enum Suit: string {
use EnumHelper\CasesIndexedByName;

case Hearts = 'H';
case Diamonds = 'D';
case Clubs = 'C';
case Spades = 'S';
}

var_dump(Suit::casesIndexedByName());
```
which will return an associative array of the defined cases, where the array index is the case name.
```
array(4) {
["Hearts"]=>
enum(Suit::Hearts)
["Diamonds"]=>
enum(Suit::Diamonds)
["Clubs"]=>
enum(Suit::Clubs)
["Spades"]=>
enum(Suit::Spades)
}
```
This can be particularly useful if you filter the `cases()` list to return a subset of cases, and don't like the gaps in numeric sequence in the enumerated array.

```php
enum Suit: string {
use EnumHelper\CasesIndexedByName;

public const RED = 'Red';
public const BLACK = 'Black';

case Hearts = 'H';
case Diamonds = 'D';
case Clubs = 'C';
case Spades = 'S';

public function color(): string {
return match($this) {
self::Hearts, self::Diamonds => self::RED,
self::Clubs, self::Spades => self::BLACK,
};
}

public static function red(): array {
return array_filter(
self::casesIndexedByName(),
fn(self $suit) => $suit->color() === self::RED
);
}

public static function black(): array {
return array_filter(
self::casesIndexedByName(),
fn(self $suit) => $suit->color() === self::BLACK
);
}
}

var_dump(Suit::black());
```
will return
```
array(2) {
["Clubs"]=>
enum(Suit::Clubs)
["Spades"]=>
enum(Suit::Spades)
}
```

## Changelog

Please see the [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

## License

This librar is released under the MIT License (MIT). Please see [License File](LICENSE.md) for more information.
This library is released under the MIT License (MIT). Please see [License File](LICENSE.md) for more information.
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
}
},
"scripts": {
"style": "phpcs --report-width=200 --standard=PSR2 --report=summary,full src/ tests/ -n",
"versions": "phpcs --report-width=200 --standard=PHPCompatibility --report=summary,full classes/src/ --runtime-set testVersion 8.1- -n"
"style": "phpcs --report-width=200 --standard=PSR2 --report=summary,full src/ tests/src/ -n",
"versions": "phpcs --report-width=200 --standard=PHPCompatibility --report=summary,full src/ --runtime-set testVersion 8.1- -n"
},
"config": {
"sort-packages": true
Expand Down
20 changes: 20 additions & 0 deletions src/CasesIndexedByName.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace EnumHelper;

trait CasesIndexedByName
{
/**
* @return array<string, self>
*/
public static function casesIndexedByName()
{
return array_combine(
array_map(
fn(self $case) => $case->name,
self::cases()
),
self::cases()
);
}
}
27 changes: 26 additions & 1 deletion tests/data/BackedEnumSuit.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,38 @@

use EnumHelper\EnumRestorableFromName;
use EnumHelper\EnumValidatableCase;
use EnumHelper\CasesIndexedByName;

enum BackedEnumSuit: string
{
use EnumRestorableFromName, EnumValidatableCase;
use EnumRestorableFromName, EnumValidatableCase, CasesIndexedByName;

public const RED = 'Red';
public const BLACK = 'Black';

case Clubs = 'C';
case Diamonds = 'D';
case Hearts = 'H';
case Spades = 'S';

public function color(): string {
return match($this) {
self::Hearts, self::Diamonds => self::RED,
self::Clubs, self::Spades => self::BLACK,
};
}

public static function red(): array {
return array_filter(
self::casesIndexedByName(),
fn(self $suit) => $suit->color() === self::RED
);
}

public static function black(): array {
return array_filter(
self::casesIndexedByName(),
fn(self $suit) => $suit->color() === self::BLACK
);
}
}
27 changes: 26 additions & 1 deletion tests/data/EnumSuit.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,38 @@

use EnumHelper\EnumRestorableFromName;
use EnumHelper\EnumValidatableCase;
use EnumHelper\CasesIndexedByName;

enum EnumSuit
{
use EnumRestorableFromName, EnumValidatableCase;
use EnumRestorableFromName, EnumValidatableCase, CasesIndexedByName;

public const RED = 'Red';
public const BLACK = 'Black';

case Clubs;
case Diamonds;
case Hearts;
case Spades;

public function color(): string {
return match($this) {
self::Hearts, self::Diamonds => self::RED,
self::Clubs, self::Spades => self::BLACK,
};
}

public static function red(): array {
return array_filter(
self::casesIndexedByName(),
fn(self $suit) => $suit->color() === self::RED
);
}

public static function black(): array {
return array_filter(
self::casesIndexedByName(),
fn(self $suit) => $suit->color() === self::BLACK
);
}
}
18 changes: 18 additions & 0 deletions tests/src/CasesIndexedByNameTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace EnumHelper\Tests;

use EnumHelper\TestData\EnumSuit;
use PHPUnit\Framework\TestCase;

class CasesIndexedByNameTest extends TestCase
{
public function testCasesIndexedByName()
{
$cases = EnumSuit::casesIndexedByName();

foreach ($cases as $caseName => $case) {
self::assertSame($case->name, $caseName);
}
}
}

0 comments on commit f1f58aa

Please sign in to comment.