Passed
Pull Request — master (#559)
by Alexander
05:07 queued 02:37
created

ValidationContext::setParameter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 4
cc 1
rs 10
ccs 0
cts 0
cp 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator;
6
7
use RuntimeException;
8
use Yiisoft\Arrays\ArrayHelper;
9
use Yiisoft\Validator\Rule\StopOnError;
10
11
/**
12
 * Validation context that might be taken into account when performing validation.
13
 *
14
 * @psalm-import-type RulesType from ValidatorInterface
15
 */
16
final class ValidationContext
17
{
18
    public const PARAMETER_VALUE_AS_ARRAY = 'yii-validator-value-as-array';
19 827
20
    /**
21
     * A name of parameter indicating that previous rule in the set caused validation error. Used to allow skipping of
22
     * the current rule:
23
     *
24
     * - in {@see Validator} for rules implementing {@see SkipOnErrorInterface}.
25
     * - for {@see StopOnError} rule (no additional configuration is needed).
26
     */
27 43
    public const PARAMETER_PREVIOUS_RULES_ERRORED = 'yii-validator-previous-rules-errored';
28
29 43
    /**
30
     * @var ValidatorInterface|null A validator instance. `null` means context data was not set
31
     * with {@see setContextDataOnce()} yet.
32
     */
33
    private ?ValidatorInterface $validator = null;
34
35 11
    /**
36
     * @var mixed The raw validated data. `null` means context data was not set with {@see setContextDataOnce()} yet.
37 11
     */
38
    private mixed $rawData = null;
39
40
    /**
41
     * @var DataSetInterface|null Global data set. `null` if data set was not set with {@see setContextDataOnce()} yet.
42
     */
43 503
    private ?DataSetInterface $globalDataSet = null;
44
45 503
    /**
46
     * @var DataSetInterface|null Current scope's data set the attribute belongs to. `null` if data set was not set
47
     * with {@see setDataSet()} yet.
48
     */
49
    private ?DataSetInterface $dataSet = null;
50
51 140
    /**
52
     * @var string|null Validated data set's attribute name. `null` if a single value is validated.
53 140
     */
54 140
    private ?string $attribute = null;
55
56
    /**
57
     * @var AttributeTranslatorInterface|null Default attribute translator to use if attribute translator is not set.
58
     */
59
    private ?AttributeTranslatorInterface $defaultAttributeTranslator = null;
60 3
61
    /**
62 3
     * @param array $parameters Arbitrary parameters.
63
     * @param AttributeTranslatorInterface|null $attributeTranslator Optional attribute translator instance to use.
64
     * If `null` is provided, or it's not specified, a default translator passed through
65
     * {@see setContextDataOnce()} is used.
66
     */
67
    public function __construct(
68
        private array $parameters = [],
69
        private ?AttributeTranslatorInterface $attributeTranslator = null,
70
    ) {
71
    }
72
73
    /**
74
     * Set context data if it is not set yet.
75 6
     *
76
     * @param ValidatorInterface $validator A validator instance.
77 6
     * @param AttributeTranslatorInterface $attributeTranslator Attribute translator to use by default. If translator
78
     * is specified via {@see setAttributeTranslator()}, it will be used instead.
79
     * @param mixed $rawData The raw validated data.
80 503
     * @param DataSetInterface $dataSet Global data set ({@see $globalDataSet}).
81
     *
82 503
     * @internal
83
     *
84
     * @return $this The same instance of validation context.
85 786
     */
86
    public function setContextDataOnce(
87 786
        ValidatorInterface $validator,
88
        AttributeTranslatorInterface $attributeTranslator,
89
        mixed $rawData,
90
        DataSetInterface $dataSet,
91
    ): self {
92
        if ($this->validator !== null) {
93
            return $this;
94
        }
95
96
        $this->validator = $validator;
97
        $this->defaultAttributeTranslator = $attributeTranslator;
98
        $this->rawData = $rawData;
99
        $this->globalDataSet = $dataSet;
100
101
        return $this;
102
    }
103
104
    /**
105
     * Set attribute translator to use.
106
     *
107
     * @param AttributeTranslatorInterface|null $attributeTranslator Attribute translator to use. If `null`,
108
     * translator passed in {@see setContextData()} will be used.
109
     *
110
     * @return $this The same instance of validation context.
111
     */
112
    public function setAttributeTranslator(?AttributeTranslatorInterface $attributeTranslator): self
113
    {
114
        $this->attributeTranslator = $attributeTranslator;
115
        return $this;
116
    }
117
118
    /**
119
     * Validate data in current context.
120
     *
121
     * @param mixed $data Data set to validate. If {@see RulesProviderInterface} instance provided and rules are
122
     * not specified explicitly, they are read from the {@see RulesProviderInterface::getRules()}.
123
     * @param callable|iterable|object|string|null $rules Rules to apply. If specified, rules are not read from data set
124
     * even if it is an instance of {@see RulesProviderInterface}.
125
     *
126
     * @psalm-param RulesType $rules
127
     *
128
     * @throws RuntimeException If validator is not set in validation context.
129
     *
130
     * @return Result Validation result.
131
     */
132
    public function validate(mixed $data, callable|iterable|object|string|null $rules = null): Result
133
    {
134
        $this->requireValidator();
135
136
        $currentDataSet = $this->dataSet;
137
        $currentAttribute = $this->attribute;
138
139
        $result = $this->validator->validate($data, $rules, $this);
0 ignored issues
show
Bug introduced by
The method validate() 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

139
        /** @scrutinizer ignore-call */ 
140
        $result = $this->validator->validate($data, $rules, $this);

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...
140
141
        $this->dataSet = $currentDataSet;
142
        $this->attribute = $currentAttribute;
143
144
        return $result;
145
    }
146
147
    /**
148
     * Get the raw validated data.
149
     *
150
     * @throws RuntimeException If validator is not set in validation context.
151
     *
152
     * @return mixed The raw validated data.
153
     */
154
    public function getRawData(): mixed
155
    {
156
        $this->requireValidator();
157
        return $this->rawData;
158
    }
159
160
    /**
161
     * Get the global data set.
162
     *
163
     * @return DataSetInterface Data set instance.
164
     *
165
     * @see $globalDataSet
166
     */
167
    public function getGlobalDataSet(): DataSetInterface
168
    {
169
        $this->requireValidator();
170
        return $this->globalDataSet;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->globalDataSet could return the type null which is incompatible with the type-hinted return Yiisoft\Validator\DataSetInterface. Consider adding an additional type-check to rule them out.
Loading history...
171
    }
172
173
    /**
174
     * Get the current scope's data set the attribute belongs to.
175
     *
176
     * @return DataSetInterface Data set instance.
177
     *
178
     * @see $dataSet
179
     */
180
    public function getDataSet(): DataSetInterface
181
    {
182
        if ($this->dataSet === null) {
183
            throw new RuntimeException('Data set in validation context is not set.');
184
        }
185
186
        return $this->dataSet;
187
    }
188
189
    /**
190
     * Set the current scope's data set the attribute belongs to.
191
     *
192
     * @param DataSetInterface $dataSet Data set instance.
193
     *
194
     * @return $this The same instance of validation context.
195
     *
196
     * @internal
197
     *
198
     * @see $dataSet
199
     */
200
    public function setDataSet(DataSetInterface $dataSet): self
201
    {
202
        $this->dataSet = $dataSet;
203
        return $this;
204
    }
205
206
    /**
207
     * Get validated data set's attribute name.
208
     *
209
     * @return string|null Validated data set's attribute name. `null` if a single value is validated.
210
     */
211
    public function getAttribute(): ?string
212
    {
213
        return $this->attribute;
214
    }
215
216
    /**
217
     * Get translated attribute name.
218
     *
219
     * @return string|null Translated attribute name. `null` if a single value is validated and there is nothing
220
     * to translate.
221
     */
222
    public function getTranslatedAttribute(): ?string
223
    {
224
        if ($this->attribute === null) {
225
            return null;
226
        }
227
228
        if ($this->attributeTranslator !== null) {
229
            return $this->attributeTranslator->translate($this->attribute);
230
        }
231
232
        if ($this->defaultAttributeTranslator !== null) {
233
            return $this->defaultAttributeTranslator->translate($this->attribute);
234
        }
235
236
        return $this->attribute;
237
    }
238
239
    /**
240
     * Set the name of the attribute validated.
241
     *
242
     * @param string|null $attribute Validated attribute name. Null if a single value is validated.
243
     *
244
     * @return $this The same instance of validation context.
245
     *
246
     * @internal
247
     */
248
    public function setAttribute(?string $attribute): self
249
    {
250
        $this->attribute = $attribute;
251
        return $this;
252
    }
253
254
    /**
255
     * Get named parameter.
256
     *
257
     * @param string $name Parameter name.
258
     * @param mixed $default Default value to return in case parameter with a given name does not exist.
259
     *
260
     * @return mixed Parameter value.
261
     *
262
     * @see ArrayHelper::getValue()
263
     */
264
    public function getParameter(string $name, mixed $default = null): mixed
265
    {
266
        return ArrayHelper::getValue($this->parameters, $name, $default);
267
    }
268
269
    /**
270
     * Set parameter value.
271
     *
272
     * @param string $name Parameter name.
273
     * @param mixed $value Parameter value.
274
     *
275
     * @return $this The same instance of validation context.
276
     */
277
    public function setParameter(string $name, mixed $value): self
278
    {
279
        $this->parameters[$name] = $value;
280
        return $this;
281
    }
282
283
    /**
284
     * Check whether {@see $attribute} is missing in a {@see $dataSet}.
285
     *
286
     * @return bool Whether {@see $attribute} is missing in a {@see $dataSet}.
287
     */
288
    public function isAttributeMissing(): bool
289
    {
290
        return $this->attribute !== null && !$this->getDataSet()->hasAttribute($this->attribute);
291
    }
292
293
    /**
294
     * Ensure that validator is set in validation context.
295
     *
296
     * @psalm-assert ValidatorInterface $this->validator
297
     * @psalm-assert DataSetInterface $this->globalDataSet
298
     *
299
     * @throws RuntimeException If validator is not set in validation context.
300
     */
301
    private function requireValidator(): void
302
    {
303
        if ($this->validator === null) {
304
            throw new RuntimeException('Validator is not set in validation context.');
305
        }
306
    }
307
}
308