Skip to content

Commit 06536dd

Browse files
authored
Merge pull request #17 from webfox/feature/enum-collection-casting
Add EnumCollection support
2 parents 79fe7c9 + 2630d5f commit 06536dd

File tree

3 files changed

+119
-2
lines changed

3 files changed

+119
-2
lines changed

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,40 @@ public function rules(): array
333333
}
334334
```
335335

336+
## Other Classes
337+
338+
### AsFullEnumCollection
339+
This cast is similar to the Laravel built in `AsEnumCollection` cast but unlike the built in will maintain the full `toArray` structure
340+
when converting to json.
341+
342+
E.g. the Laravel built in `AsEnumCollection` cast will return the following json:
343+
```json
344+
["MILLIGRAMS", "GRAMS"]
345+
```
346+
This cast will return
347+
```json
348+
[
349+
{
350+
"name": "MILLIGRAMS",
351+
"value": "MILLIGRAMS",
352+
"label": "mg",
353+
"meta": {
354+
"background_color": "bg-green-100",
355+
"text_color": "text-green-800"
356+
}
357+
},
358+
{
359+
"name": "GRAMS",
360+
"value": "GRAMS",
361+
"label": "g",
362+
"meta": {
363+
"background_color": "bg-red-100",
364+
"text_color": "text-red-800"
365+
}
366+
}
367+
]
368+
```
369+
336370
## Changelog
337371

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

src/Casts/AsFullEnumCollection.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Webfox\LaravelBackedEnums\Casts;
5+
6+
use BackedEnum;
7+
use LogicException;
8+
use Illuminate\Support\Collection;
9+
use Illuminate\Database\Eloquent\Model;
10+
use Illuminate\Database\Eloquent\Casts\Json;
11+
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
12+
use function is_int;
13+
use function collect;
14+
use function is_array;
15+
use function constant;
16+
use function is_string;
17+
use function is_subclass_of;
18+
19+
/**
20+
* @template T of \UnitEnum|\BackedEnum
21+
*/
22+
class AsFullEnumCollection implements CastsAttributes
23+
{
24+
/**
25+
* @param class-string<T> $enumClass
26+
*/
27+
public function __construct(protected string $enumClass)
28+
{
29+
}
30+
31+
/**
32+
* @return \Illuminate\Support\Collection<T>|null
33+
*/
34+
public function get(Model $model, string $key, mixed $value, array $attributes): ?Collection
35+
{
36+
if (empty($attributes[$key])) {
37+
return new Collection();
38+
}
39+
40+
$data = Json::decode($attributes[$key]);
41+
42+
if (!is_array($data)) {
43+
throw new LogicException('Invalid data for enum collection cast: ' . $attributes[$key]);
44+
}
45+
46+
47+
return (new Collection($data))->map(function($value) {
48+
return is_subclass_of($this->enumClass, BackedEnum::class)
49+
? $this->enumClass::from($value)
50+
: constant($this->enumClass . '::' . $value);
51+
});
52+
}
53+
54+
public function set(Model $model, string $key, mixed $value, array $attributes): array
55+
{
56+
$valueArray = Collection::wrap($value)
57+
->map(fn($enum) => $this->getStorableEnumValue($enum))
58+
->jsonSerialize();
59+
60+
return [$key => Json::encode($valueArray)];
61+
}
62+
63+
protected function getStorableEnumValue($enum)
64+
{
65+
if (is_string($enum) || is_int($enum)) {
66+
return $enum;
67+
}
68+
69+
return $enum instanceof BackedEnum ? $enum->value : $enum->name;
70+
}
71+
}

src/IsBackedEnum.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22

33
namespace Webfox\LaravelBackedEnums;
44

5+
use Illuminate\Database\Eloquent\JsonEncodingException;
56
use Illuminate\Validation\Rules\Enum as EnumValidationRule;
7+
use function get_class;
8+
use function json_encode;
9+
use function json_last_error;
10+
use function json_last_error_msg;
11+
use const JSON_ERROR_NONE;
612

713
/**
814
* @implements \Webfox\LaravelBackedEnums\BackedEnum<string,string>
@@ -100,10 +106,16 @@ public function toHtml(): string
100106
return $this->label();
101107
}
102108

103-
public function toJson($options = 0): array
109+
public function toJson($options = 0): string
104110
{
105111
static::ensureImplementsInterface();
106-
return $this->toArray();
112+
$json = json_encode($this->toArray(), $options);
113+
114+
if (json_last_error() !== JSON_ERROR_NONE) {
115+
throw new JsonEncodingException('Error encoding enum ['.get_class($this).'] with value ['.$this->value.'] to JSON: '. json_last_error_msg());
116+
}
117+
118+
return $json;
107119
}
108120

109121
public function is(string|self $value): bool

0 commit comments

Comments
 (0)