Skip to content

Commit

Permalink
Add Instance Rule Object
Browse files Browse the repository at this point in the history
  • Loading branch information
macocci7 committed Apr 28, 2024
1 parent 1f6d449 commit 66699d5
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 1 deletion.
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,27 @@ $validator = Validator::make(
);
```

Additionally and uniquely, `Instance` rule object is supported.

```php
$validator = Validator::make(
data: [
'prop1' => new Instance([]),
'prop2' => 'Instance',
'prop3' => fn () => true,
],
rules: [
'prop1' => Instance::of(Instance::class),
'prop2' => Instance::of([
Instance::class,
Validator::class,
(fn () => true)::class,
]),
'prop3' => Instance::of('Closure'),
],
);
```

## 2. Contents

- [1. Features](#1-features)
Expand All @@ -46,6 +67,7 @@ $validator = Validator::make(
- [5.2. Setting Traslations Root Path and Language](#52-setting-translations-root-path-and-language)
- [5.3. Using Passowrd Rule Object](#53-using-password-rule-object)
- [5.4. Using File Rule Object](#54-using-file-rule-object)
- [5.5. Using Instance Rule Object](#55-using-instance-rule-object)
- [6. Examples](#6-examples)
- [7. LICENSE](#7-license)

Expand Down Expand Up @@ -193,12 +215,43 @@ You can learn more about Laravel's `File` rule object at the [Laravel Official D

Here's an example code for using Laravel's `File` rule object: [ValidateFile.php](examples/ValidateFile.php)

### 5.5. Using Instance Rule Object

You can validate objects using `Instance` rule object. (unique feature)

By using `Instance::of($class)` method as a rule, you can perform `$value instanceof $class` in the validation.

`Instance::of()` accepts class name(s) as an argument.

```php
use Macocci7\PurephpValidation\Rules\Instance;

