Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Instance Rule Object #3

Merged
merged 1 commit into from
Apr 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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