Skip to content

Commit

Permalink
Merge 1.x to master (#685)
Browse files Browse the repository at this point in the history
  • Loading branch information
vjik committed Apr 5, 2024
1 parent 628e07c commit fe63447
Show file tree
Hide file tree
Showing 45 changed files with 3,134 additions and 123 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
phpunit:
uses: yiisoft/actions/.github/workflows/phpunit.yml@master
with:
extensions: intl
extensions: intl,fileinfo
coverage: xdebug
os: >-
['ubuntu-latest', 'windows-latest']
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@
- Enh #639: Simplify validation of JSON in `JsonHandler` using built-in PHP functions for PHP versions below 8.3
(@arogachev)

## 1.3.0 April 04, 2024

- New #665: Add methods `addErrorWithFormatOnly()` and `addErrorWithoutPostProcessing()` to `Result` object (@vjik)
- New #670, #677, #680: Add `Image` validation rule (@vjik, @arogachev)
- New #678: Add `Date`, `DateTime` and `Time` validation rules (@vjik)
- Enh #668: Clarify psalm types in `Result` (@vjik)

## 1.2.0 February 21, 2024

- New #597, #608: Add debug collector for `yiisoft/yii-debug` (@xepozz, @vjik)
Expand Down
4 changes: 4 additions & 0 deletions composer-require-checker.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"symbol-whitelist": [
"Yiisoft\\Yii\\Debug\\Collector\\CollectorTrait",
"Yiisoft\\Yii\\Debug\\Collector\\SummaryCollectorInterface",
"JetBrains\\PhpStorm\\ArrayShape",
"JetBrains\\PhpStorm\\ExpectedValues",
"JetBrains\\PhpStorm\\Language",
"json_validate"
],
"php-core-extensions": [
Expand All @@ -13,6 +16,7 @@
"Reflection",
"SPL",
"standard",
"fileinfo",
"intl"
],
"scan-files": []
Expand Down
10 changes: 6 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"issues": "https://github.com/yiisoft/validator/issues?state=open",
"forum": "https://www.yiiframework.com/forum/",
"wiki": "https://www.yiiframework.com/wiki/",
"irc": "irc://irc.freenode.net/yii",
"irc": "ircs://irc.libera.chat:6697/yii",
"chat": "https://t.me/yii3en",
"source": "https://github.com/yiisoft/validator"
},
Expand All @@ -30,11 +30,12 @@
"php": "^8.1",
"ext-mbstring": "*",
"psr/container": "^1.0|^2.0",
"psr/http-message": "^1.0|^2.0",
"yiisoft/arrays": "^2.1|^3.0",
"yiisoft/translator": "^2.1|^3.0",
"yiisoft/friendly-exception": "^1.0",
"yiisoft/network-utilities": "^1.0",
"yiisoft/strings": "^2.1"
"yiisoft/strings": "^2.1",
"yiisoft/translator": "^2.1|^3.0"
},
"require-dev": {
"jetbrains/phpstorm-attributes": "^1.0",
Expand All @@ -51,7 +52,8 @@
"yiisoft/yii-debug": "dev-master|dev-php80"
},
"suggest": {
"ext-intl": "Allows using IDN validation for emails",
"ext-intl": "Allows using date rules and IDN validation for emails",
"ext-fileinfo": "To use image rule",
"yiisoft/di": "To create rule handlers via Yii DI"
},
"autoload": {
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/en/built-in-rules-nested.md
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,6 @@ $data = [

[Result]: result.md
[Basic usage]: #basic-usage-one-to-one-relation
[JSFiddle]: http://jsfiddle.net/fys8uadr/
[JSFiddle]: https://jsfiddle.net/fys8uadr/
[Configuring rules via PHP attributes]: configuring-rules-via-php-attributes.md
[Using validator]: using-validator.md
10 changes: 10 additions & 0 deletions docs/guide/en/built-in-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ Here is a list of all available built-in rules, divided by category.
- [Count](../../../src/Rule/Count.php)
- [OneOf](../../../src/Rule/OneOf.php)

### File rules

- [Image](../../../src/Rule/Image/Image.php)

### Date rules

- [Date](../../../src/Rule/Date/Date.php)
- [DateTime](../../../src/Rule/Date/DateTime.php)
- [Time](../../../src/Rule/Date/Time.php)

### General purpose rules

- [Callback](../../../src/Rule/Callback.php)
Expand Down
38 changes: 22 additions & 16 deletions docs/guide/en/result.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ $result->isAttributeValid('name');

## Errors

Most of the time telling only the status of validation is not enough. There are multiple methods to get detailed errors
list with their data from the result. The difference between them is in the grouping, filtering, and representation of every
Most of the time telling only the status of validation is not enough. There are multiple methods to get detailed errors
list with their data from the result. The difference between them is in the grouping, filtering, and representation of every
error. Choose one to fit your needs depending on the situation.

### Flat list of error messages
Expand Down Expand Up @@ -128,25 +128,30 @@ Returning to the previous example, when `name` and `email` belong to a `user` at
];
```

Also keep in mind that attribute names are always strings, even when used with `Each`:
Also keep in mind that attribute names must be strings, even when used with `Each`:

```php
$rule = new Each([new Number(min: 21)]),
```

Given `[21, 22, 23, 20]` input, the output will be:
With input containing non-string keys for top level attributes, for example, `[21, 22, 23, 20]`, InvalidArgumentException` will be thrown.

Even array `['1' => 21, '2' => 22, '3' => 23, '4' => 20]` will cause an error, because PHP [will cast keys to the int type].

But if given array with string keys `['1a' => 21, '2b' => 22, '3c' => 23, '4d' => 20]`, the output will be:

```php
[
'1' => ['Value must be no less than 21.'],
'2' => ['Value must be no less than 21.'],
],
'4d' => [
0 => 'Value must be no less than 21.'
]
]
```

### Error messages indexed by path

This is probably the most advanced representation offered by built-in methods. The grouping is done by path - a
concatenated attribute sequence showing the location of errored value within a data structure. A separator is customizable,
This is probably the most advanced representation offered by built-in methods. The grouping is done by path - a
concatenated attribute sequence showing the location of errored value within a data structure. A separator is customizable,
dot notation is set as the default one. Use the following `Result` API call:

```php
Expand Down Expand Up @@ -202,8 +207,8 @@ $rules = [
];
```

However, when using the `Nested` rule with multiple attributes per rule set, special characters need to be escaped with
a backslash (`\`) for value paths to be correct and to be possible to reverse them back from string to individual
However, when using the `Nested` rule with multiple attributes per rule set, special characters need to be escaped with
a backslash (`\`) for value paths to be correct and to be possible to reverse them back from string to individual
items. See the [Using keys containing separator / shortcut] section for more details.

This can be used as an alternative to using a custom separator.
Expand All @@ -230,7 +235,7 @@ The output for example above:

## Error objects list

When even these representations are not enough, an initial unmodified list of error objects can be accessed via
When even these representations are not enough, an initial unmodified list of error objects can be accessed via
this method:

```php
Expand All @@ -242,9 +247,9 @@ $result->getErrors();

Each error stores the following data:

- Message. Either a simple message like `This value is wrong.` or a template with placeholders enclosed in curly braces
(`{}`), for example: `Value must be no less than {min}.`. The actual formatting is done in `Validator` depending on
the configured translator.
- Message. Either a simple message like `This value is wrong.` or a template with placeholders enclosed in curly braces
(`{}`), for example: `Value must be no less than {min}.`. The actual formatting is done in `Validator` depending on
the configured translator.
- Template parameters for substitution during formatting, for example: `['min' => 7]`.
- A path to a value within a checked data structure, for example: `['user', 'name', 'firstName']`.

Expand All @@ -264,7 +269,7 @@ What this can be useful for? For example, to build a nested tree of error messag
];
```

It's intentionally not provided out of the box due to the complexity of iteration. However, this can be useful for dumping
It's intentionally not provided out of the box due to the complexity of iteration. However, this can be useful for dumping
as JSON and storing in logs for example.

Debugging original error objects is also more convenient.
Expand All @@ -281,3 +286,4 @@ $result->getAttributeErrors('email');
```

[Using keys containing separator / shortcut]: built-in-rules-nested.md#using-keys-containing-separator--shortcut
[will cast keys to the int type]: https://www.php.net/manual/en/language.oop5.properties.php#language.oop5.properties.readonly-properties
11 changes: 11 additions & 0 deletions infection.json.dist
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@
"Yiisoft\\Validator\\EmptyCondition\\NeverEmpty::__invoke",
"Yiisoft\\Validator\\EmptyCondition\\WhenNull::__invoke"
]
},
"IncrementInteger": {
"ignoreSourceCodeByRegex": [
".*setDate\\(2024, 3, 29\\).*",
".*setTime\\(0, 0\\).*"
]
},
"DecrementInteger": {
"ignoreSourceCodeByRegex": [
".*setDate\\(2024, 3, 29\\).*"
]
}
}
}
19 changes: 19 additions & 0 deletions messages/ru/yii-validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,23 @@
'The allowed types are integer, float and string.' => 'Разрешённые типы: integer, float и string.',
'{Attribute} must be no less than {min}.' => '{Attribute} должно быть не меньше {min}.',
'{Attribute} must be no greater than {max}.' => '{Attribute} должно быть не больше {max}.',