$validator = Validator::make(
data: $data,
rules: [
'prop1' => Instance::of(Instance::class),
'prop2' => Instance::of([
// Macocci7\PurephpValidation\Rules\Instance
Instance::class,
// Macocci7\PurephpValidation\ValidatorFactory
Validator::class,
// Closure
(fn () => true)::class,
]),
'prop3' => Instance::of('Closure'),
],
);
```

Here's an example code for using `Instance` rule object: [ValidateInstance.php](examples/ValidateInstance.php)

## 6. Examples

- [BasicUsage.php](examples/BasicUsage.php)
- [SetTranslationsRootPath.php](examples/SetTranslationsRootPath.php)
- [ValidatePassword.php](examples/ValidatePassword.php)
- [ValidateFile.php](examples/ValidateFile.php)
- [ValidateInstance.php](examples/ValidateInstance.php)

## 7. LICENSE

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "macocci7/purephp-validation",
"description": "illuminate/validation wrapper for pure php.",
"version": "0.0.2",
"version": "0.0.3",
"type": "library",
"license": "MIT",
"autoload": {
Expand Down
31 changes: 31 additions & 0 deletions examples/ValidateInstance.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

require_once __DIR__ . '/../vendor/autoload.php';

use Macocci7\PurephpValidation\Rules\Instance;
use Macocci7\PurephpValidation\ValidatorFactory as Validator;

// Creating instance
$validator = Validator::make(
data: [
'prop1' => new Instance([]),
'prop2' => 'Instance',
'prop3' => fn () => true,
],
rules: [
'prop1' => Instance::of(Instance::class),
'prop2' => Instance::of([
Instance::class,
Validator::class,
(fn () => true)::class,
]),
'prop3' => Instance::of('Closure'),
],
);

// Checking result
if ($validator->fails()) {
var_dump($validator->errors()->messages());
} else {
echo "🎊 passed 🎉" . PHP_EOL;
}
59 changes: 59 additions & 0 deletions src/Rules/Instance.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace Macocci7\PurephpValidation\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class Instance implements ValidationRule
{
/**
* @var string[] $classes
*/
protected array $classes = [];

/**
* constructor
*
* @param string[] $classes
*/
public function __construct(array $classes)
{
$this->classes = $classes;
}

/**
* Run the validation rule.
*
* @param string $attribute
* @param mixed $value
* @param Closure $fail
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
$matched = false;
foreach ($this->classes as $class) {
if ($value instanceof $class) {
$matched = true;
break;
}
}
if (!$matched) {
$fail('validation.instance')->translate([
'classes' => implode(', ', $this->classes),
]);
}
}

/**
* Sets class names and returns an instance of this class
*
* @param string|string[] $class
* @return Instance
*/
public static function of(string|array $class)
{
return new static(is_string($class) ? [$class] : $class);
}
}
1 change: 1 addition & 0 deletions src/lang/en/validation.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
'image' => 'The :attribute field must be an image.',
'in' => 'The selected :attribute is invalid.',
'in_array' => 'The :attribute field must exist in :other.',
'instance' => 'The :attribute must be an instance of: :classes.',
'integer' => 'The :attribute field must be an integer.',
'ip' => 'The :attribute field must be a valid IP address.',
'ipv4' => 'The :attribute field must be a valid IPv4 address.',
Expand Down
1 change: 1 addition & 0 deletions src/lang/ja/validation.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
'image' => ':attributeには画像ファイルを指定してください。',
'in' => '選択された:attributeは正しくありません。',
'in_array' => ':attributeには:otherの値を指定してください。',
'instance' => ':attributeは次のいずれかのインスタンスを指定してください: :classes.',
'integer' => ':attributeは整数で指定してください。',
'ip' => ':attributeには、有効なIPアドレスを指定してください。',
'ipv4' => ':attributeには、有効なIPv4アドレスを指定してください。',
Expand Down
84 changes: 84 additions & 0 deletions tests/Rules/InstanceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

declare(strict_types=1);

namespace Macocci7\PurephpValidation;

use Illuminate\Validation\Rule;
use Macocci7\PurephpValidation\Rules\Instance;
use Macocci7\PurephpValidation\ValidatorFactory;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;

/**
* @SuppressWarnings(PHPMD.CamelCaseMethodName)
*/
final class InstanceTest extends TestCase
{
public static function provide_of_can_work_correctly(): array
{
return [
[
'input' => [
'lang' => 'en',
'data' => [
'prop1' => new Instance([]),
'prop2' => 'Instance',
'prop3' => fn () => true,
],
'rules' => [
'prop1' => Instance::of(Instance::class),
'prop2' => Instance::of([
Instance::class,
ValidatorFactory::class,
(fn () => true)::class,
]),
'prop3' => Instance::of('Closure'),
],
],
'expected' => [
'fails' => true,
'messages' => [
'prop2' => ['The prop2 must be an instance of: Macocci7\PurephpValidation\Rules\Instance, Macocci7\PurephpValidation\ValidatorFactory, Closure.'],
],
],
],
[
'input' => [
'lang' => 'ja',
'data' => [
'prop1' => new Instance([]),
'prop2' => 'Instance',
'prop3' => fn () => true,
],
'rules' => [
'prop1' => Instance::of(Instance::class),
'prop2' => Instance::of([
Instance::class,
ValidatorFactory::class,
(fn () => true)::class,
]),
'prop3' => Instance::of('Closure'),
],
],
'expected' => [
'fails' => true,
'messages' => [
'prop2' => ['prop2は次のいずれかのインスタンスを指定してください: Macocci7\PurephpValidation\Rules\Instance, Macocci7\PurephpValidation\ValidatorFactory, Closure.'],
],
],
],
];
}

#[DataProvider('provide_of_can_work_correctly')]
public function test_of_can_work_correctly(array $input, array $expected): void
{
ValidatorFactory::lang($input['lang']);
$validator = ValidatorFactory::make($input['data'], $input['rules']);
$this->assertSame($expected['fails'], $validator->fails());
if ($validator->fails()) {
$this->assertSame($expected['messages'], $validator->errors()->messages());
}
}
}
5 changes: 5 additions & 0 deletions tests/Rules/PasswordWrapperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public static function provide_password_rule_can_work_correctly(): array
return [
[
'input' => [
'lang' => 'en',
'data' => [
'password' => 'passwor',
],
Expand All @@ -35,6 +36,7 @@ public static function provide_password_rule_can_work_correctly(): array
],
[
'input' => [
'lang' => 'en',
'data' => [
'password' => 'password',
],
Expand All @@ -50,6 +52,7 @@ public static function provide_password_rule_can_work_correctly(): array
],
[
'input' => [
'lang' => 'en',
'data' => [
'password' => 'passwordpasswordpassword',
],
Expand All @@ -66,6 +69,7 @@ public static function provide_password_rule_can_work_correctly(): array
],
[
'input' => [
'lang' => 'en',
'data' => [
'password' => 'password',
],
Expand Down Expand Up @@ -98,6 +102,7 @@ public static function provide_password_rule_can_work_correctly(): array
#[DataProvider('provide_password_rule_can_work_correctly')]
public function test_password_rule_can_work_correctly(array $input, array $expected): void
{
ValidatorFactory::lang($input['lang']);
$validator = ValidatorFactory::make($input['data'], $input['rules']);
$this->assertSame($expected['fails'], $validator->fails());
if ($validator->fails()) {
Expand Down

0 comments on commit 66699d5

Please sign in to comment.