Passed
Push — master ( 99ab46...a20a6f )
by Alexander
02:59
created

Rule::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 0
nc 1
nop 0
dl 0
loc 2
ccs 1
cts 1
cp 1
crap 1
rs 10
c 0
b 0
f 0
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 = true;
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): self
40
     * {
41
     *     $rule = new self();
42
     *     $rule->count = $count;
43
     *     return $rule;
44
     * }
45
     * ```
46
     */
47 169
    final protected function __construct()
48
    {
49 169
    }
50
51
    /**
52
     * Validates the value
53
     *
54
     * @param mixed $value Value to be validated.
55
     * @param ValidationContext|null $context Optional validation context.
56
     *
57
     * @return Result
58
     */
59 157
    final public function validate($value, ValidationContext $context = null): Result
60
    {
61 157
        if ($this->skipOnEmpty && $this->isEmpty($value)) {
62 1
            return new Result();
63
        }
64
65
        if (
66 157
            ($this->skipOnError && $context && $context->getParameter(Rules::PARAMETER_PREVIOUS_RULES_ERRORED) === true) ||
67 157
            (is_callable($this->when) && !($this->when)($value, $context))
68
        ) {
69 8
            return new Result();
70
        }
71
72 157
        return $this->validateValue($value, $context);
73
    }
74
75
    /**
76
     * Validates the value. The method should be implemented by concrete validation rules.
77
     *
78
     * @param mixed $value Value to be validated.
79
     * @param ValidationContext|null $context Optional validation context.
80
     *
81
     * @return Result
82
     */
83
    abstract protected function validateValue($value, ValidationContext $context = null): Result;
84
85
    /**
86
     * @return static
87
     */
88 1
    public function withFormatter(?FormatterInterface $formatter): self
89
    {
90 1
        $new = clone $this;
91 1
        $new->formatter = $formatter;
92 1
        return $new;
93
    }
94
95 175
    protected function formatMessage(string $message, array $parameters = []): string
96
    {
97 175
        if ($this->formatter === null) {
98 175
            $this->formatter = new Formatter();
99
        }
100
101 175
        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

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