/**
* @see \Yiisoft\Validator\Rule\Date\Date
* @see \Yiisoft\Validator\Rule\Date\DateTime
* @see \Yiisoft\Validator\Rule\Date\Time
*/
'{Attribute} must be no early than {limit}.' => '{Attribute} должно быть не ранее {limit}.',
'{Attribute} must be no late than {limit}.' => '{Attribute} должно быть не позднее {limit}.',

/**
* @see \Yiisoft\Validator\Rule\Date\Date
* @see \Yiisoft\Validator\Rule\Date\DateTime
*/
'Invalid date value.' => 'Некорректное значение даты.',

/**
* @see \Yiisoft\Validator\Rule\Date\Time
*/
'Invalid time value.' => 'Некорректное значение времени.',
];
21 changes: 21 additions & 0 deletions src/Error.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
*/
final class Error
{
public const MESSAGE_NONE = 0;
public const MESSAGE_FORMAT = 1;
public const MESSAGE_TRANSLATE = 2;

/**
* @param string $message The raw validation error message. Can be a simple text or a template with placeholders enclosed
* in curly braces (`{}`). In the end of the validation it will be translated using configured translator.
Expand Down Expand Up @@ -60,12 +64,19 @@ final class Error
*
* A value without nested structure won't have a path at all (it will be an empty array).
*
* @param int $messageProcessing Message processing type:
* - `Error::MESSAGE_NONE` - without post-processing;
* - `Error::MESSAGE_FORMAT` - format message;
* - `Error::MESSAGE_TRANSLATE` - translate message (translator do formatting also).
*
* @psalm-param list<int|string> $valuePath
* @psalm-param self::MESSAGE_* $messageProcessing
*/
public function __construct(
private string $message,
private array $parameters = [],
private array $valuePath = [],
private int $messageProcessing = self::MESSAGE_TRANSLATE,
) {
}

Expand Down Expand Up @@ -124,4 +135,14 @@ public function getValuePath(bool|string|null $escape = false): array
$this->valuePath,
);
}

