diff --git a/README.md b/README.md index 9ea254f..3e63ca0 100644 --- a/README.md +++ b/README.md @@ -429,18 +429,21 @@ Options::empty(); ### Using for validation -For convenience, you can quickly turn the same options you passed to the front end, as a back end validation rule. -This will account for nullable options too. +Options, can be converted to a Laravel validation rule: ```php -$options = Options::forArray([ - 'gondor' => 'Gondor', - 'rohan' => 'Rohan', - 'mordor' => 'Mordor', -]); +$request->validate([ + // ['in:frodo,sam,merry,pippin'] + 'hobbit' => Options::forEnum(Hobbit::class)->toValidationRule() +]); +``` +When options are nullable, the validation rule automatically will become nullable: + +```php $request->validate([ - 'my_options_input' => $options->toValidationRule() + // ['nullable', 'in:frodo,sam,merry,pippin'] + 'hobbit' => Options::forEnum(Hobbit::class)->nullable()->toValidationRule() ]); ``` diff --git a/src/Options.php b/src/Options.php index e633f9a..ce14276 100644 --- a/src/Options.php +++ b/src/Options.php @@ -14,6 +14,7 @@ use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Validation\Rule; +use Illuminate\Validation\Rules\In; use JsonSerializable; use MyCLabs\Enum\Enum as MyclabsEnum; use Spatie\Enum\Enum as SpatieEnum; @@ -168,6 +169,41 @@ public function push(SelectOption ...$options): self public function toArray(): array { + return $this->resolveOptions()->toArray(); + } + + /** + * @return array + */ + public function toValidationRule(): array + { + $rulesArray = [Rule::in($this->resolveOptions(enableNullOption: false)->pluck('value'))]; + + if ($this->nullable) { + $rulesArray[] = 'nullable'; + } + + return $rulesArray; + } + + public function toJson($options = 0) + { + return json_encode($this, flags: JSON_THROW_ON_ERROR); + } + + public function __toString() + { + return json_encode($this, flags: JSON_THROW_ON_ERROR); + } + + public function jsonSerialize(): mixed + { + return $this->toArray(); + } + + private function resolveOptions( + bool $enableNullOption = true, + ): Collection { return $this->provider ->provide() ->when($this->filter instanceof Closure, fn(Collection $collection) => $collection->filter($this->filter)) @@ -198,42 +234,11 @@ public function toArray(): array )) ->values() ->when( - $this->nullable === true, + $this->nullable === true && $enableNullOption, fn(Collection $collection) => $collection->prepend(new SelectOption( $this->nullableLabel, null )) - ) - ->toArray(); - } - - /** - * @return array - */ - public function toValidationRule(): array - { - $rulesArray = []; - if ($this->nullable) { - $rulesArray[] = 'nullable'; - } - - $rulesArray[] = Rule::in(array_filter(Arr::pluck($this->toArray(), 'value'))); - - return $rulesArray; - } - - public function toJson($options = 0) - { - return json_encode($this, flags: JSON_THROW_ON_ERROR); - } - - public function __toString() - { - return json_encode($this, flags: JSON_THROW_ON_ERROR); - } - - public function jsonSerialize(): mixed - { - return $this->toArray(); + ); } } diff --git a/tests/OptionsTest.php b/tests/OptionsTest.php index ab88416..76d0f1c 100644 --- a/tests/OptionsTest.php +++ b/tests/OptionsTest.php @@ -1,5 +1,6 @@ filter(fn (StringEnum $enum) => $enum === StringEnum::Frodo) + ->filter(fn(StringEnum $enum) => $enum === StringEnum::Frodo) ->toArray(); expect($options)->toBeArray()->toBe([ @@ -19,7 +20,7 @@ it('can reject options', function () { $options = Options::create(new NativeEnumProvider(StringEnum::class)) - ->reject(fn (StringEnum $enum) => $enum === StringEnum::Frodo) + ->reject(fn(StringEnum $enum) => $enum === StringEnum::Frodo) ->toArray(); expect($options)->toBeArray()->toBe([ @@ -44,7 +45,7 @@ it('can sort options using closure', function () { $options = Options::create(new NativeEnumProvider(StringEnum::class)) - ->sort(fn (StringEnum $enum) => match ($enum) { + ->sort(fn(StringEnum $enum) => match ($enum) { StringEnum::Frodo => 4, StringEnum::Sam => 3, StringEnum::Merry => 2, @@ -81,7 +82,7 @@ $model = Character::factory()->create(); $options = Options::forModels([$model, $model]) - ->unique(fn (Character $character) => $character->getKey()) + ->unique(fn(Character $character) => $character->getKey()) ->toArray(); expect($options)->toBeArray()->toBe([ @@ -92,7 +93,7 @@ it('can add a null option', function () { $options = Options::create(new NativeEnumProvider(StringEnum::class)) ->nullable() - ->sort(fn (StringEnum $enum) => match ($enum) { + ->sort(fn(StringEnum $enum) => match ($enum) { StringEnum::Frodo => 4, StringEnum::Sam => 3, StringEnum::Merry => 2, @@ -139,7 +140,7 @@ it('can append data using closure', function () { $options = Options::create(new NativeEnumProvider(StringEnum::class)) - ->append(fn (StringEnum $enum) => ['upper' => strtoupper($enum->name)]) + ->append(fn(StringEnum $enum) => ['upper' => strtoupper($enum->name)]) ->toArray(); expect($options)->toBeArray()->toBe([ @@ -178,7 +179,7 @@ Character::factory()->create(['name' => 'Aragon', 'kind' => 'Men']); $options = Options::forModels(SelectableCharacter::class) - ->append(fn (SelectableCharacter $character) => ['upper_name' => strtoupper($character->name)]) + ->append(fn(SelectableCharacter $character) => ['upper_name' => strtoupper($character->name)]) ->toArray(); expect($options)->toBeArray()->toBe([ @@ -192,42 +193,21 @@ }); it('can be turned into a laravel validation rule', function () { - $rules = Options::create(new NativeEnumProvider(StringEnum::class)) - ->toValidationRule(); + $rules = Options::create(new NativeEnumProvider(StringEnum::class))->toValidationRule(); expect($rules) ->toBeArray() - ->toHaveCount(1); - - $options = $rules[0]; - $optionsString = $options->__toString(); - - expect($options)->toBeInstanceOf(\Illuminate\Validation\Rules\In::class); - expect($optionsString) - ->toBeString() - ->toBe('in:"frodo","sam","merry","pippin"'); + ->toHaveCount(1) + ->toEqual([new In(['frodo', 'sam', 'merry', 'pippin'])]); }); it('can be turned into a laravel validation rule when nullable', function () { $rules = Options::create(new NativeEnumProvider(StringEnum::class)) - ->nullable() - ->toValidationRule(); + ->nullable() + ->toValidationRule(); expect($rules) ->toBeArray() - ->toHaveCount(2); - - $nullable = $rules[0]; - - expect($nullable) - ->toBeString() - ->toBe('nullable'); - - $options = $rules[1]; - $optionsString = $options->__toString(); - - expect($options)->toBeInstanceOf(\Illuminate\Validation\Rules\In::class); - expect($optionsString) - ->toBeString() - ->toBe('in:"frodo","sam","merry","pippin"'); + ->toHaveCount(2) + ->toEqual([new In(['frodo', 'sam', 'merry', 'pippin']), 'nullable']); });