mirror of
https://github.com/Respect/Validation.git
synced 2026-03-16 07:15:45 +01:00
Currently, the Key rule has a third parameter that allows the validation of the wrapped rule to be optional, meaning that the validation will only happen if the key exists. That parameter makes the rule harder to understand at times. I'm splitting the Key rule into Key, KeyExists, and KeyOptional. That way, it becomes apparent when someone wants only to validate whether a key exists or if they're going to validate the value of the key only when it exists. I deliberately didn't create an abstract class because those rules are different enough not to have an abstraction. In fact, I can see myself deleting the "AbstractRelated" in the upcoming changes. With these changes, the KeySet rule will not accept validating if the key exists or validating the value only if the key exists. I should refactor that soon, and I will likely need to create a common interface for Key, KeyExists, and KeyOptional. Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
78 lines
2.2 KiB
PHP
78 lines
2.2 KiB
PHP
<?php
|
|
|
|
/*
|
|
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Respect\Validation\Rules;
|
|
|
|
use Respect\Validation\Helpers\CanBindEvaluateRule;
|
|
use Respect\Validation\Helpers\CanExtractRules;
|
|
use Respect\Validation\Message\Template;
|
|
use Respect\Validation\Result;
|
|
use Respect\Validation\Rules\Core\Wrapper;
|
|
use Respect\Validation\Validatable;
|
|
|
|
use function array_diff;
|
|
use function array_keys;
|
|
use function array_map;
|
|
use function array_merge;
|
|
use function array_values;
|
|
use function count;
|
|
|
|
#[Template(
|
|
'Must have keys {{missingKeys}} in {{name}}',
|
|
'Must not have keys {{missingKeys}} in {{name}}',
|
|
self::TEMPLATE_MISSING,
|
|
)]
|
|
#[Template(
|
|
'Must not have keys {{extraKeys}} in {{name}}',
|
|
'Must have keys {{extraKeys}} in {{name}}',
|
|
self::TEMPLATE_EXTRA,
|
|
)]
|
|
final class KeySet extends Wrapper
|
|
{
|
|
use CanBindEvaluateRule;
|
|
use CanExtractRules;
|
|
|
|
public const TEMPLATE_MISSING = '__missing__';
|
|
public const TEMPLATE_EXTRA = '__extra__';
|
|
|
|
/** @var array<string|int> */
|
|
private readonly array $keys;
|
|
|
|
public function __construct(Validatable $rule, Validatable ...$rules)
|
|
{
|
|
/** @var array<Key> $keyRules */
|
|
$keyRules = $this->extractMany(array_merge([$rule], $rules), Key::class);
|
|
|
|
$this->keys = array_map(static fn(Key $keyRule) => $keyRule->getKey(), $keyRules);
|
|
|
|
parent::__construct(count($keyRules) === 1 ? $keyRules[0] : new AllOf(...$keyRules));
|
|
}
|
|
|
|
public function evaluate(mixed $input): Result
|
|
{
|
|
$result = $this->bindEvaluate(new ArrayType(), $this, $input);
|
|
if (!$result->isValid) {
|
|
return $result;
|
|
}
|
|
|
|
$inputKeys = array_keys($input);
|
|
|
|
$missingKeys = array_diff($this->keys, $inputKeys);
|
|
if (count($missingKeys) > 0) {
|
|
return Result::failed($input, $this, ['missingKeys' => array_values($missingKeys)], self::TEMPLATE_MISSING);
|
|
}
|
|
|
|
$extraKeys = array_diff($inputKeys, $this->keys);
|
|
if (count($extraKeys) > 0) {
|
|
return Result::failed($input, $this, ['extraKeys' => array_values($extraKeys)], self::TEMPLATE_EXTRA);
|
|
}
|
|
|
|
return parent::evaluate($input);
|
|
}
|
|
}
|