mirror of
https://github.com/ambieco/laravel-lift.git
synced 2026-01-12 22:43:48 +08:00
feature: Add enum support for Enum column casting
This commit is contained in:
@@ -4,10 +4,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace WendellAdriel\Lift\Concerns;
|
||||
|
||||
use BackedEnum;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use UnitEnum;
|
||||
use WendellAdriel\Lift\Attributes\Config;
|
||||
use WendellAdriel\Lift\Attributes\CreateRules;
|
||||
use WendellAdriel\Lift\Attributes\Rules;
|
||||
@@ -82,6 +84,32 @@ trait RulesValidation
|
||||
return self::formatValidationMessages(self::$modelUpdateMessages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a scalar value for the given value that might be an enum.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @template TValue
|
||||
* @template TDefault
|
||||
*
|
||||
* @param TValue $value
|
||||
* @param TDefault|callable(TValue): TDefault $default
|
||||
* @return ($value is empty ? TDefault : mixed)
|
||||
*/
|
||||
private static function enumValue($value, $default = null)
|
||||
{
|
||||
if (function_exists('Illuminate\Support\enum_value')) {
|
||||
return \Illuminate\Support\enum_value($value, $default);
|
||||
}
|
||||
|
||||
return transform($value, fn ($value) => match (true) {
|
||||
$value instanceof BackedEnum => $value->value,
|
||||
$value instanceof UnitEnum => $value->name,
|
||||
|
||||
default => $value,
|
||||
}, $default ?? $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection<PropertyInfo> $properties
|
||||
*
|
||||
@@ -90,10 +118,10 @@ trait RulesValidation
|
||||
private static function applyValidations(Collection $properties): void
|
||||
{
|
||||
$validatedProperties = self::getPropertiesForAttributes($properties, [Rules::class]);
|
||||
$data = $validatedProperties->mapWithKeys(fn ($property) => [$property->name => $property->value]);
|
||||
$data = $validatedProperties->mapWithKeys(fn ($property) => [$property->name => static::enumValue($property->value)]);
|
||||
|
||||
$configProperties = self::getPropertiesForAttributes($properties, [Config::class]);
|
||||
$data = $data->merge($configProperties->mapWithKeys(fn ($property) => [$property->name => $property->value]));
|
||||
$data = $data->merge($configProperties->mapWithKeys(fn ($property) => [$property->name => static::enumValue($property->value)]));
|
||||
|
||||
$validator = Validator::make(
|
||||
data: $data->toArray(),
|
||||
@@ -114,7 +142,7 @@ trait RulesValidation
|
||||
private static function applyCreateValidations(Collection $properties): void
|
||||
{
|
||||
$validatedProperties = self::getPropertiesForAttributes($properties, [CreateRules::class]);
|
||||
$data = $validatedProperties->mapWithKeys(fn ($property) => [$property->name => $property->value]);
|
||||
$data = $validatedProperties->mapWithKeys(fn ($property) => [$property->name => static::enumValue($property->value)]);
|
||||
|
||||
$validator = Validator::make(
|
||||
data: $data->toArray(),
|
||||
@@ -135,7 +163,7 @@ trait RulesValidation
|
||||
private static function applyUpdateValidations(Collection $properties): void
|
||||
{
|
||||
$validatedProperties = self::getPropertiesForAttributes($properties, [UpdateRules::class]);
|
||||
$data = $validatedProperties->mapWithKeys(fn ($property) => [$property->name => $property->value]);
|
||||
$data = $validatedProperties->mapWithKeys(fn (PropertyInfo $property) => [$property->name => static::enumValue($property->value)]);
|
||||
|
||||
$validator = Validator::make(
|
||||
data: $data->toArray(),
|
||||
|
||||
@@ -340,7 +340,7 @@ trait Lift
|
||||
{
|
||||
return $properties->filter(
|
||||
fn ($property) => $property->attributes->contains(
|
||||
fn ($attribute) => in_array($attribute->getName(), $attributes)
|
||||
fn ($attribute) => in_array($attribute->getName(), $attributes, true)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
28
tests/Datasets/Article.php
Normal file
28
tests/Datasets/Article.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Datasets;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Tests\Datasets\Enums\ArticleStatusEnum;
|
||||
use WendellAdriel\Lift\Attributes\Cast;
|
||||
use WendellAdriel\Lift\Attributes\PrimaryKey;
|
||||
use WendellAdriel\Lift\Attributes\Rules;
|
||||
use WendellAdriel\Lift\Lift;
|
||||
|
||||
class Article extends Model
|
||||
{
|
||||
use Lift;
|
||||
|
||||
#[PrimaryKey]
|
||||
public int $id;
|
||||
|
||||
#[Cast(ArticleStatusEnum::class)]
|
||||
#[Rules(['required', 'string', 'in:draft.published,archived'], ['required' => 'The book name cannot be empty', 'in' => 'The status must be draft, published or archived'])]
|
||||
public ArticleStatusEnum $status;
|
||||
|
||||
protected $fillable = [
|
||||
'status',
|
||||
];
|
||||
}
|
||||
12
tests/Datasets/Enums/ArticleStatusEnum.php
Normal file
12
tests/Datasets/Enums/ArticleStatusEnum.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Datasets\Enums;
|
||||
|
||||
enum ArticleStatusEnum: string
|
||||
{
|
||||
case DRAFT = 'draft';
|
||||
case PUBLISHED = 'published';
|
||||
case ARCHIVED = 'archived';
|
||||
}
|
||||
@@ -158,3 +158,17 @@ it('casts values when retrieving model with custom columns', function () {
|
||||
->and($product->expires_at->format('Y-m-d H:i:s'))->toBe('2023-12-31 23:59:59')
|
||||
->and($product->json_column)->toBe(['foo' => 'bar']);
|
||||
});
|
||||
|
||||
it('casts values when creating model with enum cast', closure: function () {
|
||||
$article = \Tests\Datasets\Article::castAndCreate([
|
||||
'status' => \Tests\Datasets\Enums\ArticleStatusEnum::ARCHIVED,
|
||||
]);
|
||||
|
||||
expect($article->status)->toBe(\Tests\Datasets\Enums\ArticleStatusEnum::ARCHIVED);
|
||||
|
||||
$this->assertDatabaseHas(\Tests\Datasets\Article::class, [
|
||||
'status' => \Tests\Datasets\Enums\ArticleStatusEnum::ARCHIVED,
|
||||
'id' => $article->id,
|
||||
]);
|
||||
$this->assertSame(\Tests\Datasets\Enums\ArticleStatusEnum::ARCHIVED, $article->status);
|
||||
});
|
||||
|
||||
@@ -210,6 +210,12 @@ abstract class TestCase extends BaseTestCase
|
||||
$table->string('title');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('articles', function (Blueprint $table) {
|
||||
$table->id('id');
|
||||
$table->enum('status', ['draft', 'published', 'archived']);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
protected function getPackageProviders($app)
|
||||
|
||||
Reference in New Issue
Block a user