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

Fix OneOf and AtLeast messages #625

Merged
merged 10 commits into from
Aug 26, 2023
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
# Yii Validator Change Log

## 1.2.0 under development
## 2.0.0 under development

- New #597, #608: Add debug collector for `yiisoft/yii-debug` (@xepozz, @vjik)
- New #610: Add `$escape` parameter to methods `Result::getAttributeErrorMessagesIndexedByPath()` and
`Result::getErrorMessagesIndexedByPath()` that allow change or disable symbol which will be escaped in value path
elements (@vjik)
- Bug #612: Disable escaping of asterisk char in value path returned by `Error::getValuePath(true)` (@vjik)
- New #617: Add `OneOf` rule (@arogachev)
- Chg #623: List translated attributes in error message for `OneOf` and `AtLeast` rules (@arogachev)
- Chg #624: Fix meaning of error message in `OneOf` rule (@arogachev)
- Chg #625: Improve meaning and use pluralization in error message for `OneOf` and `AtLeast` rules (@arogachev)

## 1.1.0 April 06, 2023

Expand Down
4 changes: 2 additions & 2 deletions messages/pl/yii-validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
// Used in single rule

/** @see AtLeast */
'The data must have at least "{min}" filled attributes.' => 'Dane muszą mieć co najmniej "{min}" wypełnionych atrybutów.',
'At least {min, number} {min, plural, one{attribute} other{attributes}} from this list must be filled' => 'At least {min, number} {min, plural, one{attribute} other{attributes}} from this list must be filled',
/** @see BooleanValue */
'Value must be either "{true}" or "{false}".' => 'Wartość musi wynosić "{true}" albo "{false}".',
/** @see Count */
Expand Down Expand Up @@ -70,7 +70,7 @@
/** @see Number */
'Value must be a number.' => 'Wartość musi być liczbą.',
/** @see OneOf */
'The data must have at least 1 filled attribute.' => 'Dane muszą mieć co najmniej 1 wypełniony atrybut.',
'Exactly 1 attribute from this list must be filled: {attributes}.' => 'Exactly 1 attribute from this list must be filled: {attributes}.',
/** @see Regex */
'Value is invalid.' => 'Wartość jest nieprawidłowa.',
/** @see Required */
Expand Down
8 changes: 6 additions & 2 deletions messages/ru/yii-validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@
// Used in single rule

/** @see AtLeast */
'The data must have at least "{min}" filled attributes.' => 'Данные должны содержать минимум {min, number} {min, plural, one{заполненный атрибут} few{заполненных атрибута} many{заполненных атрибутов} other{заполненных атрибута}}.',
'At least {min, number} {min, plural, one{attribute} other{attributes}} from this list must be filled' => 'Как ' .
'минимум {min, number}' .
'{min, plural, one{атрибут} few{атрибута} many{атрибутов} other{атрибута}} из этого списка ' .
'{min, plural, one{должен} few{должны} many{должны} other{должны}} быть ' .
'заполнены: {attributes}.',
/** @see BooleanValue */
'Value must be either "{true}" or "{false}".' => 'Значение должно быть «{true}» или «{false}».',
/** @see Count */
Expand Down Expand Up @@ -70,7 +74,7 @@
/** @see Number */
'Value must be a number.' => 'Значение должно быть числом.',
/** @see OneOf */
'The data must have at least 1 filled attribute.' => 'Данные должны содержать минимум 1 заполненный атрибут.',
'Exactly 1 attribute from this list must be filled: {attributes}.' => 'Ровно 1 атрибут из этого списка должен быть заполнен: {attributes}.',
/** @see Regex */
'Value is invalid.' => 'Значение неверно.',
/** @see Required */
Expand Down
4 changes: 2 additions & 2 deletions messages/uz/yii-validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
// Used in single rule

