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

Sync with 1.x branch #712

Closed
wants to merge 7 commits into from
Closed
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
1 change: 0 additions & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@
| Is bugfix? | ✔️/❌
| New feature? | ✔️/❌
| Breaks BC? | ✔️/❌
| Fixed issues | <!-- comma-separated list of tickets # fixed by the PR, if any -->
2 changes: 1 addition & 1 deletion .github/workflows/bc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ jobs:
os: >-
['ubuntu-latest']
php: >-
['8.1']
['8.0']
2 changes: 1 addition & 1 deletion .github/workflows/bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ jobs:
os: >-
['ubuntu-latest', 'windows-latest']
php: >-
['8.1']
['8.0', '8.1']
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
os: >-
['ubuntu-latest', 'windows-latest']
php: >-
['8.1', '8.2', '8.3']
['8.0', '8.1', '8.2', '8.3']
phpunit-without-intl:
uses: yiisoft/actions/.github/workflows/phpunit.yml@master
with:
Expand All @@ -41,4 +41,4 @@ jobs:
os: >-
['ubuntu-latest', 'windows-latest']
php: >-
['8.1', '8.2', '8.3']
['8.0', '8.1', '8.2', '8.3']
2 changes: 1 addition & 1 deletion .github/workflows/composer-require-checker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ jobs:
os: >-
['ubuntu-latest']
php: >-
['8.1', '8.2', '8.3']
['8.0', '8.1', '8.2', '8.3']
config: ./composer-require-checker.json
8 changes: 8 additions & 0 deletions .github/workflows/static.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,11 @@ jobs:
['ubuntu-latest']
php: >-
['8.1', '8.2', '8.3']
psalm80:
uses: yiisoft/actions/.github/workflows/psalm.yml@master
with:
psalm-config: psalm80.xml
os: >-
['ubuntu-latest']
php: >-
['8.0']
2 changes: 0 additions & 2 deletions src/EmptyCondition/NeverEmpty.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@
final class NeverEmpty
{
/**
* @param mixed $value The validated value.
* @param bool $isAttributeMissing A flag defining whether the attribute is missing (not used / not passed at all).
*
* @return bool Whether the validated value is considered empty.
*/
public function __invoke(mixed $value, bool $isAttributeMissing = false): bool
Expand Down
2 changes: 0 additions & 2 deletions src/EmptyCondition/WhenEmpty.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ public function __construct(
}

/**
* @param mixed $value The validated value.
* @param bool $isAttributeMissing A flag defining whether the attribute is missing (not used / not passed at all).
*
* @return bool Whether the validated value is considered empty.
*/
public function __invoke(mixed $value, bool $isAttributeMissing = false): bool
Expand Down
2 changes: 0 additions & 2 deletions src/EmptyCondition/WhenMissing.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
final class WhenMissing
{
/**
* @param mixed $value The validated value.
* @param bool $isAttributeMissing A flag defining whether the attribute is missing (not used / not passed at all).
*
* @return bool Whether the validated value is considered empty.
*/
public function __invoke(mixed $value, bool $isAttributeMissing = false): bool
Expand Down
2 changes: 0 additions & 2 deletions src/EmptyCondition/WhenNull.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
final class WhenNull
{
/**
* @param mixed $value The validated value.
* @param bool $isAttributeMissing A flag defining whether the attribute is missing (not used / not passed at all).
*
* @return bool Whether the validated value is considered empty.
*/
public function __invoke(mixed $value, bool $isAttributeMissing = false): bool
Expand Down
2 changes: 0 additions & 2 deletions src/Helper/DataSetNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ final class DataSetNormalizer
* In order to prevent mapping objects and arrays to corresponding data sets, wrap them with
* {@see SingleValueDataSet} explicitly or use a custom data set ({@see DataSetInterface}).
*
* @param mixed $data Raw validated data of any type.
*
* @return DataSetInterface Data set instance.
*/
public static function normalize(mixed $data): DataSetInterface
Expand Down
1 change: 0 additions & 1 deletion src/Helper/ObjectParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,6 @@ private function getCacheItem(
* Updates cache item contents by its name.
*
* @param string $name Cache item name. Can be on of: `rules`, `reflectionProperties`, `reflectionSource`.
* @param mixed $value A new value.
*/
private function setCacheItem(
#[ExpectedValues(['rules', 'reflectionProperties', 'reflectionSource', 'labels'])]
Expand Down
3 changes: 0 additions & 3 deletions src/Helper/RulesNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,7 @@ public static function normalizeList(iterable|callable|RuleInterface $rules): it
*
* @psalm-param RawRules|null $rules
*
* @param mixed $data Validated data.
*
* @throws ReflectionException When parsing rules from PHP attributes failed.
*
* @return iterable An iterable with rules for further individual rules' normalization.
*/
private static function prepareRulesIterable(
Expand Down
2 changes: 0 additions & 2 deletions src/Helper/RulesNormalizerIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,12 @@ public function getIterator(): Traversable
* - For any other type verifies that it's a valid rule instance.
* - If default "skip on empty" condition is set, applies it if possible.
*
* @param mixed $rule A raw rule.
* @param callable|null $defaultSkipOnEmptyCondition A "skip on empty" condition ({@see SkipOnEmptyInterface}) to
* apply as default, already normalized. `null` means there is no condition to apply.
*
* @throws InvalidArgumentException When rule is neither a callable nor a {@see RuleInterface} implementation.
*
* @return RuleInterface Ready to use rule instance.
*
* @psalm-param SkipOnEmptyCallable|null $defaultSkipOnEmptyCondition
*/
private static function normalizeRule(mixed $rule, ?callable $defaultSkipOnEmptyCondition): RuleInterface
Expand Down
2 changes: 0 additions & 2 deletions src/Rule/AbstractCompare.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@
/**
* A default for {@see $incorrectInputMessage}.
*/
protected const DEFAULT_INCORRECT_INPUT_MESSAGE = 'The allowed types are integer, float, string, boolean, null ' .

Check failure on line 50 in src/Rule/AbstractCompare.php

View workflow job for this annotation

GitHub Actions / psalm / PHP 8.3-ubuntu-latest

MissingClassConstType

src/Rule/AbstractCompare.php:50:21: MissingClassConstType: Class constant "Yiisoft\Validator\Rule\AbstractCompare::DEFAULT_INCORRECT_INPUT_MESSAGE" should have a declared type. (see https://psalm.dev/359)
'and object implementing \Stringable interface or \DateTimeInterface.';
/**
* A default for {@see $incorrectDataSetTypeMessage}.
*/
protected const DEFAULT_INCORRECT_DATA_SET_TYPE_MESSAGE = 'The attribute value returned from a custom data set ' .

Check failure on line 55 in src/Rule/AbstractCompare.php

View workflow job for this annotation

GitHub Actions / psalm / PHP 8.3-ubuntu-latest

MissingClassConstType

src/Rule/AbstractCompare.php:55:21: MissingClassConstType: Class constant "Yiisoft\Validator\Rule\AbstractCompare::DEFAULT_INCORRECT_DATA_SET_TYPE_MESSAGE" should have a declared type. (see https://psalm.dev/359)
'must have one of the following types: integer, float, string, boolean, null or an object implementing ' .
'\Stringable interface or \DateTimeInterface.';
/**
Expand All @@ -60,11 +60,11 @@
*
* @see CompareType
*/
private const VALID_TYPES = [CompareType::ORIGINAL, CompareType::STRING, CompareType::NUMBER];

Check failure on line 63 in src/Rule/AbstractCompare.php

View workflow job for this annotation

GitHub Actions / psalm / PHP 8.3-ubuntu-latest

MissingClassConstType

src/Rule/AbstractCompare.php:63:19: MissingClassConstType: Class constant "Yiisoft\Validator\Rule\AbstractCompare::VALID_TYPES" should have a declared type. (see https://psalm.dev/359)
/**
* Map of valid operators. It's used instead of a list for better performance.
*/
private const VALID_OPERATORS_MAP = [

Check failure on line 67 in src/Rule/AbstractCompare.php

View workflow job for this annotation

GitHub Actions / psalm / PHP 8.3-ubuntu-latest

MissingClassConstType

src/Rule/AbstractCompare.php:67:19: MissingClassConstType: Class constant "Yiisoft\Validator\Rule\AbstractCompare::VALID_OPERATORS_MAP" should have a declared type. (see https://psalm.dev/359)
'==' => 1,
'===' => 1,
'!=' => 1,
Expand All @@ -76,8 +76,6 @@
];

/**
* @param mixed $targetValue The value to be compared with. When both this property and {@see $targetAttribute} are
* set, this property takes precedence.
* @param string|null $targetAttribute The name of the attribute to be compared with. When both this property and
* {@see $targetValue} are set, the {@see $targetValue} takes precedence.
* @param string $incorrectInputMessage A message used when the input is incorrect.
Expand Down
164 changes: 164 additions & 0 deletions src/Rule/AnyRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Validator\Rule;

use Attribute;
use Closure;
use JetBrains\PhpStorm\ArrayShape;
use Yiisoft\Validator\AfterInitAttributeEventInterface;
use Yiisoft\Validator\Helper\RulesNormalizer;
use Yiisoft\Validator\Rule\Trait\SkipOnEmptyTrait;
use Yiisoft\Validator\Rule\Trait\SkipOnErrorTrait;
use Yiisoft\Validator\Rule\Trait\WhenTrait;
use Yiisoft\Validator\Helper\RulesDumper;
use Yiisoft\Validator\RuleWithOptionsInterface;
use Yiisoft\Validator\SkipOnEmptyInterface;
use Yiisoft\Validator\SkipOnErrorInterface;
use Yiisoft\Validator\ValidatorInterface;
use Yiisoft\Validator\WhenInterface;

/**
* Applies to a set of rules, runs validation for each one of them in the order they are defined and stops at the rule
* where validation passed. The opposite of {@see StopOnError}.
*
* An example of usage:
*
* ```php
* $rule = new AnyRule([
* new IntegerType(), // Let's say the validation passed here.
* new FloatType(), // Then this rule will be skipped.
* ]);
* ```
*
* When using with other rules, conditional validation options, such as {@see AnyRule::$skipOnError} will be applied
* to the whole group of {@see AnyRule::$rules}.
*
* @see StopOnErrorHandler Corresponding handler performing the actual validation.
*
* @psalm-import-type SkipOnEmptyValue from SkipOnEmptyInterface
* @psalm-import-type WhenType from WhenInterface
* @psalm-import-type NormalizedRulesList from RulesNormalizer
* @psalm-import-type RawRulesList from ValidatorInterface
*/
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
final class AnyRule implements
RuleWithOptionsInterface,

Check failure on line 47 in src/Rule/AnyRule.php

View workflow job for this annotation

GitHub Actions / psalm / PHP 8.1-ubuntu-latest

UndefinedClass

src/Rule/AnyRule.php:47:5: UndefinedClass: Class, interface or enum named Yiisoft\Validator\RuleWithOptionsInterface does not exist (see https://psalm.dev/019)

Check failure on line 47 in src/Rule/AnyRule.php

View workflow job for this annotation

GitHub Actions / psalm / PHP 8.2-ubuntu-latest

UndefinedClass

src/Rule/AnyRule.php:47:5: UndefinedClass: Class, interface or enum named Yiisoft\Validator\RuleWithOptionsInterface does not exist (see https://psalm.dev/019)
SkipOnEmptyInterface,
SkipOnErrorInterface,
WhenInterface,
AfterInitAttributeEventInterface
{
use SkipOnEmptyTrait;
use SkipOnErrorTrait;
use WhenTrait;

/**
* @var iterable A set of normalized rules that needs to be run.
*
* @psalm-var NormalizedRulesList
*/
private iterable $rules = [];

/**
* @param string $message Error message used when validation fails because none of the inner {@see $rules} has
* passed the validation.
*
* @param iterable $rules A set of rules for running the validation. They will be normalized during initialization
* using {@see RulesNormalizer}.
*
* @psalm-param RawRulesList $rules
*
* @param bool|callable|null $skipOnEmpty Whether to skip this `Any` rule with all defined {@see $rules} if the
* validated value is empty / not passed. See {@see SkipOnEmptyInterface}.
* @param bool $skipOnError Whether to skip this `Any` rule with all defined {@see $rules} if any of the previous
* rules gave an error. See {@see SkipOnErrorInterface}.
* @param Closure|null $when A callable to define a condition for applying this `Any` rule with all defined
* {@see $rules}. See {@see WhenInterface}.
*
* @psalm-param SkipOnEmptyValue $skipOnEmpty
* @psalm-param WhenType $when
*/
public function __construct(
iterable $rules,
private string $message = 'At least one of the inner rules must pass the validation.',
private mixed $skipOnEmpty = null,
private bool $skipOnError = false,
private Closure|null $when = null,
) {
$this->rules = RulesNormalizer::normalizeList($rules);
}

public function getName(): string
{
return 'any';
}

/**
* Gets a set of rules for running the validation.
*
* @return iterable A set of rules.
*
* @psalm-return NormalizedRulesList
*/
public function getRules(): iterable
{
return $this->rules;
}

/**
* Gets error message used when validation fails because none of the inner {@see $rules} has passed the validation.
*
* @return string Error message / template.
*
* @see $message
*/
public function getMessage(): string
{
return $this->message;
}

#[ArrayShape([
'message' => 'array',
'skipOnEmpty' => 'bool',
'skipOnError' => 'bool',
'rules' => 'array|null',
])]
public function getOptions(): array
{
return [
'message' => [
'template' => $this->message,
'parameters' => [],
],
'skipOnEmpty' => $this->getSkipOnEmptyOption(),
'skipOnError' => $this->skipOnError,
'rules' => $this->dumpRulesAsArray(),
];
}

public function getHandler(): string
{
return AnyRuleHandler::class;
}

public function afterInitAttribute(object $object): void
{
foreach ($this->rules as $rule) {
if ($rule instanceof AfterInitAttributeEventInterface) {
$rule->afterInitAttribute($object);
}
}
}

/**
* Dumps defined {@see $rules} to array.
*
* @return array The array of rules with their options.
*/
private function dumpRulesAsArray(): array
{
return RulesDumper::asArray($this->getRules());
}
}
33 changes: 33 additions & 0 deletions src/Rule/AnyRuleHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Validator\Rule;

use Yiisoft\Validator\Exception\UnexpectedRuleException;
use Yiisoft\Validator\Result;
use Yiisoft\Validator\RuleHandlerInterface;
use Yiisoft\Validator\ValidationContext;

/**
* A handler for {@see AnyRule} rule. Validates a set of rules consecutively and stops at the rule where validation
* has passed.
*/
final class AnyRuleHandler implements RuleHandlerInterface
{
public function validate(mixed $value, object $rule, ValidationContext $context): Result

Check failure on line 18 in src/Rule/AnyRuleHandler.php

View workflow job for this annotation

GitHub Actions / psalm / PHP 8.1-ubuntu-latest

MixedInferredReturnType

src/Rule/AnyRuleHandler.php:18:87: MixedInferredReturnType: Could not verify return type 'Yiisoft\Validator\Result' for Yiisoft\Validator\Rule\AnyRuleHandler::validate (see https://psalm.dev/047)

Check failure on line 18 in src/Rule/AnyRuleHandler.php

View workflow job for this annotation

GitHub Actions / psalm / PHP 8.2-ubuntu-latest

MixedInferredReturnType

src/Rule/AnyRuleHandler.php:18:87: MixedInferredReturnType: Could not verify return type 'Yiisoft\Validator\Result' for Yiisoft\Validator\Rule\AnyRuleHandler::validate (see https://psalm.dev/047)
{
if (!$rule instanceof AnyRule) {

Check failure on line 20 in src/Rule/AnyRuleHandler.php

View workflow job for this annotation

GitHub Actions / psalm / PHP 8.1-ubuntu-latest

MissingDependency

src/Rule/AnyRuleHandler.php:20:31: MissingDependency: Yiisoft\Validator\Rule\AnyRule depends on class or interface yiisoft\validator\rulewithoptionsinterface that does not exist (see https://psalm.dev/157)

Check failure on line 20 in src/Rule/AnyRuleHandler.php

View workflow job for this annotation

GitHub Actions / psalm / PHP 8.2-ubuntu-latest

MissingDependency

src/Rule/AnyRuleHandler.php:20:31: MissingDependency: Yiisoft\Validator\Rule\AnyRule depends on class or interface yiisoft\validator\rulewithoptionsinterface that does not exist (see https://psalm.dev/157)
throw new UnexpectedRuleException(AnyRule::class, $rule);
}

foreach ($rule->getRules() as $relatedRule) {
$result = $context->validate($value, $relatedRule);
if ($result->isValid()) {
return $result;
}
}

return (new Result())->addError($rule->getMessage(), []);
}
}
Loading
Loading