kuaukutsu / validator

Validator

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Validator

Это рабочий прототип с тестами, они же примеры. Я попытался продемонстрировать идею. В целом это такой гибрид разных практик.

Идея:

  • декомпозировать правила (rule). Убрать длинные цепочки, мне кажется лучше использовать набор правил, чем одно правило с "до-настройкой"

  • убрать явную зависимость описания ошибки от переводчика. Пускай ошибка будет не строкой, а Value Object, и тогда подключение переводчика потребуется только в месте вывода ошибки. Пример можно посмотреть ViolationPrintf - translate может быть его зависимостью, а может быть и чем то вроде ViolationTranslate

  • и в целом можно отделить правила (rules) от валидатора, в том числе вынести в отдельный репозиторий.

Что здесь может быть лишнее:

  • вместо массивов использую Коллекции. Это даёт строгую типизацию, а так же возможность определять дополнительные характеристики, например skipOnError, который нужен не для конкретного правила, а для группы правил (и не нужно прокидывать $previousRulesErrored). Но можно вернуться к массивам, а skipOnError сделать декоратором, или отдельной реализацией как например tests/data/SkipOnErrorAggregate.php

Example

Rule validate

$rule = new Boolean(1,0);

// positive
$violations = $rule->validate(1);
$violations->hasViolations(); // <-- false

// negative
$violations = $rule->validate(true);
$violations->hasViolations(); // <-- true

$violations = $rule->validate('0');
$violations->hasViolations(); // <-- true

Strict disable

$rule = (new Boolean(1,0))
    ->strict(false);

// positive
$violations = $rule->validate(1);
$violations->hasViolations(); // <-- false

$violations = $rule->validate('0'); // cast to 0
$violations->hasViolations(); // <-- false

$violations = $rule->validate(true); // cast to 1
$violations->hasViolations(); // <-- false

$violations = $rule->validate('string'); // cast to 0
$violations->hasViolations(); // <-- false

Simple value

$validator = new Validator(
    new RuleCollection(
        new NotBlank(),
        new Boolean(1, 0)
    )
);

// validate
$violations = $validator->validate(1);

// check status
if ($violations->hasViolations()) {
    // print violation
    $printf = new ViolationPrintf($violations);
    
    /** @var string $error */
    $error = $printf->getFirstViolation();
}

Object properties

$validator = new Validator([
    'id' => new RuleCollection(
        new NotBlank(),
        new Type(Type::TYPE_INT),
        new GreaterThan(0)
    ),
    'name' => new RuleCollection(
        (new Length(5,255))->skipOnEmpty(false)
    ),
]);

// validate
$violations = $validator->validate(new Entity(1, 'test'));

// check status
if ($violations->hasViolations()) {
    // print violation
    $printf = new ViolationPrintf($violations);
    
    /** @var string[] $errors */
    $errors = $printf->formatByAttributeName('name')->toArray();
}

Array validate

$ruleString = new RuleCollection(
    new NotBlank(),
    new Type('string'),
    new Length(5,255)
)

$validator = new Validator([
    'id' => new RuleCollection(
        new NotBlank(),
        new Type('int'),
        new LessThan(100, true)
    ),
    'name' => $ruleString->skipOnError(true),
]);

// validate
$violations = $validator->validate([
    'id' => 100,
    'name' => 'test' 
]);

// check status
if ($violations->hasViolations()) {
    // print violation
    $printf = new ViolationPrintf($violations);
    
    /** @var string $error */
    $error = $printf->formatByAttributeName('name')->getFirstViolation();
}

Testing

Unit testing

The package is tested with PHPUnit. To run tests:

./vendor/bin/phpunit

local

docker run --init -it --rm -v "$(pwd):/project" -v "$(pwd)/phpqa/tmp:/tmp" -w /project jakzal/phpqa php -d pcov.enabled=1 /tools/phpunit --coverage-clover=coverage.clover --colors=always

Mutation testing

The package tests are checked with Infection mutation framework. To run it:

./vendor/bin/infection

local

docker run --init -it --rm -v "$(pwd):/project" -v "$(pwd)/phpqa/tmp:/tmp" -w /project jakzal/phpqa /tools/infection run --initial-tests-php-options='-dpcov.enabled=1'

or

docker run --init -it --rm -v "$(pwd):/project" -v "$(pwd)/phpqa/tmp:/tmp" -w /project jakzal/phpqa ./vendor/bin/roave-infection-static-analysis-plugin run --initial-tests-php-options='-dpcov.enabled=1'

Static analysis

The code is statically analyzed with Psalm. To run static analysis:

./vendor/bin/psalm

About

Validator


Languages

Language:PHP 100.0%