Passed
Push — master ( 30cbd8...e94fe5 )
by
unknown
02:15
created

Rule::withFormatter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator;
6
7
use function is_callable;
8
9
/**
10
 * Rule represents a single value validation rule.
11
 */
12
abstract class Rule implements RuleInterface, ParametrizedRuleInterface, FormattableRuleInterface
13
{
14
    private ?FormatterInterface $formatter = null;
15
    private bool $skipOnEmpty = false;
16
    private bool $skipOnError = false;
17
18
    /**
19
     * @var callable|null
20
     */
21
    private $when = null;
22
23
    /**
24
     * To create an instance of a rule class, the static factory method `rule()` must be implemented
25
     * in the final class.
26
     *
27
     * Simple example:
28
     *
29
     * ```php
30
     * public static function rule(): self
31
     * {
32
     *     return new self();
33
     * }
34
     * ```
35
     *
36
     * Example with parameters:
37
     *
38
     * ```php
39
     * public static function rule(int $count, ConnectionInterface $connection): self
40
     * {
41
     *     $rule = new self();
42
     *     $rule->count = $count;
43
     *     $rule->connection = $connection;
44
     *     return $rule;
45
     * }
46
     * ```
47
     */
48
    final protected function __construct()
49
    {
50
    }
51
52
    /**
53
     * Validates the value
54
     *
55
     * @param mixed $value Value to be validated.
56
     * @param ValidationContext|null $context Optional validation context.
57
     *
58
     * @return Result
59
     */
60 171
    final public function validate($value, ValidationContext $context = null): Result
61
    {
62 171
        if ($this->skipOnEmpty && $this->isEmpty($value)) {
63 1
            return new Result();
64
        }
65
66
        if (
67 171
            ($this->skipOnError && $context && $context->getParameter(RuleSet::PARAMETER_PREVIOUS_RULES_ERRORED) === true) ||
68 171
            (is_callable($this->when) && !($this->when)($value, $context))
69
        ) {
70 2
            return new Result();
71
        }
72
73 171
        return $this->validateValue($value, $context);
74
    }
75
76
    /**
77
     * Validates the value. The method should be implemented by concrete validation rules.
78
     *
79
     * @param mixed $value Value to be validated.
80
     * @param ValidationContext|null $context Optional validation context.
81
     *
82
     * @return Result
83
     */
84
    abstract protected function validateValue($value, ValidationContext $context = null): Result;
85
86
    /**
87
     * @return static
88
     */
89 1
    public function withFormatter(?FormatterInterface $formatter): self
90
    {
91 1
        $new = clone $this;
92 1
        $new->formatter = $formatter;
93 1
        return $new;
94
    }
95
96 188
    protected function formatMessage(string $message, array $parameters = []): string
97
    {
98 188
        if ($this->formatter === null) {
99 188
            $this->formatter = new Formatter();
100
        }
101
102 188
        return $this->formatter->format(
0 ignored issues
show
Bug introduced by
The method format() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

102
        return $this->formatter->/** @scrutinizer ignore-call */ format(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
103
            $message,
104
            $parameters
105
        );
106
    }
107
108
    /**
109
     * Add a PHP callable whose return value determines whether this rule should be applied.
110
     * By default, rule will always be applied.
111
     *
112
     * The signature of the callable should be `function ($value, ValidationContext $context): bool`,
113
     * where `$value` and `$context` refer to the value validated and the validation context.
114
     * The callable should return a boolean value.
115
     *
116
     * The following example will enable the validator only when the country currently selected is USA:
117
     *
118
     * ```php
119
     * function ($value, ValidationContext $context)) {
120
     *     if ($context === null) {
121
     *         return false;
122
     *     }
123
     *
124
     *     $dataSet = $context->getDataSet();
125
     *     if ($dataSet === null) {
126
     *         return false;
127
     *     }
128
     *
129
     *     return $dataSet->getAttributeValue('country') === Country::USA;
130
     * }
131
     * ```
132
     *
133
     * @param callable $callback
134
     *
135
     * @return static
136
     */
137 1
    public function when(callable $callback): self
138
    {
139 1
        $new = clone $this;
140 1
        $new->when = $callback;
141 1
        return $new;
142
    }
143
144 1
    public function skipOnError(bool $value): self
145
    {
146 1
        $new = clone $this;
147 1
        $new->skipOnError = $value;
148 1
        return $new;
149
    }
150
151
    /**
152
     * @param bool $value if validation should be skipped if value validated is empty
153
     *
154
     * @return static
155
     */
156 2
    public function skipOnEmpty(bool $value): self
157
    {
158 2
        $new = clone $this;
159 2
        $new->skipOnEmpty = $value;
160 2
        return $new;
161
    }
162
163
    /**
164
     * Checks if the given value is empty.
165
     * A value is considered empty if it is null, an empty array, or an empty string.
166
     * Note that this method is different from PHP empty(). It will return false when the value is 0.
167
     *
168
     * @param mixed $value the value to be checked
169
     *
170
     * @return bool whether the value is empty
171
     */
172 18
    protected function isEmpty($value): bool
173
    {
174 18
        return $value === null || $value === [] || $value === '';
175
    }
176
177
    /**
178
     * Get name of the rule to be used when rule is converted to array.
179
     * By default it returns base name of the class, first letter in lowercase.
180
     *
181
     * @return string
182
     */
183 21
    public function getName(): string
184
    {
185 21
        $className = static::class;
186 21
        return lcfirst(substr($className, strrpos($className, '\\') + 1));
187
    }
188
189
    /**
190
     * Returns rule options as array.
191
     *
192
     * @return array
193
     */
194 57
    public function getOptions(): array
195
    {
196
        return [
197 57
            'skipOnEmpty' => $this->skipOnEmpty,
198 57
            'skipOnError' => $this->skipOnError,
199
        ];
200
    }
201
}
202