Skip to content

Commit

Permalink
feature: Add enum support for Article status and enhance validation l…
Browse files Browse the repository at this point in the history
…ogic
  • Loading branch information
BadJacky committed Oct 28, 2024
1 parent 508158c commit 9c12844
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 5 deletions.
36 changes: 32 additions & 4 deletions src/Concerns/RulesValidation.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@

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;
Expand Down Expand Up @@ -82,6 +84,32 @@ public static function updateValidationMessages(): array
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
*
Expand All @@ -90,10 +118,10 @@ public static function updateValidationMessages(): array
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(),
Expand All @@ -114,7 +142,7 @@ private static function applyValidations(Collection $properties): void
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(),
Expand All @@ -135,7 +163,7 @@ private static function applyCreateValidations(Collection $properties): void
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(),
Expand Down
2 changes: 1 addition & 1 deletion src/Lift.php
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ private static function getPropertiesForAttributes(Collection $properties, array
{
return $properties->filter(
fn ($property) => $property->attributes->contains(
fn ($attribute) => in_array($attribute->getName(), $attributes)
fn ($attribute) => in_array($attribute->getName(), $attributes, true)
)
);
}
Expand Down
28 changes: 28 additions & 0 deletions tests/Datasets/Article.php
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 0 deletions tests/Datasets/Enums/ArticleStatusEnum.php
Original file line number Diff line number Diff line change
@@ -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';
}
14 changes: 14 additions & 0 deletions tests/Feature/CastTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,17 @@
->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);
});
6 changes: 6 additions & 0 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,12 @@ protected function setUp(): void
$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)
Expand Down

0 comments on commit 9c12844

Please sign in to comment.