/**
* Returns error message processing type.
*
* @psalm-return self::MESSAGE_*
*/
public function getMessageProcessing(): int
{
return $this->messageProcessing;
}
}
22 changes: 8 additions & 14 deletions src/Exception/UnexpectedRuleException.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,28 +36,22 @@
*/
final class UnexpectedRuleException extends InvalidArgumentException
{
/**
* @param string|string[] $expectedClassName Expected class name(s) of a rule.
* @param object $actualObject An actual given object that's not an instance of `$expectedClassName`.
* @param int $code The Exception code.
* @param Throwable|null $previous The previous throwable used for the exception chaining.
*/
public function __construct(
/**
* @var string Expected class name of a rule.
*/
string $expectedClassName,
/**
* @var object An actual given object that's not an instance of `$expectedClassName`.
*/
string|array $expectedClassName,
object $actualObject,
/**
* @var int The Exception code.
*/
int $code = 0,
/**
* @var Throwable|null The previous throwable used for the exception chaining.
*/
?Throwable $previous = null,
) {
parent::__construct(
sprintf(
'Expected "%s", but "%s" given.',
$expectedClassName,
implode('", "', (array) $expectedClassName),
$actualObject::class
),
$code,
Expand Down
47 changes: 47 additions & 0 deletions src/Helper/MessageProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Validator\Helper;

use Yiisoft\Translator\MessageFormatterInterface;
use Yiisoft\Translator\TranslatorInterface;
use Yiisoft\Validator\Error;

/**
* @internal
*/
final class MessageProcessor
{
/**
* @param TranslatorInterface $translator A translator instance used for translations of error messages.
* @param string $translationCategory A translation category.
* @param MessageFormatterInterface $messageFormatter A message formatter instance used for formats of error
* messages.
* @param string $messageFormatterLocale Locale to use when error message requires format only.
*/
public function __construct(
private TranslatorInterface $translator,
private string $translationCategory,
private MessageFormatterInterface $messageFormatter,
private string $messageFormatterLocale,
) {
}

public function process(Error $error): string
{
return match ($error->getMessageProcessing()) {
Error::MESSAGE_TRANSLATE => $this->translator->translate(
$error->getMessage(),
$error->getParameters(),
$this->translationCategory
),
Error::MESSAGE_FORMAT => $this->messageFormatter->format(
$error->getMessage(),
$error->getParameters(),
$this->messageFormatterLocale,
),
default => $error->getMessage(),
};
}
}
Loading

0 comments on commit fe63447

Please sign in to comment.