Skip to content

Commit

Permalink
Merge pull request #597 from yiisoft/split-debug
Browse files Browse the repository at this point in the history
Split debug
  • Loading branch information
xepozz committed Apr 29, 2023
2 parents 97e94f6 + be7e2f4 commit 81eace1
Show file tree
Hide file tree
Showing 55 changed files with 335 additions and 4 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
@@ -1,8 +1,8 @@
# Yii Validator Change Log

## 1.1.1 under development
## 1.2.0 under development

- no changes in this release.
- Enh #66: Add debug collector for yiisoft/yii-debug (@xepozz)

## 1.1.0 April 06, 2023

Expand Down
5 changes: 4 additions & 1 deletion composer-require-checker.json
@@ -1,5 +1,8 @@
{
"symbol-whitelist": [],
"symbol-whitelist": [
"Yiisoft\\Yii\\Debug\\Collector\\CollectorTrait",
"Yiisoft\\Yii\\Debug\\Collector\\SummaryCollectorInterface"
],
"php-core-extensions": [
"Core",
"date",
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Expand Up @@ -47,7 +47,8 @@
"vimeo/psalm": "^4.30|^5.0",
"yiisoft/di": "^1.2",
"yiisoft/test-support": "^3.0",
"yiisoft/translator-message-php": "^1.1"
"yiisoft/translator-message-php": "^1.1",
"yiisoft/yii-debug": "dev-master"
},
"suggest": {
"ext-intl": "Allows using IDN validation for emails",
Expand Down
12 changes: 12 additions & 0 deletions config/params.php
Expand Up @@ -2,10 +2,22 @@

declare(strict_types=1);

use Yiisoft\Validator\Debug\ValidatorCollector;
use Yiisoft\Validator\Debug\ValidatorInterfaceProxy;
use Yiisoft\Validator\Validator;
use Yiisoft\Validator\ValidatorInterface;

return [
'yiisoft/validator' => [
'translation.category' => Validator::DEFAULT_TRANSLATION_CATEGORY,
],

'yiisoft/yii-debug' => [
'collectors' => [
ValidatorCollector::class,
],
'trackedServices' => [
ValidatorInterface::class => [ValidatorInterfaceProxy::class, ValidatorCollector::class],
],
],
];
1 change: 1 addition & 0 deletions src/AttributeTranslator/ArrayAttributeTranslator.php
Expand Up @@ -14,6 +14,7 @@ final class ArrayAttributeTranslator implements AttributeTranslatorInterface
/**
* @param array $translations Translations array where each key is an attribute name and the corresponding value is
* a translation.
*
* @psalm-param array<string,string> $translations
*/
public function __construct(
Expand Down
1 change: 1 addition & 0 deletions src/DataSet/ObjectDataSet.php
Expand Up @@ -198,6 +198,7 @@ public function __construct(
* so, when used together, the latter ones will be ignored without exception.
*
* @return iterable The resulting rules is an array with the following structure:
*
* @psalm-return RawRulesMap
*
* ```php
Expand Down
61 changes: 61 additions & 0 deletions src/Debug/ValidatorCollector.php
@@ -0,0 +1,61 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Validator\Debug;

use Traversable;
use Yiisoft\Validator\Result;
use Yiisoft\Yii\Debug\Collector\CollectorTrait;
use Yiisoft\Yii\Debug\Collector\SummaryCollectorInterface;

final class ValidatorCollector implements SummaryCollectorInterface
{
use CollectorTrait;

private array $validations = [];

public function getCollected(): array
{
return $this->validations;
}

public function collect(mixed $value, Result $result, callable|iterable|object|string|null $rules = null): void
{
if (!$this->isActive()) {
return;
}

if ($rules instanceof Traversable) {
$rules = iterator_to_array($rules);
}


$this->validations[] = [
'value' => $value,
'rules' => $rules,
'result' => $result->isValid(),
'errors' => $result->getErrors(),
];
}

public function getSummary(): array
{
$count = count($this->validations);
$countValid = count(array_filter($this->validations, fn (array $data): bool => (bool)$data['result']));
$countInvalid = $count - $countValid;

return [
'validator' => [
'total' => $count,
'valid' => $countValid,
'invalid' => $countInvalid,
],
];
}

private function reset(): void
{
$this->validations = [];
}
}
39 changes: 39 additions & 0 deletions src/Debug/ValidatorInterfaceProxy.php
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Validator\Debug;

use Yiisoft\Validator\Result;
use Yiisoft\Validator\RulesProviderInterface;
use Yiisoft\Validator\ValidationContext;
use Yiisoft\Validator\ValidatorInterface;

final class ValidatorInterfaceProxy implements ValidatorInterface
{
public function __construct(
private ValidatorInterface $validator,
private ValidatorCollector $collector,
) {
}

public function validate(
mixed $data,
callable|iterable|object|string|null $rules = null,
?ValidationContext $context = null
): Result {
$result = $this->validator->validate($data, $rules, $context);

if ($rules === null && $data instanceof RulesProviderInterface) {
$rules = (array) $data->getRules();
}

$this->collector->collect(
$data,
$result,
$rules,
);

return $result;
}
}
4 changes: 4 additions & 0 deletions src/Error.php
Expand Up @@ -34,6 +34,7 @@ final class Error
* names and values. Note that only scalar or `null` values are allowed.
*
* @link https://www.php.net/manual/ru/function.is-scalar.php
*
* @psalm-param array<string, scalar|null> $parameters
*
* @param array $valuePath A sequence of keys determining where a value caused the validation error is located
Expand All @@ -57,6 +58,7 @@ final class Error
* ```
*
* A value without nested structure won't have a path at all (it will be an empty array).
*
* @psalm-param list<int|string> $valuePath
*/
public function __construct(
Expand All @@ -80,6 +82,7 @@ public function getMessage(): string
* A getter for {@see $parameters} property. Returns parameters used for {@see $message} translation.
*
* @return array A mapping between parameter names and values.
*
* @psalm-return array<string, scalar|null>
*/
public function getParameters(): array
Expand All @@ -95,6 +98,7 @@ public function getParameters(): array
* (`'*``, used as a {@see Each} rule shortcut) char with a backslash char (`'\'`).
*
* @return array A list of keys for nested structures or an empty array otherwise.
*
* @psalm-return list<int|string>
*/
public function getValuePath(bool $escape = false): array
Expand Down
4 changes: 4 additions & 0 deletions src/Helper/ObjectParser.php
Expand Up @@ -126,6 +126,7 @@ final class ObjectParser
* - The second nesting level is a mapping between cache item names and their contents.
*
* Different properties' combinations of the same object are cached separately.
*
* @psalm-var array<string, array<string, mixed>>
*/
#[ArrayShape([
Expand All @@ -149,13 +150,15 @@ public function __construct(
/**
* @var object|string A source for parsing rules and data. Can be either a class name string or an
* instance.
*
* @psalm-var class-string|object
*/
private string|object $source,
/**
* @var int Visibility levels the parsed properties must have. For example: public and protected only, this
* means that the rest (private ones) will be skipped. Defaults to all visibility levels (public, protected and
* private).
*
* @psalm-var int-mask-of<ReflectionProperty::IS_*>
*/
private int $propertyVisibility = ReflectionProperty::IS_PRIVATE |
Expand Down Expand Up @@ -376,6 +379,7 @@ private function prepareRules(array $source): array
} else {
/**
* @psalm-var list<RulesCacheItem> $data
*
* @psalm-suppress UndefinedInterfaceMethod
*/
foreach ($data as $rule) {
Expand Down
2 changes: 2 additions & 0 deletions src/Helper/PropagateOptionsHelper.php
Expand Up @@ -27,10 +27,12 @@ final class PropagateOptionsHelper
* @param RuleInterface $parentRule A parent rule which options' values need to be propagated.
* @param iterable $childRules Direct child rules for this particular parent rule which options'
* values must be changed to be the same as in parent rule.
*
* @psalm-param iterable<RuleInterface> $childRules
*
* @return array A list of child rules of the same nesting level with changed options' values or
* unchanged if none of the required interfaces were implemented. The order is preserved.
*
* @psalm-return list<RuleInterface>
*/
public static function propagate(RuleInterface $parentRule, iterable $childRules): array
Expand Down
5 changes: 5 additions & 0 deletions src/Helper/RulesNormalizer.php
Expand Up @@ -23,6 +23,7 @@
* Note that when using {@see Validator}, normalization is performed automatically.
*
* @psalm-import-type RawRules from ValidatorInterface
*
* @psalm-type NormalizedRulesList = iterable<int, RuleInterface>
* @psalm-type NormalizedRulesMap = array<int|string, NormalizedRulesList>
*/
Expand Down Expand Up @@ -56,6 +57,7 @@ final class RulesNormalizer
* - Object providing rules via separate method.
* - Single rule instance / callable.
* - Name of a class providing rules via PHP attributes.
*
* @psalm-param RawRules|null $rules
*
* @param mixed|null $data Validated data,
Expand All @@ -67,6 +69,7 @@ final class RulesNormalizer
* @throws ReflectionException When parsing rules from PHP attributes failed.
*
* @return array Rules normalized as a whole and individually, ready to use for validation.
*
* @psalm-return NormalizedRulesMap
*/
public static function normalize(
Expand Down Expand Up @@ -113,6 +116,7 @@ public static function normalize(
* implementation.
*
* @return iterable An iterable with every rule checked and normalized.
*
* @psalm-return NormalizedRulesList
*/
public static function normalizeList(iterable|callable|RuleInterface $rules): iterable
Expand Down Expand Up @@ -141,6 +145,7 @@ public static function normalizeList(iterable|callable|RuleInterface $rules): it
* - Object providing rules via separate method.
* - Single rule instance / callable.
* - Name of a class providing rules via PHP attributes.
*
* @psalm-param RawRules|null $rules
*
* @param mixed $data Validated data.
Expand Down
5 changes: 5 additions & 0 deletions src/Result.php
Expand Up @@ -75,6 +75,7 @@ public function getErrorMessages(): array
* @param string $separator Attribute path separator. Dot is used by default.
*
* @return array Arrays of error messages indexed by attribute path.
*
* @psalm-return array<string, non-empty-list<string>>
*/
public function getErrorMessagesIndexedByPath(string $separator = '.'): array
Expand All @@ -94,6 +95,7 @@ public function getErrorMessagesIndexedByPath(string $separator = '.'): array
* @throws InvalidArgumentException If top level attribute has a non-string type.
*
* @return array Arrays of error messages indexed by attribute name.
*
* @psalm-return array<string, non-empty-list<string>>
*/
public function getErrorMessagesIndexedByAttribute(): array
Expand Down Expand Up @@ -158,6 +160,7 @@ public function getAttributeErrorMessages(string $attribute): array
* @param string $separator Attribute path separator. Dot is used by default.
*
* @return array Arrays of error messages for the attribute specified indexed by attribute path.
*
* @psalm-return array<string, non-empty-list<string>>
*/
public function getAttributeErrorMessagesIndexedByPath(string $attribute, string $separator = '.'): array
Expand Down Expand Up @@ -192,10 +195,12 @@ public function getCommonErrorMessages(): array
* @param string $message The raw validation error message. See {@see Error::$message}.
* @param array $parameters Parameters used for {@see $message} translation - a mapping between parameter
* names and values. See {@see Error::$parameters}.
*
* @psalm-param array<string,scalar|null> $parameters
*
* @param array $valuePath A sequence of keys determining where a value caused the validation
* error is located within a nested structure. See {@see Error::$valuePath}.
*
* @psalm-param list<int|string> $valuePath
*
* @return $this Same instance of result.
Expand Down
3 changes: 3 additions & 0 deletions src/Rule/AbstractCompare.php
Expand Up @@ -119,6 +119,7 @@ abstract class AbstractCompare implements
* {@see CompareType::ORIGINAL} allows any values. All PHP comparison rules apply here, see comparison operators -
* {@see https://www.php.net/manual/en/language.operators.comparison.php} and PHP type comparison tables -
* {@see https://www.php.net/manual/en/types.comparisons.php} sections in official PHP documentation.
*
* @psalm-param CompareType::ORIGINAL | CompareType::STRING | CompareType::NUMBER $type
*
* @param string $operator The operator for comparison. The following operators are supported:
Expand All @@ -137,6 +138,7 @@ abstract class AbstractCompare implements
* See {@see SkipOnErrorInterface}.
* @param Closure|null $when A callable to define a condition for applying the rule.
* See {@see WhenInterface}.
*
* @psalm-param WhenType $when
*/
public function __construct(
Expand Down Expand Up @@ -196,6 +198,7 @@ public function getTargetAttribute(): string|null
*
* @return string The type of the values being compared. Either {@see CompareType::STRING}
* or {@see CompareType::NUMBER}.
*
* @psalm-return CompareType::ORIGINAL | CompareType::STRING | CompareType::NUMBER $type
*
* @see $type
Expand Down
1 change: 1 addition & 0 deletions src/Rule/AbstractNumber.php
Expand Up @@ -85,6 +85,7 @@ abstract class AbstractNumber implements
* @param bool $skipOnError Whether to skip this rule if any of the previous rules gave an error. See
* {@see SkipOnErrorInterface}.
* @param Closure|null $when A callable to define a condition for applying the rule. See {@see WhenInterface}.
*
* @psalm-param WhenType $when
*/
public function __construct(
Expand Down
1 change: 1 addition & 0 deletions src/Rule/AtLeast.php
Expand Up @@ -51,6 +51,7 @@ final class AtLeast implements RuleWithOptionsInterface, SkipOnErrorInterface, W
* See {@see SkipOnErrorInterface}.
* @param Closure|null $when A callable to define a condition for applying the rule.
* See {@see WhenInterface}.
*
* @psalm-param WhenType $when
*/
public function __construct(
Expand Down
1 change: 1 addition & 0 deletions src/Rule/BooleanValue.php
Expand Up @@ -74,6 +74,7 @@ final class BooleanValue implements RuleWithOptionsInterface, SkipOnEmptyInterfa
* @param bool $skipOnError Whether to skip this rule if any of the previous rules gave an error. See
* {@see SkipOnErrorInterface}.
* @param Closure|null $when A callable to define a condition for applying the rule. See {@see WhenInterface}.
*
* @psalm-param WhenType $when
*/
public function __construct(
Expand Down
1 change: 1 addition & 0 deletions src/Rule/BooleanValueHandler.php
Expand Up @@ -48,6 +48,7 @@ public function validate(mixed $value, object $rule, ValidationContext $context)
* @param ValidationContext $context Validation context.
*
* @return array A mapping between attribute names and their values.
*
* @psalm-return array<string,scalar|null>
*/
private function getCommonResultParameters(BooleanValue $rule, ValidationContext $context): array
Expand Down
1 change: 1 addition & 0 deletions src/Rule/Callback.php
Expand Up @@ -47,6 +47,7 @@ final class Callback implements
* See {@see SkipOnErrorInterface}.
* @param Closure|null $when A callable to define a condition for applying the rule.
* See {@see WhenInterface}.
*
* @psalm-param WhenType $when
*
* @throws InvalidArgumentException When neither {@see $callback} nor {@see $method} is specified or
Expand Down

0 comments on commit 81eace1

Please sign in to comment.