Skip to content

Commit

Permalink
[8.x] Add an Enum validation rule (laravel#39437)
Browse files Browse the repository at this point in the history
* add an Enum validation rule

* fix style

* fix test requirements

* fix style
  • Loading branch information
themsaid authored and chu121su12 committed Nov 2, 2021
1 parent 1221f15 commit a7773e0
Show file tree
Hide file tree
Showing 3 changed files with 213 additions and 0 deletions.
54 changes: 54 additions & 0 deletions src/Illuminate/Validation/Rules/Enum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace Illuminate\Validation\Rules;

use Illuminate\Contracts\Validation\Rule;

class Enum implements Rule
{
/**
* The type of the enum.
*
* @var string
*/
protected $type;

/**
* Create a new rule instance.
*
* @param string $type
* @return void
*/
public function __construct($type)
{
$this->type = $type;
}

/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
if (is_null($value) || ! function_exists('enum_exists') || ! enum_exists($this->type)) {
return false;
}

return ! is_null($this->type::tryFrom($value));
}

/**
* Get the validation error message.
*
* @return array
*/
public function message()
{
return [
'The selected :attribute is invalid.',
];
}
}
15 changes: 15 additions & 0 deletions tests/Validation/Enums.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Illuminate\Tests\Validation;

enum StringStatus: string
{
case pending = 'pending';
case done = 'done';
}

enum IntegerStatus: int
{
case pending = 1;
case done = 2;
}
144 changes: 144 additions & 0 deletions tests/Validation/ValidationEnumRuleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?php

namespace Illuminate\Tests\Validation;

use Illuminate\Container\Container;
use Illuminate\Support\Facades\Facade;
use Illuminate\Translation\ArrayLoader;
use Illuminate\Translation\Translator;
use Illuminate\Validation\Rules\Enum;
use Illuminate\Validation\Rules\Password;
use Illuminate\Validation\ValidationServiceProvider;
use Illuminate\Validation\Validator;
use PHPUnit\Framework\TestCase;

if (PHP_VERSION_ID >= 80100) {
include 'Enums.php';
}

/**
* @requires PHP >= 8.1
*/
class ValidationEnumRuleTest extends TestCase
{
public function testvalidationPassesWhenPassingCorrectEnum()
{
$v = new Validator(
resolve('translator'),
[
'status' => 'pending',
'int_status' => 1,
],
[
'status' => new Enum(StringStatus::class),
'int_status' => new Enum(IntegerStatus::class),
]
);

$this->assertFalse($v->fails());
}

public function testValidationFailsWhenProvidingNoExistingCases()
{
$v = new Validator(
resolve('translator'),
[
'status' => 'finished',
],
[
'status' => new Enum(StringStatus::class),
]
);

$this->assertTrue($v->fails());
$this->assertEquals(['The selected status is invalid.'], $v->messages()->get('status'));
}

public function testValidationFailsWhenProvidingDifferentType()
{
$v = new Validator(
resolve('translator'),
[
'status' => 10,
],
[
'status' => new Enum(StringStatus::class),
]
);

$this->assertTrue($v->fails());
$this->assertEquals(['The selected status is invalid.'], $v->messages()->get('status'));
}

public function testValidationPassesWhenProvidingDifferentTypeThatIsCastableToTheEnumType()
{
$v = new Validator(
resolve('translator'),
[
'status' => '1',
],
[
'status' => new Enum(IntegerStatus::class),
]
);

$this->assertFalse($v->fails());
}

public function testValidationFailsWhenProvidingNull()
{
$v = new Validator(
resolve('translator'),
[
'status' => null,
],
[
'status' => new Enum(StringStatus::class),
]
);

$this->assertTrue($v->fails());
$this->assertEquals(['The selected status is invalid.'], $v->messages()->get('status'));
}

public function testValidationPassesWhenProvidingNullButTheFieldIsNullable()
{
$v = new Validator(
resolve('translator'),
[
'status' => null,
],
[
'status' => ['nullable', new Enum(StringStatus::class)],
]
);

$this->assertFalse($v->fails());
}

protected function setUp(): void
{
$container = Container::getInstance();

$container->bind('translator', function () {
return new Translator(
new ArrayLoader, 'en'
);
});

Facade::setFacadeApplication($container);

(new ValidationServiceProvider($container))->register();
}

protected function tearDown(): void
{
Container::setInstance(null);

Facade::clearResolvedInstances();

Facade::setFacadeApplication(null);

Password::$defaultCallback = null;
}
}

0 comments on commit a7773e0

Please sign in to comment.