Skip to content

Commit

Permalink
Update validation rule code
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenvanassche committed Jul 13, 2022
1 parent ec3016b commit 35d47db
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 76 deletions.
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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()
]);
```

Expand Down
71 changes: 38 additions & 33 deletions src/Options.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -168,6 +169,41 @@ public function push(SelectOption ...$options): self

public function toArray(): array
{
return $this->resolveOptions()->toArray();
}

/**
* @return array<string|In>
*/
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))
Expand Down Expand Up @@ -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<int, string|In>
*/
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();
);
}
}
50 changes: 15 additions & 35 deletions tests/OptionsTest.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php

use Illuminate\Validation\Rules\In;
use Spatie\LaravelOptions\Options;
use Spatie\LaravelOptions\Providers\NativeEnumProvider;
use Spatie\LaravelOptions\SelectOption;
Expand All @@ -9,7 +10,7 @@

it('can filter options', function () {
$options = Options::create(new NativeEnumProvider(StringEnum::class))
->filter(fn (StringEnum $enum) => $enum === StringEnum::Frodo)
->filter(fn(StringEnum $enum) => $enum === StringEnum::Frodo)
->toArray();

expect($options)->toBeArray()->toBe([
Expand All @@ -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([
Expand All @@ -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,
Expand Down Expand Up @@ -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([
Expand All @@ -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,
Expand Down Expand Up @@ -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([
Expand Down Expand Up @@ -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([
Expand All @@ -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']);
});

0 comments on commit 35d47db

Please sign in to comment.