Skip to content

Commit

Permalink
Improvements (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
vjik committed Dec 12, 2022
1 parent 62f0eb9 commit a376c94
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 73 deletions.
147 changes: 145 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
# Yii Validator Scenarios
<p align="center">
<a href="https://github.com/yiisoft" target="_blank">
<img src="https://yiisoft.github.io/docs/images/yii_logo.svg" height="100px">
</a>
<h1 align="center">Yii Validator Scenarios</h1>
<br>
</p>

[![Latest Stable Version](https://poser.pugx.org/vjik/yii-validator-scenarios/v/stable.png)](https://packagist.org/packages/vjik/yii-validator-scenarios)
[![Total Downloads](https://poser.pugx.org/vjik/yii-validator-scenarios/downloads.png)](https://packagist.org/packages/vjik/yii-validator-scenarios)
Expand All @@ -8,7 +14,8 @@
[![static analysis](https://github.com/vjik/yii-validator-scenarios/workflows/static%20analysis/badge.svg)](https://github.com/vjik/yii-validator-scenarios/actions?query=workflow%3A%22static+analysis%22)
[![psalm-level](https://shepherd.dev/github/vjik/yii-validator-scenarios/level.svg)](https://shepherd.dev/github/vjik/yii-validator-scenarios)

The package ...
The package provides validator rule `On` that implement the scenario feature
for [Yii Validator](https://github.com/yiisoft/validator).

## Requirements

Expand All @@ -24,6 +31,142 @@ composer require vjik/yii-validator-scenarios

## General usage

The scenario feature implement via the rule `On` and a validation context parameter.

Configure rules:

```php
use Vjik\Yii\ValidatorScenarios\On;
use Yiisoft\Validator\Rule\Email;
use Yiisoft\Validator\Rule\HasLength;
use Yiisoft\Validator\Rule\Required;

final class UserDto
{
public function __construct(
#[On(
'register',
[new Required(), new HasLength(min: 7, max: 10)]
)]
public string $name,

#[Required]
#[Email]
public string $email,

#[On(
['login', 'register'],
[new Required(), new HasLength(min: 8)],
)]
public string $password,
) {
}
}
```

Or same without attributes:

```php
use Vjik\Yii\ValidatorScenarios\On;
use Yiisoft\Validator\Rule\Email;
use Yiisoft\Validator\Rule\HasLength;
use Yiisoft\Validator\Rule\Required;
use Yiisoft\Validator\RulesProviderInterface;

final class UserDto implements RulesProviderInterface
{
public function __construct(
public string $name,
public string $email,
public string $password,
) {
}

public function getRules(): iterable
{
return [
'name' => new On(
'register',
[new Required(), new HasLength(min: 7, max: 10)],
),
'email' => [new Required(), new Email()],
'password' => new On(
['login', 'register'],
[new Required(), new HasLength(min: 8)],
),
];
}
}
```

Pass the scenario to the validator through the context:

```php
use Yiisoft\Validator\ValidationContext;
use Yiisoft\Validator\Validator;

$result = (new Validator())->validate(
$userDto,
context: new ValidationContext([
On::SCENARIO_PARAMETER => $scenario,
]),
);
```

Rules that will be applied according to scenarios:

**register**

| Attrubute | Rules |
|------------|-------------------------|
| `name` | `Required`, `HasLength` |
| `email` | `Required`, `Email` |
| `password` | `Required`, `HasLength` |

**login**

| Attrubute | Rules |
|------------|-------------------------|
| `name` ||
| `email` | `Required`, `Email` |
| `password` | `Required`, `HasLength` |

**Without scenario**

| Attrubute | Rules |
|------------|---------------------|
| `name` ||
| `email` | `Required`, `Email` |
| `password` ||

## `On` rule parameters

**$scenario**

The scenario(s) that `$rules` are in. `null` if rules used always. Defaults to `null`.

**$rules**

Rules that will be applied according to `$scenario`. Defaults to empty array.

**$not**

Whether the scenario check should be inverted. When this parameter is set `true`, the validator checks whether
the current scenario is among `$scenario` and if NOT, `$rules` will be applied. Defaults to `false`.

**$skipOnEmpty**

Whether skip `$rules` on empty value or not, and which value consider as empty. Defaults to `null`.

**$skipOnError**

A boolean value where `true` means to skip `$rules` when the previous one errored and `false` — do not skip.
Defaults to `false`.

**$when**

The closure that allow to apply `$rules` under certain conditions only. Defaults to `null`.

## Testing

### Unit testing
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": "vjik/yii-validator-scenarios",
"type": "library",
"description": "Yii Validator Scenarios",
"description": "The scenario feature for Yii Validator",
"keywords": [
"yii",
"validator",
Expand Down
66 changes: 51 additions & 15 deletions src/On.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,34 @@
use Yiisoft\Validator\WhenInterface;

/**
* The rule implement the scenario feature.
*
* Example:
*
* ```php
* final class UserDto
* {
* public function __construct(
* #[On(
* 'register',
* [new Required(), new HasLength(min: 7, max: 10)]
* )]
* public string $name,
*
* #[Required]
* #[Email]
* public string $email,
*
* #[On(
* ['login', 'register'],
* [new Required(), new HasLength(min: 8)],
* )]
* public string $password,
* ) {
* }
* }
* ```
*
* @psalm-import-type WhenType from WhenInterface
*/
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
Expand All @@ -47,34 +75,42 @@ final class On implements
*/
private iterable $rules;

/**
* @var bool|callable|null
*/
private $skipOnEmpty;

private ?RulesDumper $rulesDumper = null;

/**
* @param string|Stringable|string[]|Stringable[]|null $scenario The scenario(s) that rules are in. `null` if rules
* used always.
* @param iterable<callable|RuleInterface>|callable|RuleInterface $rules Rules that will be applied according
* to `$scenario`.
* @param bool $not Whether the scenario check should be inverted. When this parameter is set `true`, the validator
* checks whether the current scenario is among `$scenario` and if NOT, `$rules` will be applied.
* @param bool|callable|null $skipOnEmpty Whether skip `$rules` on empty value or not, and which value consider as
* empty. More details in {@see SkipOnEmptyInterface}.
* @param bool $skipOnError A boolean value where `true` means to skip `$rules` when the previous one errored
* and `false` - do not skip.
* @param Closure|null $when The closure that allow to apply `$rules` under certain conditions only. More details
* in {@see SkipOnErrorInterface}.
*
* @psalm-param WhenType $when
*
* @throws InvalidArgumentException
*/
public function __construct(
/**
* @var string|Stringable|string[]|Stringable[]|null The scenario(s) that rules are in. Null if rules used
* always.
*/
string|Stringable|array|null $scenario = null,
/**
* @param iterable<callable|RuleInterface>|callable|RuleInterface Rules to apply.
*/
callable|iterable|object $rules = [],
callable|iterable|RuleInterface $rules = [],
private bool $not = false,
/**
* @var bool|callable|null
*/
private $skipOnEmpty = null,
bool|callable|null $skipOnEmpty = null,
private bool $skipOnError = false,
/**
* @var WhenType
*/
private Closure|null $when = null,
) {
$this->setScenarios($scenario);
$this->rules = RulesNormalizer::normalizeList($rules);
$this->skipOnEmpty = $skipOnEmpty;
}

public function getName(): string
Expand Down
4 changes: 2 additions & 2 deletions tests/Php81/OnTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use PHPUnit\Framework\TestCase;
use Vjik\Yii\ValidatorScenarios\On;
use Vjik\Yii\ValidatorScenarios\Tests\Support\ClassAttribute;
use Vjik\Yii\ValidatorScenarios\Tests\Support\User;
use Vjik\Yii\ValidatorScenarios\Tests\Support\UserDto;
use Yiisoft\Validator\ValidationContext;
use Yiisoft\Validator\Validator;

Expand Down Expand Up @@ -45,7 +45,7 @@ public function dataBase(): array
*/
public function testBase(array $expectedMessage, ?string $scenario): void
{
$user = new User(
$user = new UserDto(
name: 'bob',
email: 'hello.ru',
password: 'qwerty',
Expand Down
53 changes: 0 additions & 53 deletions tests/Support/User.php

This file was deleted.

32 changes: 32 additions & 0 deletions tests/Support/UserDto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace Vjik\Yii\ValidatorScenarios\Tests\Support;

use Vjik\Yii\ValidatorScenarios\On;
use Yiisoft\Validator\Rule\Email;
use Yiisoft\Validator\Rule\HasLength;
use Yiisoft\Validator\Rule\Required;

final class UserDto
{
public function __construct(
#[On(
'register',
[new Required(), new HasLength(min: 7, max: 10)]
)]
public string $name,

#[Required]
#[Email]
public string $email,

#[On(
['login', 'register'],
[new Required(), new HasLength(min: 8)],
)]
public string $password,
) {
}
}

0 comments on commit a376c94

Please sign in to comment.