/** @see AtLeast */
'The data must have at least "{min}" filled attributes.' => 'Kamida {min} ta atributlar toʻldirilgan boʻlishi kerak.',
'At least {min, number} {min, plural, one{attribute} other{attributes}} from this list must be filled' => 'At least {min, number} {min, plural, one{attribute} other{attributes}} from this list must be filled',
/** @see BooleanValue */
'Value must be either "{true}" or "{false}".' => 'Qiymat "{true}" yoki "{false}" boʻlishi kerak.',
/** @see Count */
Expand Down Expand Up @@ -70,7 +70,7 @@
/** @see Number */
'Value must be a number.' => 'Qiymat raqam boʻlishi kerak.',
/** @see OneOf */
'The data must have at least 1 filled attribute.' => 'Kamida 1 ta atribut toʻldirilgan boʻlishi kerak.',
'Exactly 1 attribute from this list must be filled: {attributes}.' => 'Exactly 1 attribute from this list must be filled: {attributes}.',
/** @see Regex */
'Value is invalid.' => 'Qiymat notoʻgʻri.',
/** @see Required */
Expand Down
3 changes: 2 additions & 1 deletion src/Rule/AtLeast.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ public function __construct(
private array $attributes,
private int $min = 1,
private string $incorrectInputMessage = 'The value must be an array or an object.',
private string $message = 'The data must have at least "{min}" filled attributes.',
private string $message = 'At least {min, number} {min, plural, one{attribute} other{attributes}} from this ' .
'list must be filled: {attributes}.',
private mixed $skipOnEmpty = null,
private bool $skipOnError = false,
private Closure|null $when = null
Expand Down
5 changes: 4 additions & 1 deletion src/Rule/AtLeastHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Yiisoft\Arrays\ArrayHelper;
use Yiisoft\Validator\Exception\UnexpectedRuleException;
use Yiisoft\Validator\Result;
use Yiisoft\Validator\Rule\Trait\TranslatedAttributesHandlerTrait;
use Yiisoft\Validator\RuleHandlerInterface;
use Yiisoft\Validator\EmptyCondition\WhenEmpty;
use Yiisoft\Validator\ValidationContext;
Expand All @@ -21,6 +22,8 @@
*/
final class AtLeastHandler implements RuleHandlerInterface
{
use TranslatedAttributesHandlerTrait;

public function validate(mixed $value, object $rule, ValidationContext $context): Result
{
if (!$rule instanceof AtLeast) {
Expand Down Expand Up @@ -48,7 +51,7 @@ public function validate(mixed $value, object $rule, ValidationContext $context)

if ($filledCount < $rule->getMin()) {
$result->addError($rule->getMessage(), [
'attribute' => $context->getTranslatedAttribute(),
'attributes' => $this->getFormattedAttributesString($rule->getAttributes(), $context),
'min' => $rule->getMin(),
]);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Rule/OneOf.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ final class OneOf implements RuleWithOptionsInterface, SkipOnErrorInterface, Whe
public function __construct(
private array $attributes,
private string $incorrectInputMessage = 'The value must be an array or an object.',
private string $message = 'The data must have at least 1 filled attribute.',
private string $message = 'Exactly 1 attribute from this list must be filled: {attributes}.',
private mixed $skipOnEmpty = null,
private bool $skipOnError = false,
private Closure|null $when = null
Expand Down
13 changes: 8 additions & 5 deletions src/Rule/OneOfHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Yiisoft\Arrays\ArrayHelper;
use Yiisoft\Validator\Exception\UnexpectedRuleException;
use Yiisoft\Validator\Result;
use Yiisoft\Validator\Rule\Trait\TranslatedAttributesHandlerTrait;
use Yiisoft\Validator\RuleHandlerInterface;
use Yiisoft\Validator\EmptyCondition\WhenEmpty;
use Yiisoft\Validator\ValidationContext;
Expand All @@ -21,6 +22,8 @@
*/
final class OneOfHandler implements RuleHandlerInterface
{
use TranslatedAttributesHandlerTrait;

public function validate(mixed $value, object $rule, ValidationContext $context): Result
{
if (!$rule instanceof OneOf) {
Expand All @@ -46,17 +49,17 @@ public function validate(mixed $value, object $rule, ValidationContext $context)
}

if ($filledCount > 1) {
return $this->getGenericErrorResult($rule->getMessage(), $context);
return $this->getGenericErrorResult($rule, $context);
}
}

return $filledCount === 1 ? $result : $this->getGenericErrorResult($rule->getMessage(), $context);
return $filledCount === 1 ? $result : $this->getGenericErrorResult($rule, $context);
}

private function getGenericErrorResult(string $message, ValidationContext $context): Result
private function getGenericErrorResult(OneOf $rule, ValidationContext $context): Result
{
return (new Result())->addError($message, [
'attribute' => $context->getTranslatedAttribute(),
return (new Result())->addError($rule->getMessage(), [
'attributes' => $this->getFormattedAttributesString($rule->getAttributes(), $context),
]);
}
}
38 changes: 38 additions & 0 deletions src/Rule/Trait/TranslatedAttributesHandlerTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Validator\Rule\Trait;

use Yiisoft\Validator\ValidationContext;

trait TranslatedAttributesHandlerTrait
{
/**
* @param string[] $attributes
*/
private function getFormattedAttributesString(array $attributes, ValidationContext $context): string
{
return '"' . implode('", "', $this->getTranslatedAttributes($attributes, $context)) . '"';
}

/**
* @param string[] $attributes
*
* @return string[]
*/
private function getTranslatedAttributes(array $attributes, ValidationContext $context): array
{
$initialAttribute = $context->getAttribute();
$translatedAttributes = [];
foreach ($attributes as $attribute) {
$translatedAttributes[] = $context->setAttribute($attribute)->getTranslatedAttribute();
}

/** @var string[] $translatedAttributes */

$context->setAttribute($initialAttribute);

return $translatedAttributes;
}
}
29 changes: 16 additions & 13 deletions tests/Rule/AtLeastTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ public function dataOptions(): array
'parameters' => [],
],
'message' => [
'template' => 'The data must have at least "{min}" filled attributes.',
'template' => 'At least {min, number} {min, plural, one{attribute} other{attributes}} from ' .
'this list must be filled: {attributes}.',
'parameters' => ['min' => 1],
],
'skipOnEmpty' => false,
Expand All @@ -63,7 +64,8 @@ public function dataOptions(): array
'parameters' => [],
],
'message' => [
'template' => 'The data must have at least "{min}" filled attributes.',
'template' => 'At least {min, number} {min, plural, one{attribute} other{attributes}} from ' .
'this list must be filled: {attributes}.',
'parameters' => ['min' => 2],
],
'skipOnEmpty' => false,
Expand All @@ -83,7 +85,8 @@ public function dataOptions(): array
'parameters' => [],
],
'message' => [
'template' => 'The data must have at least "{min}" filled attributes.',
'template' => 'At least {min, number} {min, plural, one{attribute} other{attributes}} from ' .
'this list must be filled: {attributes}.',
'parameters' => ['min' => 1],
],
'skipOnEmpty' => null,
Expand Down Expand Up @@ -208,22 +211,22 @@ public function dataValidationFailed(): array
'object' => [
$class,
[new AtLeast(['attr2'])],
['' => ['The data must have at least "1" filled attributes.']],
['' => ['At least 1 attribute from this list must be filled: "attr2".']],
],
'object, custom min' => [
$class,
[new AtLeast(['attr1', 'attr2'], min: 2)],
['' => ['The data must have at least "2" filled attributes.']],
['' => ['At least 2 attributes from this list must be filled: "attr1", "attr2".']],
],
'array' => [
$array,
[new AtLeast(['attr2'])],
['' => ['The data must have at least "1" filled attributes.']],
['' => ['At least 1 attribute from this list must be filled: "attr2".']],
],
'array, custom min' => [
$array,
[new AtLeast(['attr2'], min: 2)],
['' => ['The data must have at least "2" filled attributes.']],
['' => ['At least 2 attributes from this list must be filled: "attr2".']],
],
'custom message' => [
$class,
Expand All @@ -232,18 +235,18 @@ public function dataValidationFailed(): array
],
'custom message with parameters' => [
$class,
[new AtLeast(['attr1', 'attr2'], min: 2, message: 'Attribute - {attribute}, min - {min}.')],
['' => ['Attribute - , min - 2.']],
[new AtLeast(['attr1', 'attr2'], min: 2, message: 'Attributes - {attributes}, min - {min}.')],
['' => ['Attributes - "attr1", "attr2", min - 2.']],
],
'custom message with parameters, attribute set' => [
['data' => $class],
['data' => new AtLeast(['attr1', 'attr2'], min: 2, message: 'Attribute - {attribute}, min - {min}.')],
['data' => ['Attribute - data, min - 2.']],
['data' => new AtLeast(['attr1', 'attr2'], min: 2, message: 'Attributes - {attributes}, min - {min}.')],
['data' => ['Attributes - "attr1", "attr2", min - 2.']],
],
'class attribute' => [
'class attribute, tranlation' => [
new AtLeastDto(),
null,
['' => ['The data must have at least "1" filled attributes.']],
['' => ['At least 1 attribute from this list must be filled: "A", "B", "C".']],
],
];
}
Expand Down
22 changes: 11 additions & 11 deletions tests/Rule/OneOfTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public function dataOptions(): array
'parameters' => [],
],
'message' => [
'template' => 'The data must have at least 1 filled attribute.',
'template' => 'Exactly 1 attribute from this list must be filled: {attributes}.',
'parameters' => [],
],
'skipOnEmpty' => false,
Expand All @@ -61,7 +61,7 @@ public function dataOptions(): array
'parameters' => [],
],
'message' => [
'template' => 'The data must have at least 1 filled attribute.',
'template' => 'Exactly 1 attribute from this list must be filled: {attributes}.',
'parameters' => [],
],
'skipOnEmpty' => null,
Expand Down Expand Up @@ -139,7 +139,7 @@ public function __construct()
['obj' => ['attr1' => null, 'attr2' => 1]],
['obj' => new OneOf(['attr1', 'attr2'])],
],
'class attribute' => [
'class attribute, translation' => [
new OneOfDto(1),
],
];
Expand Down Expand Up @@ -182,17 +182,17 @@ public function dataValidationFailed(): array
'object' => [
$object,
[new OneOf(['attr1', 'attr2'])],
['' => ['The data must have at least 1 filled attribute.']],
['' => ['Exactly 1 attribute from this list must be filled: "attr1", "attr2".']],
],
'array' => [
$array,
[new OneOf(['attr1', 'attr2'])],
['' => ['The data must have at least 1 filled attribute.']],
['' => ['Exactly 1 attribute from this list must be filled: "attr1", "attr2".']],
],
'more than 1 attribute is filled' => [
['attr1' => 1, 'attr2' => 2],
[new OneOf(['attr1', 'attr2'])],
['' => ['The data must have at least 1 filled attribute.']],
['' => ['Exactly 1 attribute from this list must be filled: "attr1", "attr2".']],
],
'custom message' => [
$object,
Expand All @@ -201,18 +201,18 @@ public function dataValidationFailed(): array
],
'custom message with parameters' => [
$object,
[new OneOf(['attr1', 'attr2'], message: 'Attribute - {attribute}.')],
['' => ['Attribute - .']],
[new OneOf(['attr1', 'attr2'], message: 'Attributes - {attributes}.')],
['' => ['Attributes - "attr1", "attr2".']],
],
'custom message with parameters, attribute set' => [
['data' => $object],
['data' => new OneOf(['attr1', 'attr2'], message: 'Attribute - {attribute}.')],
['data' => ['Attribute - data.']],
['data' => new OneOf(['attr1', 'attr2'], message: 'Attributes - {attributes}.')],
['data' => ['Attributes - "attr1", "attr2".']],
],
'class attribute' => [
new OneOfDto(),
null,
['' => ['The data must have at least 1 filled attribute.']],
['' => ['Exactly 1 attribute from this list must be filled: "A", "B", "C".']],
],
];
}
Expand Down
19 changes: 18 additions & 1 deletion tests/Support/Data/AtLeastDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,32 @@

namespace Yiisoft\Validator\Tests\Support\Data;

use Yiisoft\Validator\AttributeTranslator\ArrayAttributeTranslator;
use Yiisoft\Validator\AttributeTranslatorInterface;
use Yiisoft\Validator\AttributeTranslatorProviderInterface;
use Yiisoft\Validator\Rule\AtLeast;

#[AtLeast(['a', 'b', 'c'])]
final class AtLeastDto
final class AtLeastDto implements AttributeTranslatorProviderInterface
{
public function __construct(
public ?int $a = null,
public ?int $b = null,
public ?int $c = null,
) {
}

public function getAttributeLabels(): array
{
return [
'a' => 'A',
'b' => 'B',
'c' => 'C',
];
}

public function getAttributeTranslator(): ?AttributeTranslatorInterface
{
return new ArrayAttributeTranslator($this->getAttributeLabels());
}
}
Loading