1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Terah\Assert; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* Assert |
7
|
|
|
* |
8
|
|
|
* LICENSE |
9
|
|
|
* |
10
|
|
|
* This source file is subject to the new BSD license that is bundled |
11
|
|
|
* with this package in the file LICENSE.txt. |
12
|
|
|
* If you did not receive a copy of the license and are unable to |
13
|
|
|
* obtain it through the world-wide-web, please send an email |
14
|
|
|
* to [email protected] so I can send you a copy immediately. |
15
|
|
|
*/ |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Assert library |
19
|
|
|
* |
20
|
|
|
* @author Benjamin Eberlei <[email protected]> |
21
|
|
|
* @author Terry Cullen <[email protected]> |
22
|
|
|
* |
23
|
|
|
*/ |
24
|
|
|
class Assert |
25
|
|
|
{ |
26
|
|
|
const INVALID_FLOAT = 9; |
27
|
|
|
const INVALID_INTEGER = 10; |
28
|
|
|
const INVALID_DIGIT = 11; |
29
|
|
|
const INVALID_INTEGERISH = 12; |
30
|
|
|
const INVALID_BOOLEAN = 13; |
31
|
|
|
const VALUE_EMPTY = 14; |
32
|
|
|
const VALUE_NULL = 15; |
33
|
|
|
const INVALID_STRING = 16; |
34
|
|
|
const INVALID_REGEX = 17; |
35
|
|
|
const INVALID_MIN_LENGTH = 18; |
36
|
|
|
const INVALID_MAX_LENGTH = 19; |
37
|
|
|
const INVALID_STRING_START = 20; |
38
|
|
|
const INVALID_STRING_CONTAINS = 21; |
39
|
|
|
const INVALID_CHOICE = 22; |
40
|
|
|
const INVALID_NUMERIC = 23; |
41
|
|
|
const INVALID_ARRAY = 24; |
42
|
|
|
const INVALID_KEY_EXISTS = 26; |
43
|
|
|
const INVALID_NOT_BLANK = 27; |
44
|
|
|
const INVALID_INSTANCE_OF = 28; |
45
|
|
|
const INVALID_SUBCLASS_OF = 29; |
46
|
|
|
const INVALID_RANGE = 30; |
47
|
|
|
const INVALID_ALNUM = 31; |
48
|
|
|
const INVALID_TRUE = 32; |
49
|
|
|
const INVALID_EQ = 33; |
50
|
|
|
const INVALID_SAME = 34; |
51
|
|
|
const INVALID_MIN = 35; |
52
|
|
|
const INVALID_MAX = 36; |
53
|
|
|
const INVALID_LENGTH = 37; |
54
|
|
|
const INVALID_FALSE = 38; |
55
|
|
|
const INVALID_STRING_END = 39; |
56
|
|
|
const INVALID_UUID = 40; |
57
|
|
|
const INVALID_COUNT = 41; |
58
|
|
|
const INVALID_NOT_EQ = 42; |
59
|
|
|
const INVALID_NOT_SAME = 43; |
60
|
|
|
const INVALID_TRAVERSABLE = 44; |
61
|
|
|
const INVALID_ARRAY_ACCESSIBLE = 45; |
62
|
|
|
const INVALID_KEY_ISSET = 46; |
63
|
|
|
const INVALID_DIRECTORY = 101; |
64
|
|
|
const INVALID_FILE = 102; |
65
|
|
|
const INVALID_READABLE = 103; |
66
|
|
|
const INVALID_WRITEABLE = 104; |
67
|
|
|
const INVALID_CLASS = 105; |
68
|
|
|
const INVALID_EMAIL = 201; |
69
|
|
|
const INTERFACE_NOT_IMPLEMENTED = 202; |
70
|
|
|
const INVALID_URL = 203; |
71
|
|
|
const INVALID_NOT_INSTANCE_OF = 204; |
72
|
|
|
const VALUE_NOT_EMPTY = 205; |
73
|
|
|
const INVALID_JSON_STRING = 206; |
74
|
|
|
const INVALID_OBJECT = 207; |
75
|
|
|
const INVALID_METHOD = 208; |
76
|
|
|
const INVALID_SCALAR = 209; |
77
|
|
|
const INVALID_DATE = 210; |
78
|
|
|
const INVALID_CALLABLE = 211; |
79
|
|
|
const INVALID_KEYS_EXIST = 300; |
80
|
|
|
const INVALID_PROPERTY_EXISTS = 301; |
81
|
|
|
const INVALID_PROPERTIES_EXIST = 302; |
82
|
|
|
const INVALID_UTF8 = 303; |
83
|
|
|
const INVALID_DOMAIN_NAME = 304; |
84
|
|
|
const INVALID_NOT_FALSE = 305; |
85
|
|
|
const INVALID_FILE_OR_DIR = 306; |
86
|
|
|
const INVALID_ASCII = 307; |
87
|
|
|
const INVALID_NOT_REGEX = 308; |
88
|
|
|
const INVALID_GREATER_THAN = 309; |
89
|
|
|
const INVALID_LESS_THAN = 310; |
90
|
|
|
const INVALID_GREATER_THAN_OR_EQ = 311; |
91
|
|
|
const INVALID_LESS_THAN_OR_EQ = 312; |
92
|
|
|
|
93
|
|
|
/** @var bool */ |
94
|
|
|
protected $nullOr = false; |
95
|
|
|
|
96
|
|
|
/** @var bool */ |
97
|
|
|
protected $emptyOr = false; |
98
|
|
|
|
99
|
|
|
/** @var mixed */ |
100
|
|
|
protected $value = null; |
101
|
|
|
|
102
|
|
|
/** @var bool */ |
103
|
|
|
protected $all = false; |
104
|
|
|
|
105
|
|
|
/** @var null|string */ |
106
|
|
|
protected $propertyPath = null; |
107
|
|
|
/** |
108
|
|
|
* Exception to throw when an assertion failed. |
109
|
|
|
* |
110
|
|
|
* @var string |
111
|
|
|
*/ |
112
|
|
|
protected $exceptionClass = 'Terah\Assert\AssertionFailedException'; |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* @param mixed $value |
116
|
|
|
*/ |
117
|
|
|
public function __construct($value) |
118
|
|
|
{ |
119
|
|
|
$this->value($value); |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* @param $value |
124
|
|
|
* @return Assert |
125
|
|
|
*/ |
126
|
|
|
public static function that($value) |
127
|
|
|
{ |
128
|
|
|
return new Assert($value); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* @param mixed $value |
133
|
|
|
* @return Assert |
134
|
|
|
*/ |
135
|
|
|
public function reset($value) |
136
|
|
|
{ |
137
|
|
|
return $this->all(false)->nullOr(false)->value($value); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* @param mixed $value |
142
|
|
|
* @return Assert |
143
|
|
|
*/ |
144
|
|
|
public function value($value) |
145
|
|
|
{ |
146
|
|
|
$this->value = $value; |
147
|
|
|
return $this; |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* @param bool $nullOr |
152
|
|
|
* @return Assert |
153
|
|
|
*/ |
154
|
|
|
public function nullOr($nullOr = true) |
155
|
|
|
{ |
156
|
|
|
$this->nullOr = $nullOr; |
157
|
|
|
return $this; |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* @param bool $emptyOr |
162
|
|
|
* @return Assert |
163
|
|
|
*/ |
164
|
|
|
public function emptyOr($emptyOr = true) |
165
|
|
|
{ |
166
|
|
|
$this->emptyOr = $emptyOr; |
167
|
|
|
return $this; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* @param bool $all |
172
|
|
|
* @return Assert |
173
|
|
|
*/ |
174
|
|
|
public function all($all = true) |
175
|
|
|
{ |
176
|
|
|
$this->all = $all; |
177
|
|
|
return $this; |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* Helper method that handles building the assertion failure exceptions. |
182
|
|
|
* They are returned from this method so that the stack trace still shows |
183
|
|
|
* the assertions method. |
184
|
|
|
* |
185
|
|
|
* @param string $message |
186
|
|
|
* @param int $code |
187
|
|
|
* @param string $propertyPath |
188
|
|
|
* @param array $constraints |
189
|
|
|
* @return AssertionFailedException |
190
|
|
|
*/ |
191
|
|
|
protected function createException($message, $code, $propertyPath, array $constraints = []) |
192
|
|
|
{ |
193
|
|
|
$exceptionClass = $this->exceptionClass; |
194
|
|
|
$propertyPath = is_null($propertyPath) ? $this->propertyPath : $propertyPath; |
195
|
|
|
return new $exceptionClass($message, $code, $propertyPath, $this->value, $constraints); |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* @param $exceptionClass |
200
|
|
|
* @return Assert |
201
|
|
|
*/ |
202
|
|
|
public function setExceptionClass($exceptionClass) |
203
|
|
|
{ |
204
|
|
|
$this->exceptionClass = $exceptionClass; |
205
|
|
|
return $this; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
/** |
209
|
|
|
* @param string $name |
210
|
|
|
* @return Assert |
211
|
|
|
*/ |
212
|
|
|
public function name($name) |
213
|
|
|
{ |
214
|
|
|
$this->propertyPath = $name; |
215
|
|
|
return $this; |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
/** |
219
|
|
|
* Assert that two values are equal (using == ). |
220
|
|
|
* |
221
|
|
|
* @param mixed $value2 |
222
|
|
|
* @param string|null $message |
223
|
|
|
* @param string|null $propertyPath |
224
|
|
|
* @return Assert |
225
|
|
|
* @throws AssertionFailedException |
226
|
|
|
*/ |
227
|
|
|
public function eq($value2, $message = null, $propertyPath = null) |
228
|
|
|
{ |
229
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
230
|
|
|
{ |
231
|
|
|
return $this; |
232
|
|
|
} |
233
|
|
|
if ( $this->value != $value2 ) |
234
|
|
|
{ |
235
|
|
|
$message = sprintf( |
236
|
|
|
$message ?: 'Value "%s" does not equal expected value "%s".', |
237
|
|
|
$this->stringify($this->value), |
238
|
|
|
$this->stringify($value2) |
239
|
|
|
); |
240
|
|
|
throw $this->createException($message, self::INVALID_EQ, $propertyPath, ['expected' => $value2]); |
241
|
|
|
} |
242
|
|
|
return $this; |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
/** |
246
|
|
|
* |
247
|
|
|
* @param mixed $value2 |
248
|
|
|
* @param string|null $message |
249
|
|
|
* @param string|null $propertyPath |
250
|
|
|
* @return Assert |
251
|
|
|
* @throws AssertionFailedException |
252
|
|
|
*/ |
253
|
|
View Code Duplication |
public function greaterThan($value2, $message = null, $propertyPath = null) |
|
|
|
|
254
|
|
|
{ |
255
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
256
|
|
|
{ |
257
|
|
|
return $this; |
258
|
|
|
} |
259
|
|
|
if ( ! ( $this->value > $value2 ) ) |
260
|
|
|
{ |
261
|
|
|
$message = sprintf( |
262
|
|
|
$message ?: 'Value "%s" does not greater then expected value "%s".', |
263
|
|
|
$this->stringify($this->value), |
264
|
|
|
$this->stringify($value2) |
265
|
|
|
); |
266
|
|
|
throw $this->createException($message, self::INVALID_EQ, $propertyPath, ['expected' => $value2]); |
267
|
|
|
} |
268
|
|
|
return $this; |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
/** |
272
|
|
|
* |
273
|
|
|
* @param mixed $value2 |
274
|
|
|
* @param string|null $message |
275
|
|
|
* @param string|null $propertyPath |
276
|
|
|
* @return Assert |
277
|
|
|
* @throws AssertionFailedException |
278
|
|
|
*/ |
279
|
|
View Code Duplication |
public function greaterThanOrEq($value2, $message = null, $propertyPath = null) |
|
|
|
|
280
|
|
|
{ |
281
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
282
|
|
|
{ |
283
|
|
|
return $this; |
284
|
|
|
} |
285
|
|
|
if ( ! ( $this->value >= $value2 ) ) |
286
|
|
|
{ |
287
|
|
|
$message = sprintf( |
288
|
|
|
$message ?: 'Value "%s" does not greater than or equal to expected value "%s".', |
289
|
|
|
$this->stringify($this->value), |
290
|
|
|
$this->stringify($value2) |
291
|
|
|
); |
292
|
|
|
throw $this->createException($message, self::INVALID_EQ, $propertyPath, ['expected' => $value2]); |
293
|
|
|
} |
294
|
|
|
return $this; |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
/** |
298
|
|
|
* |
299
|
|
|
* @param mixed $value2 |
300
|
|
|
* @param string|null $message |
301
|
|
|
* @param string|null $propertyPath |
302
|
|
|
* @return Assert |
303
|
|
|
* @throws AssertionFailedException |
304
|
|
|
*/ |
305
|
|
View Code Duplication |
public function lessThan($value2, $message = null, $propertyPath = null) |
|
|
|
|
306
|
|
|
{ |
307
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
308
|
|
|
{ |
309
|
|
|
return $this; |
310
|
|
|
} |
311
|
|
|
if ( ! ( $this->value < $value2 ) ) |
312
|
|
|
{ |
313
|
|
|
$message = sprintf( |
314
|
|
|
$message ?: 'Value "%s" does not less then expected value "%s".', |
315
|
|
|
$this->stringify($this->value), |
316
|
|
|
$this->stringify($value2) |
317
|
|
|
); |
318
|
|
|
throw $this->createException($message, self::INVALID_LESS_THAN, $propertyPath, ['expected' => $value2]); |
319
|
|
|
} |
320
|
|
|
return $this; |
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
/** |
324
|
|
|
* |
325
|
|
|
* @param mixed $value2 |
326
|
|
|
* @param string|null $message |
327
|
|
|
* @param string|null $propertyPath |
328
|
|
|
* @return Assert |
329
|
|
|
* @throws AssertionFailedException |
330
|
|
|
*/ |
331
|
|
View Code Duplication |
public function lessThanOrEq($value2, $message = null, $propertyPath = null) |
|
|
|
|
332
|
|
|
{ |
333
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
334
|
|
|
{ |
335
|
|
|
return $this; |
336
|
|
|
} |
337
|
|
|
if ( ! ( $this->value <= $value2 ) ) |
338
|
|
|
{ |
339
|
|
|
$message = sprintf( |
340
|
|
|
$message ?: 'Value "%s" does not less than or equal to expected value "%s".', |
341
|
|
|
$this->stringify($this->value), |
342
|
|
|
$this->stringify($value2) |
343
|
|
|
); |
344
|
|
|
throw $this->createException($message, self::INVALID_LESS_THAN_OR_EQ, $propertyPath, ['expected' => $value2]); |
345
|
|
|
} |
346
|
|
|
return $this; |
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
/** |
350
|
|
|
* Assert that two values are the same (using ===). |
351
|
|
|
* |
352
|
|
|
* @param mixed $value2 |
353
|
|
|
* @param string|null $message |
354
|
|
|
* @param string|null $propertyPath |
355
|
|
|
* @return Assert |
356
|
|
|
* @throws AssertionFailedException |
357
|
|
|
*/ |
358
|
|
|
public function same($value2, $message = null, $propertyPath = null) |
359
|
|
|
{ |
360
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
361
|
|
|
{ |
362
|
|
|
return $this; |
363
|
|
|
} |
364
|
|
|
if ( $this->value !== $value2 ) |
365
|
|
|
{ |
366
|
|
|
$message = sprintf( |
367
|
|
|
$message ?: 'Value "%s" is not the same as expected value "%s".', |
368
|
|
|
$this->stringify($this->value), |
369
|
|
|
$this->stringify($value2) |
370
|
|
|
); |
371
|
|
|
throw $this->createException($message, self::INVALID_SAME, $propertyPath, ['expected' => $value2]); |
372
|
|
|
} |
373
|
|
|
return $this; |
374
|
|
|
} |
375
|
|
|
|
376
|
|
|
/** |
377
|
|
|
* Assert that two values are not equal (using == ). |
378
|
|
|
* |
379
|
|
|
* @param mixed $value2 |
380
|
|
|
* @param string|null $message |
381
|
|
|
* @param string|null $propertyPath |
382
|
|
|
* @return Assert |
383
|
|
|
* @throws AssertionFailedException |
384
|
|
|
*/ |
385
|
|
|
public function notEq($value2, $message = null, $propertyPath = null) |
386
|
|
|
{ |
387
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
388
|
|
|
{ |
389
|
|
|
return $this; |
390
|
|
|
} |
391
|
|
|
if ( $this->value == $value2 ) |
392
|
|
|
{ |
393
|
|
|
$message = sprintf( |
394
|
|
|
$message ?: 'Value "%s" is equal to expected value "%s".', |
395
|
|
|
$this->stringify($this->value), |
396
|
|
|
$this->stringify($value2) |
397
|
|
|
); |
398
|
|
|
throw $this->createException($message, self::INVALID_NOT_EQ, $propertyPath, ['expected' => $value2]); |
399
|
|
|
} |
400
|
|
|
return $this; |
401
|
|
|
} |
402
|
|
|
|
403
|
|
|
/** |
404
|
|
|
* @param string|null $message |
405
|
|
|
* @param string|null $propertyPath |
406
|
|
|
* |
407
|
|
|
* @return $this |
408
|
|
|
* @throws AssertionFailedException |
409
|
|
|
*/ |
410
|
|
|
public function isCallable($message = null, $propertyPath = null) |
411
|
|
|
{ |
412
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
413
|
|
|
{ |
414
|
|
|
return $this; |
415
|
|
|
} |
416
|
|
|
if ( !is_callable($this->value) ) |
417
|
|
|
{ |
418
|
|
|
$message = sprintf( |
419
|
|
|
$message ?: 'Value "%s" is not callable.', |
420
|
|
|
$this->stringify($this->value) |
421
|
|
|
); |
422
|
|
|
throw $this->createException($message, self::INVALID_NOT_EQ, $propertyPath); |
423
|
|
|
} |
424
|
|
|
return $this; |
425
|
|
|
} |
426
|
|
|
|
427
|
|
|
/** |
428
|
|
|
* Assert that two values are not the same (using === ). |
429
|
|
|
* |
430
|
|
|
* @param mixed $value2 |
431
|
|
|
* @param string|null $message |
432
|
|
|
* @param string|null $propertyPath |
433
|
|
|
* @return Assert |
434
|
|
|
* @throws AssertionFailedException |
435
|
|
|
*/ |
436
|
|
|
public function notSame($value2, $message = null, $propertyPath = null) |
437
|
|
|
{ |
438
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
439
|
|
|
{ |
440
|
|
|
return $this; |
441
|
|
|
} |
442
|
|
|
if ( $this->value === $value2 ) |
443
|
|
|
{ |
444
|
|
|
$message = sprintf( |
445
|
|
|
$message ?: 'Value "%s" is the same as expected value "%s".', |
446
|
|
|
$this->stringify($this->value), |
447
|
|
|
$this->stringify($value2) |
448
|
|
|
); |
449
|
|
|
throw $this->createException($message, self::INVALID_NOT_SAME, $propertyPath, ['expected' => $value2]); |
450
|
|
|
} |
451
|
|
|
return $this; |
452
|
|
|
} |
453
|
|
|
|
454
|
|
|
/** |
455
|
|
|
* @param string|null $message |
456
|
|
|
* @param string|null $propertyPath |
457
|
|
|
* @return Assert |
458
|
|
|
* @throws AssertionFailedException |
459
|
|
|
*/ |
460
|
|
|
public function id($message = null, $propertyPath = null) |
461
|
|
|
{ |
462
|
|
|
$message = $message ?: 'Value "%s" is not an integer id.'; |
463
|
|
|
return $this->nonEmptyInt($message, $propertyPath)->range(1, PHP_INT_MAX); |
464
|
|
|
} |
465
|
|
|
|
466
|
|
|
/** |
467
|
|
|
* @param string|null $message |
468
|
|
|
* @param string|null $propertyPath |
469
|
|
|
* @return Assert |
470
|
|
|
* @throws AssertionFailedException |
471
|
|
|
*/ |
472
|
|
|
public function flag($message = null, $propertyPath = null) |
473
|
|
|
{ |
474
|
|
|
$message = $message ?: 'Value "%s" is not a 0 or 1.'; |
475
|
|
|
return $this->range(0, 1, $message, $propertyPath); |
476
|
|
|
} |
477
|
|
|
|
478
|
|
|
/** |
479
|
|
|
* @param string|null $message |
480
|
|
|
* @param string|null $propertyPath |
481
|
|
|
* @return Assert |
482
|
|
|
* @throws AssertionFailedException |
483
|
|
|
*/ |
484
|
|
|
public function status($message = null, $propertyPath = null) |
485
|
|
|
{ |
486
|
|
|
$message = $message ?: 'Value "%s" is not a valid status.'; |
487
|
|
|
return $this->integer($message, $propertyPath)->inArray([-1, 0, 1]); |
488
|
|
|
} |
489
|
|
|
|
490
|
|
|
/** |
491
|
|
|
* @param string|null $message |
492
|
|
|
* @param string|null $propertyPath |
493
|
|
|
* @return Assert |
494
|
|
|
*/ |
495
|
|
|
public function nullOrId($message = null, $propertyPath = null) |
496
|
|
|
{ |
497
|
|
|
return $this->nullOr()->id($message, $propertyPath); |
498
|
|
|
} |
499
|
|
|
|
500
|
|
|
/** |
501
|
|
|
* @param string|null $message |
502
|
|
|
* @param string|null $propertyPath |
503
|
|
|
* @return Assert |
504
|
|
|
*/ |
505
|
|
|
public function allIds($message = null, $propertyPath = null) |
506
|
|
|
{ |
507
|
|
|
return $this->all()->id($message, $propertyPath); |
508
|
|
|
} |
509
|
|
|
|
510
|
|
|
/** |
511
|
|
|
* @param string|null $message |
512
|
|
|
* @param string|null $propertyPath |
513
|
|
|
* @return Assert |
514
|
|
|
* @throws AssertionFailedException |
515
|
|
|
*/ |
516
|
|
|
public function int($message = null, $propertyPath = null) |
517
|
|
|
{ |
518
|
|
|
return $this->integer($message, $propertyPath); |
519
|
|
|
} |
520
|
|
|
|
521
|
|
|
/** |
522
|
|
|
* Assert that value is a php integer. |
523
|
|
|
* |
524
|
|
|
* @param string|null $message |
525
|
|
|
* @param string|null $propertyPath |
526
|
|
|
* @return Assert |
527
|
|
|
* @throws AssertionFailedException |
528
|
|
|
*/ |
529
|
|
|
public function integer($message = null, $propertyPath = null) |
530
|
|
|
{ |
531
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
532
|
|
|
{ |
533
|
|
|
return $this; |
534
|
|
|
} |
535
|
|
|
if ( !is_int($this->value) ) |
536
|
|
|
{ |
537
|
|
|
$message = sprintf( |
538
|
|
|
$message ?: 'Value "%s" is not an integer.', |
539
|
|
|
$this->stringify($this->value) |
540
|
|
|
); |
541
|
|
|
throw $this->createException($message, self::INVALID_INTEGER, $propertyPath); |
542
|
|
|
} |
543
|
|
|
return $this; |
544
|
|
|
} |
545
|
|
|
|
546
|
|
|
/** |
547
|
|
|
* Assert that value is a php float. |
548
|
|
|
* |
549
|
|
|
* @param string|null $message |
550
|
|
|
* @param string|null $propertyPath |
551
|
|
|
* @return Assert |
552
|
|
|
* @throws AssertionFailedException |
553
|
|
|
*/ |
554
|
|
|
public function float($message = null, $propertyPath = null) |
555
|
|
|
{ |
556
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
557
|
|
|
{ |
558
|
|
|
return $this; |
559
|
|
|
} |
560
|
|
|
if ( !is_float($this->value) ) |
561
|
|
|
{ |
562
|
|
|
$message = sprintf( |
563
|
|
|
$message ?: 'Value "%s" is not a float.', |
564
|
|
|
$this->stringify($this->value) |
565
|
|
|
); |
566
|
|
|
throw $this->createException($message, self::INVALID_FLOAT, $propertyPath); |
567
|
|
|
} |
568
|
|
|
return $this; |
569
|
|
|
} |
570
|
|
|
|
571
|
|
|
/** |
572
|
|
|
* Validates if an integer or integerish is a digit. |
573
|
|
|
* |
574
|
|
|
* @param string|null $message |
575
|
|
|
* @param string|null $propertyPath |
576
|
|
|
* @return Assert |
577
|
|
|
* @throws AssertionFailedException |
578
|
|
|
*/ |
579
|
|
|
public function digit($message = null, $propertyPath = null) |
580
|
|
|
{ |
581
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
582
|
|
|
{ |
583
|
|
|
return $this; |
584
|
|
|
} |
585
|
|
|
if ( !ctype_digit((string)$this->value) ) |
586
|
|
|
{ |
587
|
|
|
$message = sprintf( |
588
|
|
|
$message ?: 'Value "%s" is not a digit.', |
589
|
|
|
$this->stringify($this->value) |
590
|
|
|
); |
591
|
|
|
throw $this->createException($message, self::INVALID_DIGIT, $propertyPath); |
592
|
|
|
} |
593
|
|
|
return $this; |
594
|
|
|
} |
595
|
|
|
|
596
|
|
|
/** |
597
|
|
|
* Validates if an string is a date . |
598
|
|
|
* |
599
|
|
|
* @param string|null $message |
600
|
|
|
* @param string|null $propertyPath |
601
|
|
|
* @return Assert |
602
|
|
|
* @throws AssertionFailedException |
603
|
|
|
*/ |
604
|
|
|
public function date($message = null, $propertyPath = null) |
605
|
|
|
{ |
606
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
607
|
|
|
{ |
608
|
|
|
return $this; |
609
|
|
|
} |
610
|
|
|
$this->notEmpty($message, $propertyPath); |
611
|
|
|
if ( strtotime($this->value) === false ) |
612
|
|
|
{ |
613
|
|
|
$message = sprintf( |
614
|
|
|
$message ?: 'Value "%s" is not a date.', |
615
|
|
|
$this->stringify($this->value) |
616
|
|
|
); |
617
|
|
|
throw $this->createException($message, self::INVALID_DATE, $propertyPath); |
618
|
|
|
} |
619
|
|
|
return $this; |
620
|
|
|
} |
621
|
|
|
|
622
|
|
|
/** |
623
|
|
|
* Assert that value is a php integer'ish. |
624
|
|
|
* |
625
|
|
|
* @param string|null $message |
626
|
|
|
* @param string|null $propertyPath |
627
|
|
|
* @return Assert |
628
|
|
|
* @throws AssertionFailedException |
629
|
|
|
*/ |
630
|
|
|
public function integerish($message = null, $propertyPath = null) |
631
|
|
|
{ |
632
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
633
|
|
|
{ |
634
|
|
|
return $this; |
635
|
|
|
} |
636
|
|
|
if ( is_object($this->value) || strval(intval($this->value)) != $this->value || is_bool($this->value) || is_null($this->value) ) |
637
|
|
|
{ |
638
|
|
|
$message = sprintf( |
639
|
|
|
$message ?: 'Value "%s" is not an integer or a number castable to integer.', |
640
|
|
|
$this->stringify($this->value) |
641
|
|
|
); |
642
|
|
|
throw $this->createException($message, self::INVALID_INTEGERISH, $propertyPath); |
643
|
|
|
} |
644
|
|
|
return $this; |
645
|
|
|
} |
646
|
|
|
|
647
|
|
|
/** |
648
|
|
|
* Assert that value is php boolean |
649
|
|
|
* |
650
|
|
|
* @param string|null $message |
651
|
|
|
* @param string|null $propertyPath |
652
|
|
|
* @return Assert |
653
|
|
|
* @throws AssertionFailedException |
654
|
|
|
*/ |
655
|
|
|
public function boolean($message = null, $propertyPath = null) |
656
|
|
|
{ |
657
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
658
|
|
|
{ |
659
|
|
|
return $this; |
660
|
|
|
} |
661
|
|
|
if ( !is_bool($this->value) ) |
662
|
|
|
{ |
663
|
|
|
$message = sprintf( |
664
|
|
|
$message ?: 'Value "%s" is not a boolean.', |
665
|
|
|
$this->stringify($this->value) |
666
|
|
|
); |
667
|
|
|
throw $this->createException($message, self::INVALID_BOOLEAN, $propertyPath); |
668
|
|
|
} |
669
|
|
|
return $this; |
670
|
|
|
} |
671
|
|
|
|
672
|
|
|
/** |
673
|
|
|
* Assert that value is a PHP scalar |
674
|
|
|
* |
675
|
|
|
* @param string|null $message |
676
|
|
|
* @param string|null $propertyPath |
677
|
|
|
* @return Assert |
678
|
|
|
* @throws AssertionFailedException |
679
|
|
|
*/ |
680
|
|
|
public function scalar($message = null, $propertyPath = null) |
681
|
|
|
{ |
682
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
683
|
|
|
{ |
684
|
|
|
return $this; |
685
|
|
|
} |
686
|
|
|
if ( !is_scalar($this->value) ) |
687
|
|
|
{ |
688
|
|
|
$message = sprintf( |
689
|
|
|
$message ?: 'Value "%s" is not a scalar.', |
690
|
|
|
$this->stringify($this->value) |
691
|
|
|
); |
692
|
|
|
throw $this->createException($message, self::INVALID_SCALAR, $propertyPath); |
693
|
|
|
} |
694
|
|
|
return $this; |
695
|
|
|
} |
696
|
|
|
|
697
|
|
|
/** |
698
|
|
|
* Assert that value is not empty |
699
|
|
|
* |
700
|
|
|
* @param string|null $message |
701
|
|
|
* @param string|null $propertyPath |
702
|
|
|
* @return Assert |
703
|
|
|
* @throws AssertionFailedException |
704
|
|
|
*/ |
705
|
|
View Code Duplication |
public function notEmpty($message = null, $propertyPath = null) |
|
|
|
|
706
|
|
|
{ |
707
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
708
|
|
|
{ |
709
|
|
|
return $this; |
710
|
|
|
} |
711
|
|
|
if ( ( is_object($this->value) && empty((array)$this->value) ) || empty($this->value) ) |
712
|
|
|
{ |
713
|
|
|
$message = sprintf( |
714
|
|
|
$message ?: 'Value "%s" is empty, but non empty value was expected.', |
715
|
|
|
$this->stringify($this->value) |
716
|
|
|
); |
717
|
|
|
throw $this->createException($message, self::VALUE_EMPTY, $propertyPath); |
718
|
|
|
} |
719
|
|
|
return $this; |
720
|
|
|
} |
721
|
|
|
|
722
|
|
|
/** |
723
|
|
|
* Assert that value is empty |
724
|
|
|
* |
725
|
|
|
* @param string|null $message |
726
|
|
|
* @param string|null $propertyPath |
727
|
|
|
* @return Assert |
728
|
|
|
* @throws AssertionFailedException |
729
|
|
|
*/ |
730
|
|
|
public function noContent($message = null, $propertyPath = null) |
731
|
|
|
{ |
732
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
733
|
|
|
{ |
734
|
|
|
return $this; |
735
|
|
|
} |
736
|
|
|
if ( !empty( $this->value ) ) |
737
|
|
|
{ |
738
|
|
|
$message = sprintf( |
739
|
|
|
$message ?: 'Value "%s" is not empty, but empty value was expected.', |
740
|
|
|
$this->stringify($this->value) |
741
|
|
|
); |
742
|
|
|
throw $this->createException($message, self::VALUE_NOT_EMPTY, $propertyPath); |
743
|
|
|
} |
744
|
|
|
return $this; |
745
|
|
|
} |
746
|
|
|
|
747
|
|
|
/** |
748
|
|
|
* Assert that value is not null |
749
|
|
|
* |
750
|
|
|
* @param string|null $message |
751
|
|
|
* @param string|null $propertyPath |
752
|
|
|
* @return Assert |
753
|
|
|
* @throws AssertionFailedException |
754
|
|
|
*/ |
755
|
|
|
public function notNull($message = null, $propertyPath = null) |
756
|
|
|
{ |
757
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
758
|
|
|
{ |
759
|
|
|
return $this; |
760
|
|
|
} |
761
|
|
|
if ( $this->value === null ) |
762
|
|
|
{ |
763
|
|
|
$message = sprintf( |
764
|
|
|
$message ?: 'Value "%s" is null, but non null value was expected.', |
765
|
|
|
$this->stringify($this->value) |
766
|
|
|
); |
767
|
|
|
throw $this->createException($message, self::VALUE_NULL, $propertyPath); |
768
|
|
|
} |
769
|
|
|
return $this; |
770
|
|
|
} |
771
|
|
|
|
772
|
|
|
/** |
773
|
|
|
* Assert that value is a string |
774
|
|
|
* |
775
|
|
|
* @param string|null $message |
776
|
|
|
* @param string|null $propertyPath |
777
|
|
|
* @return Assert |
778
|
|
|
* @throws AssertionFailedException |
779
|
|
|
*/ |
780
|
|
|
public function string($message = null, $propertyPath = null) |
781
|
|
|
{ |
782
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
783
|
|
|
{ |
784
|
|
|
return $this; |
785
|
|
|
} |
786
|
|
|
if ( !is_string($this->value) ) |
787
|
|
|
{ |
788
|
|
|
$message = sprintf( |
789
|
|
|
$message ?: 'Value "%s" expected to be string, type %s given.', |
790
|
|
|
$this->stringify($this->value), |
791
|
|
|
gettype($this->value) |
792
|
|
|
); |
793
|
|
|
throw $this->createException($message, self::INVALID_STRING, $propertyPath); |
794
|
|
|
} |
795
|
|
|
return $this; |
796
|
|
|
} |
797
|
|
|
|
798
|
|
|
/** |
799
|
|
|
* Assert that value matches a regex |
800
|
|
|
* |
801
|
|
|
* @param string $pattern |
802
|
|
|
* @param string|null $message |
803
|
|
|
* @param string|null $propertyPath |
804
|
|
|
* @return Assert |
805
|
|
|
* @throws AssertionFailedException |
806
|
|
|
*/ |
807
|
|
|
public function regex($pattern, $message = null, $propertyPath = null) |
808
|
|
|
{ |
809
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
810
|
|
|
{ |
811
|
|
|
return $this; |
812
|
|
|
} |
813
|
|
|
$this->string($message, $propertyPath); |
814
|
|
|
if ( !preg_match($pattern, $this->value) ) |
815
|
|
|
{ |
816
|
|
|
$message = sprintf( |
817
|
|
|
$message ?: 'Value "%s" does not match expression.', |
818
|
|
|
$this->stringify($this->value) |
819
|
|
|
); |
820
|
|
|
throw $this->createException($message, self::INVALID_REGEX, $propertyPath, ['pattern' => $pattern]); |
821
|
|
|
} |
822
|
|
|
return $this; |
823
|
|
|
} |
824
|
|
|
|
825
|
|
|
/** |
826
|
|
|
* @param string $pattern |
827
|
|
|
* @param string|null $message |
828
|
|
|
* @param string|null $propertyPath |
829
|
|
|
* @return $this |
830
|
|
|
* @throws AssertionFailedException |
831
|
|
|
*/ |
832
|
|
|
public function notRegex($pattern, $message = null, $propertyPath = null) |
833
|
|
|
{ |
834
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
835
|
|
|
{ |
836
|
|
|
return $this; |
837
|
|
|
} |
838
|
|
|
$this->string($message, $propertyPath); |
839
|
|
|
if ( preg_match($pattern, $this->value) ) |
840
|
|
|
{ |
841
|
|
|
$message = sprintf( |
842
|
|
|
$message ?: 'Value "%s" does not match expression.', |
843
|
|
|
$this->stringify($this->value) |
844
|
|
|
); |
845
|
|
|
throw $this->createException($message, self::INVALID_REGEX, $propertyPath, ['pattern' => $pattern]); |
846
|
|
|
} |
847
|
|
|
return $this; |
848
|
|
|
} |
849
|
|
|
|
850
|
|
|
/** |
851
|
|
|
* Assert that string has a given length. |
852
|
|
|
* |
853
|
|
|
* @param int $length |
854
|
|
|
* @param string|null $message |
855
|
|
|
* @param string|null $propertyPath |
856
|
|
|
* @param string $encoding |
857
|
|
|
* @return Assert |
858
|
|
|
* @throws AssertionFailedException |
859
|
|
|
*/ |
860
|
|
|
public function length($length, $message = null, $propertyPath = null, $encoding = 'utf8') |
861
|
|
|
{ |
862
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
863
|
|
|
{ |
864
|
|
|
return $this; |
865
|
|
|
} |
866
|
|
|
$this->string($message, $propertyPath); |
867
|
|
|
if ( mb_strlen($this->value, $encoding) !== $length ) |
868
|
|
|
{ |
869
|
|
|
$message = sprintf( |
870
|
|
|
$message ?: 'Value "%s" has to be %d exactly characters long, but length is %d.', |
871
|
|
|
$this->stringify($this->value), |
872
|
|
|
$length, |
873
|
|
|
mb_strlen($this->value, $encoding) |
874
|
|
|
); |
875
|
|
|
$constraints = ['length' => $length, 'encoding' => $encoding]; |
876
|
|
|
throw $this->createException($message, self::INVALID_LENGTH, $propertyPath, $constraints); |
877
|
|
|
} |
878
|
|
|
return $this; |
879
|
|
|
} |
880
|
|
|
|
881
|
|
|
/** |
882
|
|
|
* Assert that a string is at least $minLength chars long. |
883
|
|
|
* |
884
|
|
|
* @param int $minLength |
885
|
|
|
* @param string|null $message |
886
|
|
|
* @param string|null $propertyPath |
887
|
|
|
* @param string $encoding |
888
|
|
|
* @return Assert |
889
|
|
|
* @throws AssertionFailedException |
890
|
|
|
*/ |
891
|
|
|
public function minLength($minLength, $message = null, $propertyPath = null, $encoding = 'utf8') |
892
|
|
|
{ |
893
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
894
|
|
|
{ |
895
|
|
|
return $this; |
896
|
|
|
} |
897
|
|
|
$this->string($message, $propertyPath); |
898
|
|
|
if ( mb_strlen($this->value, $encoding) < $minLength ) |
899
|
|
|
{ |
900
|
|
|
$message = sprintf( |
901
|
|
|
$message |
902
|
|
|
?: 'Value "%s" is too short, it should have more than %d characters, but only has %d characters.', |
903
|
|
|
$this->stringify($this->value), |
904
|
|
|
$minLength, |
905
|
|
|
mb_strlen($this->value, $encoding) |
906
|
|
|
); |
907
|
|
|
$constraints = ['min_length' => $minLength, 'encoding' => $encoding]; |
908
|
|
|
throw $this->createException($message, self::INVALID_MIN_LENGTH, $propertyPath, $constraints); |
909
|
|
|
} |
910
|
|
|
return $this; |
911
|
|
|
} |
912
|
|
|
|
913
|
|
|
/** |
914
|
|
|
* Assert that string value is not longer than $maxLength chars. |
915
|
|
|
* |
916
|
|
|
* @param integer $maxLength |
917
|
|
|
* @param string|null $message |
918
|
|
|
* @param string|null $propertyPath |
919
|
|
|
* @param string $encoding |
920
|
|
|
* @return Assert |
921
|
|
|
* @throws AssertionFailedException |
922
|
|
|
*/ |
923
|
|
|
public function maxLength($maxLength, $message = null, $propertyPath = null, $encoding = 'utf8') |
924
|
|
|
{ |
925
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
926
|
|
|
{ |
927
|
|
|
return $this; |
928
|
|
|
} |
929
|
|
|
$this->string($message, $propertyPath); |
930
|
|
|
if ( mb_strlen($this->value, $encoding) > $maxLength ) |
931
|
|
|
{ |
932
|
|
|
$message = sprintf( |
933
|
|
|
$message ?: 'Value "%s" is too long, it should have no more than %d characters, but has %d characters.', |
934
|
|
|
$this->stringify($this->value), |
935
|
|
|
$maxLength, |
936
|
|
|
mb_strlen($this->value, $encoding) |
937
|
|
|
); |
938
|
|
|
$constraints = ['max_length' => $maxLength, 'encoding' => $encoding]; |
939
|
|
|
throw $this->createException($message, self::INVALID_MAX_LENGTH, $propertyPath, $constraints); |
940
|
|
|
} |
941
|
|
|
return $this; |
942
|
|
|
} |
943
|
|
|
|
944
|
|
|
/** |
945
|
|
|
* Assert that string length is between min,max lengths. |
946
|
|
|
* |
947
|
|
|
* @param integer $minLength |
948
|
|
|
* @param integer $maxLength |
949
|
|
|
* @param string|null $message |
950
|
|
|
* @param string|null $propertyPath |
951
|
|
|
* @param string $encoding |
952
|
|
|
* @return Assert |
953
|
|
|
* @throws AssertionFailedException |
954
|
|
|
*/ |
955
|
|
|
public function betweenLength($minLength, $maxLength, $message = null, $propertyPath = null, $encoding = 'utf8') |
956
|
|
|
{ |
957
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
958
|
|
|
{ |
959
|
|
|
return $this; |
960
|
|
|
} |
961
|
|
|
$this->string($message, $propertyPath); |
962
|
|
|
if ( mb_strlen($this->value, $encoding) < $minLength ) |
963
|
|
|
{ |
964
|
|
|
$message = sprintf( |
965
|
|
|
$message |
966
|
|
|
?: 'Value "%s" is too short, it should have more than %d characters, but only has %d characters.', |
967
|
|
|
$this->stringify($this->value), |
968
|
|
|
$minLength, |
969
|
|
|
mb_strlen($this->value, $encoding) |
970
|
|
|
); |
971
|
|
|
$constraints = ['min_length' => $minLength, 'encoding' => $encoding]; |
972
|
|
|
throw $this->createException($message, self::INVALID_MIN_LENGTH, $propertyPath, $constraints); |
973
|
|
|
} |
974
|
|
|
if ( mb_strlen($this->value, $encoding) > $maxLength ) |
975
|
|
|
{ |
976
|
|
|
$message = sprintf( |
977
|
|
|
$message ?: 'Value "%s" is too long, it should have no more than %d characters, but has %d characters.', |
978
|
|
|
$this->stringify($this->value), |
979
|
|
|
$maxLength, |
980
|
|
|
mb_strlen($this->value, $encoding) |
981
|
|
|
); |
982
|
|
|
$constraints = ['max_length' => $maxLength, 'encoding' => $encoding]; |
983
|
|
|
throw $this->createException($message, self::INVALID_MAX_LENGTH, $propertyPath, $constraints); |
984
|
|
|
} |
985
|
|
|
return $this; |
986
|
|
|
} |
987
|
|
|
|
988
|
|
|
/** |
989
|
|
|
* Assert that string starts with a sequence of chars. |
990
|
|
|
* |
991
|
|
|
* @param string $needle |
992
|
|
|
* @param string|null $message |
993
|
|
|
* @param string|null $propertyPath |
994
|
|
|
* @param string $encoding |
995
|
|
|
* @return Assert |
996
|
|
|
* @throws AssertionFailedException |
997
|
|
|
*/ |
998
|
|
View Code Duplication |
public function startsWith($needle, $message = null, $propertyPath = null, $encoding = 'utf8') |
|
|
|
|
999
|
|
|
{ |
1000
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1001
|
|
|
{ |
1002
|
|
|
return $this; |
1003
|
|
|
} |
1004
|
|
|
$this->string($message, $propertyPath); |
1005
|
|
|
if ( mb_strpos($this->value, $needle, null, $encoding) !== 0 ) |
1006
|
|
|
{ |
1007
|
|
|
$message = sprintf( |
1008
|
|
|
$message ?: 'Value "%s" does not start with "%s".', |
1009
|
|
|
$this->stringify($this->value), |
1010
|
|
|
$this->stringify($needle) |
1011
|
|
|
); |
1012
|
|
|
$constraints = ['needle' => $needle, 'encoding' => $encoding]; |
1013
|
|
|
throw $this->createException($message, self::INVALID_STRING_START, $propertyPath, $constraints); |
1014
|
|
|
} |
1015
|
|
|
return $this; |
1016
|
|
|
} |
1017
|
|
|
|
1018
|
|
|
/** |
1019
|
|
|
* Assert that string ends with a sequence of chars. |
1020
|
|
|
* |
1021
|
|
|
* @param string $needle |
1022
|
|
|
* @param string|null $message |
1023
|
|
|
* @param string|null $propertyPath |
1024
|
|
|
* @param string $encoding |
1025
|
|
|
* @return Assert |
1026
|
|
|
* @throws AssertionFailedException |
1027
|
|
|
*/ |
1028
|
|
|
public function endsWith($needle, $message = null, $propertyPath = null, $encoding = 'utf8') |
1029
|
|
|
{ |
1030
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1031
|
|
|
{ |
1032
|
|
|
return $this; |
1033
|
|
|
} |
1034
|
|
|
$this->string($message, $propertyPath); |
1035
|
|
|
$stringPosition = mb_strlen($this->value, $encoding) - mb_strlen($needle, $encoding); |
1036
|
|
|
if ( mb_strripos($this->value, $needle, null, $encoding) !== $stringPosition ) |
1037
|
|
|
{ |
1038
|
|
|
$message = sprintf( |
1039
|
|
|
$message ?: 'Value "%s" does not end with "%s".', |
1040
|
|
|
$this->stringify($this->value), |
1041
|
|
|
$this->stringify($needle) |
1042
|
|
|
); |
1043
|
|
|
$constraints = ['needle' => $needle, 'encoding' => $encoding]; |
1044
|
|
|
throw $this->createException($message, self::INVALID_STRING_END, $propertyPath, $constraints); |
1045
|
|
|
} |
1046
|
|
|
return $this; |
1047
|
|
|
} |
1048
|
|
|
|
1049
|
|
|
/** |
1050
|
|
|
* Assert that string contains a sequence of chars. |
1051
|
|
|
* |
1052
|
|
|
* @param string $needle |
1053
|
|
|
* @param string|null $message |
1054
|
|
|
* @param string|null $propertyPath |
1055
|
|
|
* @param string $encoding |
1056
|
|
|
* @return Assert |
1057
|
|
|
* @throws AssertionFailedException |
1058
|
|
|
*/ |
1059
|
|
View Code Duplication |
public function contains($needle, $message = null, $propertyPath = null, $encoding = 'utf8') |
|
|
|
|
1060
|
|
|
{ |
1061
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1062
|
|
|
{ |
1063
|
|
|
return $this; |
1064
|
|
|
} |
1065
|
|
|
$this->string($message, $propertyPath); |
1066
|
|
|
if ( mb_strpos($this->value, $needle, null, $encoding) === false ) |
1067
|
|
|
{ |
1068
|
|
|
$message = sprintf( |
1069
|
|
|
$message ?: 'Value "%s" does not contain "%s".', |
1070
|
|
|
$this->stringify($this->value), |
1071
|
|
|
$this->stringify($needle) |
1072
|
|
|
); |
1073
|
|
|
$constraints = ['needle' => $needle, 'encoding' => $encoding]; |
1074
|
|
|
throw $this->createException($message, self::INVALID_STRING_CONTAINS, $propertyPath, $constraints); |
1075
|
|
|
} |
1076
|
|
|
return $this; |
1077
|
|
|
} |
1078
|
|
|
|
1079
|
|
|
/** |
1080
|
|
|
* Assert that value is in array of choices. |
1081
|
|
|
* |
1082
|
|
|
* @param array $choices |
1083
|
|
|
* @param string|null $message |
1084
|
|
|
* @param string|null $propertyPath |
1085
|
|
|
* @return Assert |
1086
|
|
|
* @throws AssertionFailedException |
1087
|
|
|
*/ |
1088
|
|
|
public function choice(array $choices, $message = null, $propertyPath = null) |
1089
|
|
|
{ |
1090
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1091
|
|
|
{ |
1092
|
|
|
return $this; |
1093
|
|
|
} |
1094
|
|
|
if ( !in_array($this->value, $choices, true) ) |
1095
|
|
|
{ |
1096
|
|
|
$message = sprintf( |
1097
|
|
|
$message ?: 'Value "%s" is not an element of the valid values: %s', |
1098
|
|
|
$this->stringify($this->value), |
1099
|
|
|
implode(", ", array_map('Terah\Assert\Assert::stringify', $choices)) |
1100
|
|
|
); |
1101
|
|
|
throw $this->createException($message, self::INVALID_CHOICE, $propertyPath, ['choices' => $choices]); |
1102
|
|
|
} |
1103
|
|
|
return $this; |
1104
|
|
|
} |
1105
|
|
|
|
1106
|
|
|
/** |
1107
|
|
|
* Alias of {@see choice()} |
1108
|
|
|
* |
1109
|
|
|
* @throws AssertionFailedException |
1110
|
|
|
* |
1111
|
|
|
* @param array $choices |
1112
|
|
|
* @param string|null $message |
1113
|
|
|
* @param string|null $propertyPath |
1114
|
|
|
* @return $this |
1115
|
|
|
*/ |
1116
|
|
|
public function inArray(array $choices, $message = null, $propertyPath = null) |
1117
|
|
|
{ |
1118
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1119
|
|
|
{ |
1120
|
|
|
return $this; |
1121
|
|
|
} |
1122
|
|
|
$this->choice($choices, $message, $propertyPath); |
1123
|
|
|
return $this; |
1124
|
|
|
} |
1125
|
|
|
|
1126
|
|
|
/** |
1127
|
|
|
* Assert that value is numeric. |
1128
|
|
|
* |
1129
|
|
|
* @param string|null $message |
1130
|
|
|
* @param string|null $propertyPath |
1131
|
|
|
* @return Assert |
1132
|
|
|
* @throws AssertionFailedException |
1133
|
|
|
*/ |
1134
|
|
|
public function numeric($message = null, $propertyPath = null) |
1135
|
|
|
{ |
1136
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1137
|
|
|
{ |
1138
|
|
|
return $this; |
1139
|
|
|
} |
1140
|
|
|
if ( ! is_numeric($this->value) ) |
1141
|
|
|
{ |
1142
|
|
|
$message = sprintf( |
1143
|
|
|
$message ?: 'Value "%s" is not numeric.', |
1144
|
|
|
$this->stringify($this->value) |
1145
|
|
|
); |
1146
|
|
|
throw $this->createException($message, self::INVALID_NUMERIC, $propertyPath); |
1147
|
|
|
} |
1148
|
|
|
return $this; |
1149
|
|
|
} |
1150
|
|
|
|
1151
|
|
|
/** |
1152
|
|
|
* @param string|null $message |
1153
|
|
|
* @param string|null $propertyPath |
1154
|
|
|
* @return Assert |
1155
|
|
|
* @throws AssertionFailedException |
1156
|
|
|
*/ |
1157
|
|
|
public function nonEmptyArray($message = null, $propertyPath = null) |
1158
|
|
|
{ |
1159
|
|
|
$message = $message ?: 'Value "%s" is not a non-empty array.'; |
1160
|
|
|
return $this->isArray($message, $propertyPath)->notEmpty($message, $propertyPath); |
1161
|
|
|
} |
1162
|
|
|
|
1163
|
|
|
/** |
1164
|
|
|
* @param string|null $message |
1165
|
|
|
* @param string|null $propertyPath |
1166
|
|
|
* @return Assert |
1167
|
|
|
* @throws AssertionFailedException |
1168
|
|
|
*/ |
1169
|
|
|
public function nonEmptyInt($message = null, $propertyPath = null) |
1170
|
|
|
{ |
1171
|
|
|
$message = $message ?: 'Value "%s" is not a non-empty integer.'; |
1172
|
|
|
return $this->integer($message, $propertyPath)->notEmpty($message, $propertyPath); |
1173
|
|
|
} |
1174
|
|
|
|
1175
|
|
|
/** |
1176
|
|
|
* @param string|null $message |
1177
|
|
|
* @param string|null $propertyPath |
1178
|
|
|
* @return Assert |
1179
|
|
|
* @throws AssertionFailedException |
1180
|
|
|
*/ |
1181
|
|
|
public function nonEmptyString($message = null, $propertyPath = null) |
1182
|
|
|
{ |
1183
|
|
|
$message = $message ?: 'Value "%s" is not a non-empty string.'; |
1184
|
|
|
return $this->integer($message, $propertyPath)->notEmpty($message, $propertyPath); |
1185
|
|
|
} |
1186
|
|
|
|
1187
|
|
|
/** |
1188
|
|
|
* Assert that value is an array. |
1189
|
|
|
* |
1190
|
|
|
* @param string|null $message |
1191
|
|
|
* @param string|null $propertyPath |
1192
|
|
|
* @return Assert |
1193
|
|
|
* @throws AssertionFailedException |
1194
|
|
|
*/ |
1195
|
|
|
public function isArray($message = null, $propertyPath = null) |
1196
|
|
|
{ |
1197
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1198
|
|
|
{ |
1199
|
|
|
return $this; |
1200
|
|
|
} |
1201
|
|
|
if ( !is_array($this->value) ) |
1202
|
|
|
{ |
1203
|
|
|
$message = sprintf( |
1204
|
|
|
$message ?: 'Value "%s" is not an array.', |
1205
|
|
|
$this->stringify($this->value) |
1206
|
|
|
); |
1207
|
|
|
throw $this->createException($message, self::INVALID_ARRAY, $propertyPath); |
1208
|
|
|
} |
1209
|
|
|
return $this; |
1210
|
|
|
} |
1211
|
|
|
|
1212
|
|
|
/** |
1213
|
|
|
* Assert that value is an array or a traversable object. |
1214
|
|
|
* |
1215
|
|
|
* @param string|null $message |
1216
|
|
|
* @param string|null $propertyPath |
1217
|
|
|
* @return Assert |
1218
|
|
|
* @throws AssertionFailedException |
1219
|
|
|
*/ |
1220
|
|
|
public function isTraversable($message = null, $propertyPath = null) |
1221
|
|
|
{ |
1222
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1223
|
|
|
{ |
1224
|
|
|
return $this; |
1225
|
|
|
} |
1226
|
|
|
if ( !is_array($this->value) && !$this->value instanceof \Traversable ) |
1227
|
|
|
{ |
1228
|
|
|
$message = sprintf( |
1229
|
|
|
$message ?: 'Value "%s" is not an array and does not implement Traversable.', |
1230
|
|
|
$this->stringify($this->value) |
1231
|
|
|
); |
1232
|
|
|
throw $this->createException($message, self::INVALID_TRAVERSABLE, $propertyPath); |
1233
|
|
|
} |
1234
|
|
|
return $this; |
1235
|
|
|
} |
1236
|
|
|
|
1237
|
|
|
/** |
1238
|
|
|
* Assert that value is an array or an array-accessible object. |
1239
|
|
|
* |
1240
|
|
|
* @param string|null $message |
1241
|
|
|
* @param string|null $propertyPath |
1242
|
|
|
* @return Assert |
1243
|
|
|
* @throws AssertionFailedException |
1244
|
|
|
*/ |
1245
|
|
|
public function isArrayAccessible($message = null, $propertyPath = null) |
1246
|
|
|
{ |
1247
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1248
|
|
|
{ |
1249
|
|
|
return $this; |
1250
|
|
|
} |
1251
|
|
|
if ( !is_array($this->value) && !$this->value instanceof \ArrayAccess ) |
1252
|
|
|
{ |
1253
|
|
|
$message = sprintf( |
1254
|
|
|
$message ?: 'Value "%s" is not an array and does not implement ArrayAccess.', |
1255
|
|
|
$this->stringify($this->value) |
1256
|
|
|
); |
1257
|
|
|
throw $this->createException($message, self::INVALID_ARRAY_ACCESSIBLE, $propertyPath); |
1258
|
|
|
} |
1259
|
|
|
return $this; |
1260
|
|
|
} |
1261
|
|
|
|
1262
|
|
|
/** |
1263
|
|
|
* Assert that key exists in an array |
1264
|
|
|
* |
1265
|
|
|
* @param string|integer $key |
1266
|
|
|
* @param string|null $message |
1267
|
|
|
* @param string|null $propertyPath |
1268
|
|
|
* @return Assert |
1269
|
|
|
* @throws AssertionFailedException |
1270
|
|
|
*/ |
1271
|
|
|
public function keyExists($key, $message = null, $propertyPath = null) |
1272
|
|
|
{ |
1273
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1274
|
|
|
{ |
1275
|
|
|
return $this; |
1276
|
|
|
} |
1277
|
|
|
$this->isArray($message, $propertyPath); |
1278
|
|
|
if ( !array_key_exists($key, $this->value) ) |
1279
|
|
|
{ |
1280
|
|
|
$message = sprintf( |
1281
|
|
|
$message ?: 'Array does not contain an element with key "%s"', |
1282
|
|
|
$this->stringify($key) |
1283
|
|
|
); |
1284
|
|
|
throw $this->createException($message, self::INVALID_KEY_EXISTS, $propertyPath, ['key' => $key]); |
1285
|
|
|
} |
1286
|
|
|
return $this; |
1287
|
|
|
} |
1288
|
|
|
|
1289
|
|
|
/** |
1290
|
|
|
* Assert that keys exist in array |
1291
|
|
|
* |
1292
|
|
|
* @param array $keys |
1293
|
|
|
* @param string|null $message |
1294
|
|
|
* @param string|null $propertyPath |
1295
|
|
|
* @return Assert |
1296
|
|
|
* @throws AssertionFailedException |
1297
|
|
|
*/ |
1298
|
|
View Code Duplication |
public function keysExist($keys, $message = null, $propertyPath = null) |
|
|
|
|
1299
|
|
|
{ |
1300
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1301
|
|
|
{ |
1302
|
|
|
return $this; |
1303
|
|
|
} |
1304
|
|
|
$this->isArray($message, $propertyPath); |
1305
|
|
|
foreach ( $keys as $key ) |
1306
|
|
|
{ |
1307
|
|
|
if ( !array_key_exists($key, $this->value) ) |
1308
|
|
|
{ |
1309
|
|
|
$message = $message |
1310
|
|
|
?: sprintf( |
1311
|
|
|
'Array does not contain an element with key "%s"', |
1312
|
|
|
$this->stringify($key) |
1313
|
|
|
); |
1314
|
|
|
throw $this->createException($message, self::INVALID_KEYS_EXIST, $propertyPath, ['key' => $key]); |
1315
|
|
|
} |
1316
|
|
|
} |
1317
|
|
|
return $this; |
1318
|
|
|
} |
1319
|
|
|
|
1320
|
|
|
/** |
1321
|
|
|
* Assert that property exists in array |
1322
|
|
|
* |
1323
|
|
|
* @param string|integer $key |
1324
|
|
|
* @param string|null $message |
1325
|
|
|
* @param string|null $propertyPath |
1326
|
|
|
* @return Assert |
1327
|
|
|
* @throws AssertionFailedException |
1328
|
|
|
*/ |
1329
|
|
View Code Duplication |
public function propertyExists($key, $message = null, $propertyPath = null) |
|
|
|
|
1330
|
|
|
{ |
1331
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1332
|
|
|
{ |
1333
|
|
|
return $this; |
1334
|
|
|
} |
1335
|
|
|
$this->isObject($message, $propertyPath); |
1336
|
|
|
if ( !property_exists($this->value, $key) && !isset( $this->value->{$key} ) ) |
1337
|
|
|
{ |
1338
|
|
|
$message = $message |
1339
|
|
|
?: sprintf( |
1340
|
|
|
'Object does not contain a property with key "%s"', |
1341
|
|
|
$this->stringify($key) |
1342
|
|
|
); |
1343
|
|
|
throw $this->createException($message, self::INVALID_PROPERTY_EXISTS, $propertyPath, ['key' => $key]); |
1344
|
|
|
} |
1345
|
|
|
return $this; |
1346
|
|
|
} |
1347
|
|
|
|
1348
|
|
|
/** |
1349
|
|
|
* Assert that properties exists in array |
1350
|
|
|
* |
1351
|
|
|
* @param array $keys |
1352
|
|
|
* @param string|null $message |
1353
|
|
|
* @param string|null $propertyPath |
1354
|
|
|
* @return Assert |
1355
|
|
|
* @throws AssertionFailedException |
1356
|
|
|
*/ |
1357
|
|
View Code Duplication |
public function propertiesExist(array $keys, $message = null, $propertyPath = null) |
|
|
|
|
1358
|
|
|
{ |
1359
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1360
|
|
|
{ |
1361
|
|
|
return $this; |
1362
|
|
|
} |
1363
|
|
|
$this->isObject($message, $propertyPath); |
1364
|
|
|
foreach ( $keys as $key ) |
1365
|
|
|
{ |
1366
|
|
|
// Using isset to allow resolution of magically defined properties |
1367
|
|
|
if ( !property_exists($this->value, $key) && !isset( $this->value->{$key} ) ) |
1368
|
|
|
{ |
1369
|
|
|
$message = $message |
1370
|
|
|
?: sprintf( |
1371
|
|
|
'Object does not contain a property with key "%s"', |
1372
|
|
|
$this->stringify($key) |
1373
|
|
|
); |
1374
|
|
|
throw $this->createException($message, self::INVALID_PROPERTIES_EXIST, $propertyPath, ['key' => $key]); |
1375
|
|
|
} |
1376
|
|
|
} |
1377
|
|
|
return $this; |
1378
|
|
|
} |
1379
|
|
|
|
1380
|
|
|
/** |
1381
|
|
|
* Assert that string is valid utf8 |
1382
|
|
|
* |
1383
|
|
|
* @param string|null $message |
1384
|
|
|
* @param string|null $propertyPath |
1385
|
|
|
* @return Assert |
1386
|
|
|
* @throws AssertionFailedException |
1387
|
|
|
*/ |
1388
|
|
|
public function utf8($message = null, $propertyPath = null) |
1389
|
|
|
{ |
1390
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1391
|
|
|
{ |
1392
|
|
|
return $this; |
1393
|
|
|
} |
1394
|
|
|
$this->string($message, $propertyPath); |
1395
|
|
|
if ( mb_detect_encoding($this->value, 'UTF-8', true) !== 'UTF-8' ) |
1396
|
|
|
{ |
1397
|
|
|
$message = $message |
1398
|
|
|
?: sprintf( |
1399
|
|
|
'Value "%s" was expected to be a valid UTF8 string', |
1400
|
|
|
$this->stringify($this->value) |
1401
|
|
|
); |
1402
|
|
|
throw $this->createException($message, self::INVALID_UTF8, $propertyPath); |
1403
|
|
|
} |
1404
|
|
|
return $this; |
1405
|
|
|
} |
1406
|
|
|
|
1407
|
|
|
|
1408
|
|
|
/** |
1409
|
|
|
* Assert that string is valid utf8 |
1410
|
|
|
* |
1411
|
|
|
* @param string|null $message |
1412
|
|
|
* @param string|null $propertyPath |
1413
|
|
|
* @return Assert |
1414
|
|
|
* @throws AssertionFailedException |
1415
|
|
|
*/ |
1416
|
|
View Code Duplication |
public function ascii($message = null, $propertyPath = null) |
|
|
|
|
1417
|
|
|
{ |
1418
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1419
|
|
|
{ |
1420
|
|
|
return $this; |
1421
|
|
|
} |
1422
|
|
|
$this->string($message, $propertyPath); |
1423
|
|
|
if ( ! preg_match('/^[ -~]+$/', $this->value) ) |
1424
|
|
|
{ |
1425
|
|
|
$message = $message |
1426
|
|
|
?: sprintf( |
1427
|
|
|
'Value "%s" was expected to be a valid ASCII string', |
1428
|
|
|
$this->stringify($this->value) |
1429
|
|
|
); |
1430
|
|
|
throw $this->createException($message, self::INVALID_ASCII, $propertyPath); |
1431
|
|
|
} |
1432
|
|
|
return $this; |
1433
|
|
|
} |
1434
|
|
|
|
1435
|
|
|
/** |
1436
|
|
|
* Assert that key exists in an array/array-accessible object using isset() |
1437
|
|
|
* |
1438
|
|
|
* @param string|integer $key |
1439
|
|
|
* @param string|null $message |
1440
|
|
|
* @param string|null $propertyPath |
1441
|
|
|
* @return Assert |
1442
|
|
|
* @throws AssertionFailedException |
1443
|
|
|
*/ |
1444
|
|
|
public function keyIsset($key, $message = null, $propertyPath = null) |
1445
|
|
|
{ |
1446
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1447
|
|
|
{ |
1448
|
|
|
return $this; |
1449
|
|
|
} |
1450
|
|
|
$this->isArrayAccessible($message, $propertyPath); |
1451
|
|
|
if ( !isset( $this->value[$key] ) ) |
1452
|
|
|
{ |
1453
|
|
|
$message = sprintf( |
1454
|
|
|
$message ?: 'The element with key "%s" was not found', |
1455
|
|
|
$this->stringify($key) |
1456
|
|
|
); |
1457
|
|
|
throw $this->createException($message, self::INVALID_KEY_ISSET, $propertyPath, ['key' => $key]); |
1458
|
|
|
} |
1459
|
|
|
return $this; |
1460
|
|
|
} |
1461
|
|
|
|
1462
|
|
|
/** |
1463
|
|
|
* Assert that key exists in an array/array-accessible object and it's value is not empty. |
1464
|
|
|
* |
1465
|
|
|
* @param string|integer $key |
1466
|
|
|
* @param string|null $message |
1467
|
|
|
* @param string|null $propertyPath |
1468
|
|
|
* @return Assert |
1469
|
|
|
* @throws AssertionFailedException |
1470
|
|
|
*/ |
1471
|
|
|
public function notEmptyKey($key, $message = null, $propertyPath = null) |
1472
|
|
|
{ |
1473
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1474
|
|
|
{ |
1475
|
|
|
return $this; |
1476
|
|
|
} |
1477
|
|
|
$this->keyIsset($key, $message, $propertyPath); |
1478
|
|
|
(new Assert($this->value[$key]))->setExceptionClass($this->exceptionClass)->notEmpty($message, $propertyPath); |
1479
|
|
|
return $this; |
1480
|
|
|
} |
1481
|
|
|
|
1482
|
|
|
/** |
1483
|
|
|
* Assert that value is not blank |
1484
|
|
|
* |
1485
|
|
|
* @param string|null $message |
1486
|
|
|
* @param string|null $propertyPath |
1487
|
|
|
* @return Assert |
1488
|
|
|
* @throws AssertionFailedException |
1489
|
|
|
*/ |
1490
|
|
View Code Duplication |
public function notBlank($message = null, $propertyPath = null) |
|
|
|
|
1491
|
|
|
{ |
1492
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1493
|
|
|
{ |
1494
|
|
|
return $this; |
1495
|
|
|
} |
1496
|
|
|
if ( false === $this->value || ( empty( $this->value ) && '0' != $this->value ) ) |
1497
|
|
|
{ |
1498
|
|
|
$message = sprintf( |
1499
|
|
|
$message ?: 'Value "%s" is blank, but was expected to contain a value.', |
1500
|
|
|
$this->stringify($this->value) |
1501
|
|
|
); |
1502
|
|
|
throw $this->createException($message, self::INVALID_NOT_BLANK, $propertyPath); |
1503
|
|
|
} |
1504
|
|
|
return $this; |
1505
|
|
|
} |
1506
|
|
|
|
1507
|
|
|
/** |
1508
|
|
|
* Assert that value is instance of given class-name. |
1509
|
|
|
* |
1510
|
|
|
* @param string $className |
1511
|
|
|
* @param string|null $message |
1512
|
|
|
* @param string|null $propertyPath |
1513
|
|
|
* @return Assert |
1514
|
|
|
* @throws AssertionFailedException |
1515
|
|
|
*/ |
1516
|
|
|
public function isInstanceOf($className, $message = null, $propertyPath = null) |
1517
|
|
|
{ |
1518
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1519
|
|
|
{ |
1520
|
|
|
return $this; |
1521
|
|
|
} |
1522
|
|
|
if ( !( $this->value instanceof $className ) ) |
1523
|
|
|
{ |
1524
|
|
|
$message = sprintf( |
1525
|
|
|
$message ?: 'Class "%s" was expected to be instanceof of "%s" but is not.', |
1526
|
|
|
$this->stringify($this->value), |
1527
|
|
|
$className |
1528
|
|
|
); |
1529
|
|
|
throw $this->createException($message, self::INVALID_INSTANCE_OF, $propertyPath, ['class' => $className]); |
1530
|
|
|
} |
1531
|
|
|
return $this; |
1532
|
|
|
} |
1533
|
|
|
|
1534
|
|
|
/** |
1535
|
|
|
* Assert that value is not instance of given class-name. |
1536
|
|
|
* |
1537
|
|
|
* @param string $className |
1538
|
|
|
* @param string|null $message |
1539
|
|
|
* @param string|null $propertyPath |
1540
|
|
|
* @return Assert |
1541
|
|
|
* @throws AssertionFailedException |
1542
|
|
|
*/ |
1543
|
|
|
public function notIsInstanceOf($className, $message = null, $propertyPath = null) |
1544
|
|
|
{ |
1545
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1546
|
|
|
{ |
1547
|
|
|
return $this; |
1548
|
|
|
} |
1549
|
|
|
if ( $this->value instanceof $className ) |
1550
|
|
|
{ |
1551
|
|
|
$message = sprintf( |
1552
|
|
|
$message ?: 'Class "%s" was not expected to be instanceof of "%s".', |
1553
|
|
|
$this->stringify($this->value), |
1554
|
|
|
$className |
1555
|
|
|
); |
1556
|
|
|
throw $this->createException($message, self::INVALID_NOT_INSTANCE_OF, $propertyPath, ['class' => $className]); |
1557
|
|
|
} |
1558
|
|
|
return $this; |
1559
|
|
|
} |
1560
|
|
|
|
1561
|
|
|
/** |
1562
|
|
|
* Assert that value is subclass of given class-name. |
1563
|
|
|
* |
1564
|
|
|
* @param string $className |
1565
|
|
|
* @param string|null $message |
1566
|
|
|
* @param string|null $propertyPath |
1567
|
|
|
* @return Assert |
1568
|
|
|
* @throws AssertionFailedException |
1569
|
|
|
*/ |
1570
|
|
|
public function subclassOf($className, $message = null, $propertyPath = null) |
1571
|
|
|
{ |
1572
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1573
|
|
|
{ |
1574
|
|
|
return $this; |
1575
|
|
|
} |
1576
|
|
|
if ( !is_subclass_of($this->value, $className) ) |
1577
|
|
|
{ |
1578
|
|
|
$message = sprintf( |
1579
|
|
|
$message ?: 'Class "%s" was expected to be subclass of "%s".', |
1580
|
|
|
$this->stringify($this->value), |
1581
|
|
|
$className |
1582
|
|
|
); |
1583
|
|
|
throw $this->createException($message, self::INVALID_SUBCLASS_OF, $propertyPath, ['class' => $className]); |
1584
|
|
|
} |
1585
|
|
|
return $this; |
1586
|
|
|
} |
1587
|
|
|
|
1588
|
|
|
/** |
1589
|
|
|
* Assert that value is in range of numbers. |
1590
|
|
|
* |
1591
|
|
|
* @param integer $minValue |
1592
|
|
|
* @param integer $maxValue |
1593
|
|
|
* @param string|null $message |
1594
|
|
|
* @param string|null $propertyPath |
1595
|
|
|
* @return Assert |
1596
|
|
|
* @throws AssertionFailedException |
1597
|
|
|
*/ |
1598
|
|
|
public function range($minValue, $maxValue, $message = null, $propertyPath = null) |
1599
|
|
|
{ |
1600
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1601
|
|
|
{ |
1602
|
|
|
return $this; |
1603
|
|
|
} |
1604
|
|
|
$this->numeric($message, $propertyPath); |
1605
|
|
|
if ( $this->value < $minValue || $this->value > $maxValue ) |
1606
|
|
|
{ |
1607
|
|
|
$message = sprintf( |
1608
|
|
|
$message ?: 'Number "%s" was expected to be at least "%d" and at most "%d".', |
1609
|
|
|
$this->stringify($this->value), |
1610
|
|
|
$this->stringify($minValue), |
1611
|
|
|
$this->stringify($maxValue) |
1612
|
|
|
); |
1613
|
|
|
throw $this->createException($message, self::INVALID_RANGE, $propertyPath, [ |
1614
|
|
|
'min' => $minValue, |
1615
|
|
|
'max' => $maxValue |
1616
|
|
|
]); |
1617
|
|
|
} |
1618
|
|
|
return $this; |
1619
|
|
|
} |
1620
|
|
|
|
1621
|
|
|
/** |
1622
|
|
|
* Assert that a value is at least as big as a given limit |
1623
|
|
|
* |
1624
|
|
|
* @param mixed $minValue |
1625
|
|
|
* @param string|null $message |
1626
|
|
|
* @param string|null $propertyPath |
1627
|
|
|
* @return Assert |
1628
|
|
|
* @throws AssertionFailedException |
1629
|
|
|
*/ |
1630
|
|
|
public function min($minValue, $message = null, $propertyPath = null) |
1631
|
|
|
{ |
1632
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1633
|
|
|
{ |
1634
|
|
|
return $this; |
1635
|
|
|
} |
1636
|
|
|
$this->numeric($message, $propertyPath); |
1637
|
|
|
if ( $this->value < $minValue ) |
1638
|
|
|
{ |
1639
|
|
|
$message = sprintf( |
1640
|
|
|
$message ?: 'Number "%s" was expected to be at least "%d".', |
1641
|
|
|
$this->stringify($this->value), |
1642
|
|
|
$this->stringify($minValue) |
1643
|
|
|
); |
1644
|
|
|
throw $this->createException($message, self::INVALID_MIN, $propertyPath, ['min' => $minValue]); |
1645
|
|
|
} |
1646
|
|
|
return $this; |
1647
|
|
|
} |
1648
|
|
|
|
1649
|
|
|
/** |
1650
|
|
|
* Assert that a number is smaller as a given limit |
1651
|
|
|
* |
1652
|
|
|
* @param mixed $maxValue |
1653
|
|
|
* @param string|null $message |
1654
|
|
|
* @param string|null $propertyPath |
1655
|
|
|
* @return Assert |
1656
|
|
|
* @throws AssertionFailedException |
1657
|
|
|
*/ |
1658
|
|
|
public function max($maxValue, $message = null, $propertyPath = null) |
1659
|
|
|
{ |
1660
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1661
|
|
|
{ |
1662
|
|
|
return $this; |
1663
|
|
|
} |
1664
|
|
|
$this->numeric($message, $propertyPath); |
1665
|
|
|
if ( $this->value > $maxValue ) |
1666
|
|
|
{ |
1667
|
|
|
$message = sprintf( |
1668
|
|
|
$message ?: 'Number "%s" was expected to be at most "%d".', |
1669
|
|
|
$this->stringify($this->value), |
1670
|
|
|
$this->stringify($maxValue) |
1671
|
|
|
); |
1672
|
|
|
throw $this->createException($message, self::INVALID_MAX, $propertyPath, ['max' => $maxValue]); |
1673
|
|
|
} |
1674
|
|
|
return $this; |
1675
|
|
|
} |
1676
|
|
|
|
1677
|
|
|
/** |
1678
|
|
|
* Assert that a file exists |
1679
|
|
|
* |
1680
|
|
|
* @param string|null $message |
1681
|
|
|
* @param string|null $propertyPath |
1682
|
|
|
* @return Assert |
1683
|
|
|
* @throws AssertionFailedException |
1684
|
|
|
*/ |
1685
|
|
|
public function file($message = null, $propertyPath = null) |
1686
|
|
|
{ |
1687
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1688
|
|
|
{ |
1689
|
|
|
return $this; |
1690
|
|
|
} |
1691
|
|
|
$this->string($message, $propertyPath); |
1692
|
|
|
$this->notEmpty($message, $propertyPath); |
1693
|
|
|
if ( !is_file($this->value) ) |
1694
|
|
|
{ |
1695
|
|
|
$message = sprintf( |
1696
|
|
|
$message ?: 'File "%s" was expected to exist.', |
1697
|
|
|
$this->stringify($this->value) |
1698
|
|
|
); |
1699
|
|
|
throw $this->createException($message, self::INVALID_FILE, $propertyPath); |
1700
|
|
|
} |
1701
|
|
|
return $this; |
1702
|
|
|
} |
1703
|
|
|
|
1704
|
|
|
/** |
1705
|
|
|
* @param string|null $message |
1706
|
|
|
* @param string|null $propertyPath |
1707
|
|
|
* @return $this |
1708
|
|
|
* @throws AssertionFailedException |
1709
|
|
|
*/ |
1710
|
|
|
public function fileExists($message = null, $propertyPath = null) |
1711
|
|
|
{ |
1712
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1713
|
|
|
{ |
1714
|
|
|
return $this; |
1715
|
|
|
} |
1716
|
|
|
$this->string($message, $propertyPath); |
1717
|
|
|
$this->notEmpty($message, $propertyPath); |
1718
|
|
|
if ( ! file_exists($this->value) ) |
1719
|
|
|
{ |
1720
|
|
|
$message = sprintf( |
1721
|
|
|
$message ?: 'File or directory "%s" was expected to exist.', |
1722
|
|
|
$this->stringify($this->value) |
1723
|
|
|
); |
1724
|
|
|
throw $this->createException($message, self::INVALID_FILE_OR_DIR, $propertyPath); |
1725
|
|
|
} |
1726
|
|
|
return $this; |
1727
|
|
|
} |
1728
|
|
|
|
1729
|
|
|
/** |
1730
|
|
|
* Assert that a directory exists |
1731
|
|
|
* |
1732
|
|
|
* @param string|null $message |
1733
|
|
|
* @param string|null $propertyPath |
1734
|
|
|
* @return Assert |
1735
|
|
|
* @throws AssertionFailedException |
1736
|
|
|
*/ |
1737
|
|
View Code Duplication |
public function directory($message = null, $propertyPath = null) |
|
|
|
|
1738
|
|
|
{ |
1739
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1740
|
|
|
{ |
1741
|
|
|
return $this; |
1742
|
|
|
} |
1743
|
|
|
$this->string($message, $propertyPath); |
1744
|
|
|
if ( !is_dir($this->value) ) |
1745
|
|
|
{ |
1746
|
|
|
$message = sprintf( |
1747
|
|
|
$message ?: 'Path "%s" was expected to be a directory.', |
1748
|
|
|
$this->stringify($this->value) |
1749
|
|
|
); |
1750
|
|
|
throw $this->createException($message, self::INVALID_DIRECTORY, $propertyPath); |
1751
|
|
|
} |
1752
|
|
|
return $this; |
1753
|
|
|
} |
1754
|
|
|
|
1755
|
|
|
/** |
1756
|
|
|
* Assert that the value is something readable |
1757
|
|
|
* |
1758
|
|
|
* @param string|null $message |
1759
|
|
|
* @param string|null $propertyPath |
1760
|
|
|
* @return Assert |
1761
|
|
|
* @throws AssertionFailedException |
1762
|
|
|
*/ |
1763
|
|
View Code Duplication |
public function readable($message = null, $propertyPath = null) |
|
|
|
|
1764
|
|
|
{ |
1765
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1766
|
|
|
{ |
1767
|
|
|
return $this; |
1768
|
|
|
} |
1769
|
|
|
$this->string($message, $propertyPath); |
1770
|
|
|
if ( !is_readable($this->value) ) |
1771
|
|
|
{ |
1772
|
|
|
$message = sprintf( |
1773
|
|
|
$message ?: 'Path "%s" was expected to be readable.', |
1774
|
|
|
$this->stringify($this->value) |
1775
|
|
|
); |
1776
|
|
|
throw $this->createException($message, self::INVALID_READABLE, $propertyPath); |
1777
|
|
|
} |
1778
|
|
|
return $this; |
1779
|
|
|
} |
1780
|
|
|
|
1781
|
|
|
/** |
1782
|
|
|
* Assert that the value is something writeable |
1783
|
|
|
* |
1784
|
|
|
* @param string|null $message |
1785
|
|
|
* @param string|null $propertyPath |
1786
|
|
|
* @return Assert |
1787
|
|
|
* @throws AssertionFailedException |
1788
|
|
|
*/ |
1789
|
|
View Code Duplication |
public function writeable($message = null, $propertyPath = null) |
|
|
|
|
1790
|
|
|
{ |
1791
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1792
|
|
|
{ |
1793
|
|
|
return $this; |
1794
|
|
|
} |
1795
|
|
|
$this->string($message, $propertyPath); |
1796
|
|
|
if ( !is_writeable($this->value) ) |
1797
|
|
|
{ |
1798
|
|
|
$message = sprintf( |
1799
|
|
|
$message ?: 'Path "%s" was expected to be writeable.', |
1800
|
|
|
$this->stringify($this->value) |
1801
|
|
|
); |
1802
|
|
|
throw $this->createException($message, self::INVALID_WRITEABLE, $propertyPath); |
1803
|
|
|
} |
1804
|
|
|
return $this; |
1805
|
|
|
} |
1806
|
|
|
|
1807
|
|
|
/** |
1808
|
|
|
* Assert that value is an email adress (using |
1809
|
|
|
* input_filter/FILTER_VALIDATE_EMAIL). |
1810
|
|
|
* |
1811
|
|
|
* @param string|null $message |
1812
|
|
|
* @param string|null $propertyPath |
1813
|
|
|
* @return Assert |
1814
|
|
|
* @throws AssertionFailedException |
1815
|
|
|
*/ |
1816
|
|
|
public function email($message = null, $propertyPath = null) |
1817
|
|
|
{ |
1818
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1819
|
|
|
{ |
1820
|
|
|
return $this; |
1821
|
|
|
} |
1822
|
|
|
$this->string($message, $propertyPath); |
1823
|
|
|
if ( ! filter_var($this->value, FILTER_VALIDATE_EMAIL) ) |
1824
|
|
|
{ |
1825
|
|
|
$message = sprintf( |
1826
|
|
|
$message ?: 'Value "%s" was expected to be a valid e-mail address.', |
1827
|
|
|
$this->stringify($this->value) |
1828
|
|
|
); |
1829
|
|
|
throw $this->createException($message, self::INVALID_EMAIL, $propertyPath); |
1830
|
|
|
} |
1831
|
|
|
else |
1832
|
|
|
{ |
1833
|
|
|
$host = substr($this->value, strpos($this->value, '@') + 1); |
1834
|
|
|
// Likely not a FQDN, bug in PHP FILTER_VALIDATE_EMAIL prior to PHP 5.3.3 |
1835
|
|
|
if ( version_compare(PHP_VERSION, '5.3.3', '<') && strpos($host, '.') === false ) |
1836
|
|
|
{ |
1837
|
|
|
$message = sprintf( |
1838
|
|
|
$message ?: 'Value "%s" was expected to be a valid e-mail address.', |
1839
|
|
|
$this->stringify($this->value) |
1840
|
|
|
); |
1841
|
|
|
throw $this->createException($message, self::INVALID_EMAIL, $propertyPath); |
1842
|
|
|
} |
1843
|
|
|
} |
1844
|
|
|
return $this; |
1845
|
|
|
} |
1846
|
|
|
|
1847
|
|
|
/** |
1848
|
|
|
* @param null $message |
1849
|
|
|
* @param null $propertyPath |
1850
|
|
|
* @return Assert |
1851
|
|
|
* @throws AssertionFailedException |
1852
|
|
|
*/ |
1853
|
|
|
public function emailPrefix($message = null, $propertyPath = null) |
1854
|
|
|
{ |
1855
|
|
|
$this->value($this->value . '@example.com'); |
1856
|
|
|
return $this->email($message, $propertyPath); |
1857
|
|
|
} |
1858
|
|
|
|
1859
|
|
|
/** |
1860
|
|
|
* Assert that value is an URL. |
1861
|
|
|
* |
1862
|
|
|
* This code snipped was taken from the Symfony project and modified to the special demands of this method. |
1863
|
|
|
* |
1864
|
|
|
* @param string|null $message |
1865
|
|
|
* @param string|null $propertyPath |
1866
|
|
|
* @return Assert |
1867
|
|
|
* @throws AssertionFailedException |
1868
|
|
|
* |
1869
|
|
|
* |
1870
|
|
|
* @link https://github.com/symfony/Validator/blob/master/Constraints/UrlValidator.php |
1871
|
|
|
* @link https://github.com/symfony/Validator/blob/master/Constraints/Url.php |
1872
|
|
|
*/ |
1873
|
|
|
public function url($message = null, $propertyPath = null) |
1874
|
|
|
{ |
1875
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1876
|
|
|
{ |
1877
|
|
|
return $this; |
1878
|
|
|
} |
1879
|
|
|
$this->string($message, $propertyPath); |
1880
|
|
|
$protocols = ['http', 'https']; |
1881
|
|
|
$pattern = '~^ |
1882
|
|
|
(%s):// # protocol |
1883
|
|
|
( |
1884
|
|
|
([\pL\pN\pS-]+\.)+[\pL]+ # a domain name |
1885
|
|
|
| # or |
1886
|
|
|
\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} # a IP address |
1887
|
|
|
| # or |
1888
|
|
|
\[ |
1889
|
|
|
(?:(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){6})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:::(?:(?:(?:[0-9a-f]{1,4})):){5})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){4})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,1}(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){3})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,2}(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){2})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,3}(?:(?:[0-9a-f]{1,4})))?::(?:(?:[0-9a-f]{1,4})):)(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,4}(?:(?:[0-9a-f]{1,4})))?::)(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,5}(?:(?:[0-9a-f]{1,4})))?::)(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,6}(?:(?:[0-9a-f]{1,4})))?::)))) |
1890
|
|
|
\] # a IPv6 address |
1891
|
|
|
) |
1892
|
|
|
(:[0-9]+)? # a port (optional) |
1893
|
|
|
(/?|/\S+) # a /, nothing or a / with something |
1894
|
|
|
$~ixu'; |
1895
|
|
|
$pattern = sprintf($pattern, implode('|', $protocols)); |
1896
|
|
|
if ( !preg_match($pattern, $this->value) ) |
1897
|
|
|
{ |
1898
|
|
|
$message = sprintf( |
1899
|
|
|
$message ?: 'Value "%s" was expected to be a valid URL starting with http or https', |
1900
|
|
|
$this->stringify($this->value) |
1901
|
|
|
); |
1902
|
|
|
throw $this->createException($message, self::INVALID_URL, $propertyPath); |
1903
|
|
|
} |
1904
|
|
|
return $this; |
1905
|
|
|
} |
1906
|
|
|
|
1907
|
|
|
/** |
1908
|
|
|
* Assert that value is domain name. |
1909
|
|
|
* |
1910
|
|
|
* This code snipped was taken from the Symfony project and modified to the special demands of this method. |
1911
|
|
|
* |
1912
|
|
|
* @param string|null $message |
1913
|
|
|
* @param string|null $propertyPath |
1914
|
|
|
* @return Assert |
1915
|
|
|
* @throws AssertionFailedException |
1916
|
|
|
* |
1917
|
|
|
*/ |
1918
|
|
|
public function domainName($message = null, $propertyPath = null) |
1919
|
|
|
{ |
1920
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1921
|
|
|
{ |
1922
|
|
|
return $this; |
1923
|
|
|
} |
1924
|
|
|
$this->string($message, $propertyPath); |
1925
|
|
|
$pattern = '/^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6}$/'; |
1926
|
|
|
if ( ! preg_match($pattern, $this->value) ) |
1927
|
|
|
{ |
1928
|
|
|
$message = sprintf( |
1929
|
|
|
$message ?: 'Value "%s" was expected to be a valid domain name', |
1930
|
|
|
$this->stringify($this->value) |
1931
|
|
|
); |
1932
|
|
|
throw $this->createException($message, self::INVALID_DOMAIN_NAME, $propertyPath); |
1933
|
|
|
} |
1934
|
|
|
return $this; |
1935
|
|
|
} |
1936
|
|
|
|
1937
|
|
|
/** |
1938
|
|
|
* Assert that value is alphanumeric. |
1939
|
|
|
* |
1940
|
|
|
* @param string|null $message |
1941
|
|
|
* @param string|null $propertyPath |
1942
|
|
|
* @return Assert |
1943
|
|
|
* @throws AssertionFailedException |
1944
|
|
|
*/ |
1945
|
|
View Code Duplication |
public function alnum($message = null, $propertyPath = null) |
|
|
|
|
1946
|
|
|
{ |
1947
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1948
|
|
|
{ |
1949
|
|
|
return $this; |
1950
|
|
|
} |
1951
|
|
|
try |
1952
|
|
|
{ |
1953
|
|
|
$this->regex('(^([a-zA-Z]{1}[a-zA-Z0-9]*)$)', $message, $propertyPath); |
1954
|
|
|
} |
1955
|
|
|
catch (AssertionFailedException $e) |
1956
|
|
|
{ |
1957
|
|
|
$message = sprintf( |
1958
|
|
|
$message |
1959
|
|
|
?: 'Value "%s" is not alphanumeric, starting with letters and containing only letters and numbers.', |
1960
|
|
|
$this->stringify($this->value) |
1961
|
|
|
); |
1962
|
|
|
throw $this->createException($message, self::INVALID_ALNUM, $propertyPath); |
1963
|
|
|
} |
1964
|
|
|
return $this; |
1965
|
|
|
} |
1966
|
|
|
|
1967
|
|
|
/** |
1968
|
|
|
* Assert that the value is boolean True. |
1969
|
|
|
* |
1970
|
|
|
* @param string|null $message |
1971
|
|
|
* @param string|null $propertyPath |
1972
|
|
|
* @return Assert |
1973
|
|
|
* @throws AssertionFailedException |
1974
|
|
|
*/ |
1975
|
|
|
public function true($message = null, $propertyPath = null) |
1976
|
|
|
{ |
1977
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
1978
|
|
|
{ |
1979
|
|
|
return $this; |
1980
|
|
|
} |
1981
|
|
|
if ( $this->value !== true ) |
1982
|
|
|
{ |
1983
|
|
|
$message = sprintf( |
1984
|
|
|
$message ?: 'Value "%s" is not TRUE.', |
1985
|
|
|
$this->stringify($this->value) |
1986
|
|
|
); |
1987
|
|
|
throw $this->createException($message, self::INVALID_TRUE, $propertyPath); |
1988
|
|
|
} |
1989
|
|
|
return $this; |
1990
|
|
|
} |
1991
|
|
|
|
1992
|
|
|
/** |
1993
|
|
|
* Assert that the value is boolean True. |
1994
|
|
|
* |
1995
|
|
|
* @param string|null $message |
1996
|
|
|
* @param string|null $propertyPath |
1997
|
|
|
* @return Assert |
1998
|
|
|
* @throws AssertionFailedException |
1999
|
|
|
*/ |
2000
|
|
|
public function truthy($message = null, $propertyPath = null) |
2001
|
|
|
{ |
2002
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
2003
|
|
|
{ |
2004
|
|
|
return $this; |
2005
|
|
|
} |
2006
|
|
|
if ( ! $this->value ) |
2007
|
|
|
{ |
2008
|
|
|
$message = sprintf( |
2009
|
|
|
$message ?: 'Value "%s" is not truthy.', |
2010
|
|
|
$this->stringify($this->value) |
2011
|
|
|
); |
2012
|
|
|
throw $this->createException($message, self::INVALID_TRUE, $propertyPath); |
2013
|
|
|
} |
2014
|
|
|
return $this; |
2015
|
|
|
} |
2016
|
|
|
|
2017
|
|
|
/** |
2018
|
|
|
* Assert that the value is boolean False. |
2019
|
|
|
* |
2020
|
|
|
* @param string|null $message |
2021
|
|
|
* @param string|null $propertyPath |
2022
|
|
|
* @return Assert |
2023
|
|
|
* @throws AssertionFailedException |
2024
|
|
|
*/ |
2025
|
|
|
public function false($message = null, $propertyPath = null) |
2026
|
|
|
{ |
2027
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
2028
|
|
|
{ |
2029
|
|
|
return $this; |
2030
|
|
|
} |
2031
|
|
|
if ( $this->value !== false ) |
2032
|
|
|
{ |
2033
|
|
|
$message = sprintf( |
2034
|
|
|
$message ?: 'Value "%s" is not FALSE.', |
2035
|
|
|
$this->stringify($this->value) |
2036
|
|
|
); |
2037
|
|
|
throw $this->createException($message, self::INVALID_FALSE, $propertyPath); |
2038
|
|
|
} |
2039
|
|
|
return $this; |
2040
|
|
|
} |
2041
|
|
|
|
2042
|
|
|
/** |
2043
|
|
|
* Assert that the value is not boolean False. |
2044
|
|
|
* |
2045
|
|
|
* @param string|null $message |
2046
|
|
|
* @param string|null $propertyPath |
2047
|
|
|
* @return Assert |
2048
|
|
|
* @throws AssertionFailedException |
2049
|
|
|
*/ |
2050
|
|
|
public function notFalse($message = null, $propertyPath = null) |
2051
|
|
|
{ |
2052
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
2053
|
|
|
{ |
2054
|
|
|
return $this; |
2055
|
|
|
} |
2056
|
|
|
if ( $this->value === false ) |
2057
|
|
|
{ |
2058
|
|
|
$message = sprintf( |
2059
|
|
|
$message ?: 'Value "%s" is not FALSE.', |
2060
|
|
|
$this->stringify($this->value) |
2061
|
|
|
); |
2062
|
|
|
throw $this->createException($message, self::INVALID_NOT_FALSE, $propertyPath); |
2063
|
|
|
} |
2064
|
|
|
return $this; |
2065
|
|
|
} |
2066
|
|
|
|
2067
|
|
|
/** |
2068
|
|
|
* Assert that the class exists. |
2069
|
|
|
* |
2070
|
|
|
* @param string|null $message |
2071
|
|
|
* @param string|null $propertyPath |
2072
|
|
|
* @return Assert |
2073
|
|
|
* @throws AssertionFailedException |
2074
|
|
|
*/ |
2075
|
|
|
public function classExists($message = null, $propertyPath = null) |
2076
|
|
|
{ |
2077
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
2078
|
|
|
{ |
2079
|
|
|
return $this; |
2080
|
|
|
} |
2081
|
|
|
if ( !class_exists($this->value) ) |
2082
|
|
|
{ |
2083
|
|
|
$message = sprintf( |
2084
|
|
|
$message ?: 'Class "%s" does not exist.', |
2085
|
|
|
$this->stringify($this->value) |
2086
|
|
|
); |
2087
|
|
|
throw $this->createException($message, self::INVALID_CLASS, $propertyPath); |
2088
|
|
|
} |
2089
|
|
|
return $this; |
2090
|
|
|
} |
2091
|
|
|
|
2092
|
|
|
/** |
2093
|
|
|
* Assert that the class implements the interface |
2094
|
|
|
* |
2095
|
|
|
* @param string $interfaceName |
2096
|
|
|
* @param string|null $message |
2097
|
|
|
* @param string|null $propertyPath |
2098
|
|
|
* @return Assert |
2099
|
|
|
* @throws AssertionFailedException |
2100
|
|
|
*/ |
2101
|
|
|
public function implementsInterface($interfaceName, $message = null, $propertyPath = null) |
2102
|
|
|
{ |
2103
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
2104
|
|
|
{ |
2105
|
|
|
return $this; |
2106
|
|
|
} |
2107
|
|
|
$reflection = new \ReflectionClass($this->value); |
2108
|
|
|
if ( !$reflection->implementsInterface($interfaceName) ) |
2109
|
|
|
{ |
2110
|
|
|
$message = sprintf( |
2111
|
|
|
$message ?: 'Class "%s" does not implement interface "%s".', |
2112
|
|
|
$this->stringify($this->value), |
2113
|
|
|
$this->stringify($interfaceName) |
2114
|
|
|
); |
2115
|
|
|
throw $this->createException($message, self::INTERFACE_NOT_IMPLEMENTED, $propertyPath, ['interface' => $interfaceName]); |
2116
|
|
|
} |
2117
|
|
|
return $this; |
2118
|
|
|
} |
2119
|
|
|
|
2120
|
|
|
/** |
2121
|
|
|
* Assert that the given string is a valid json string. |
2122
|
|
|
* |
2123
|
|
|
* NOTICE: |
2124
|
|
|
* Since this does a json_decode to determine its validity |
2125
|
|
|
* you probably should consider, when using the variable |
2126
|
|
|
* content afterwards, just to decode and check for yourself instead |
2127
|
|
|
* of using this assertion. |
2128
|
|
|
* |
2129
|
|
|
* @param string|null $message |
2130
|
|
|
* @param string|null $propertyPath |
2131
|
|
|
* @return Assert |
2132
|
|
|
* @throws AssertionFailedException |
2133
|
|
|
*/ |
2134
|
|
|
public function isJsonString($message = null, $propertyPath = null) |
2135
|
|
|
{ |
2136
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
2137
|
|
|
{ |
2138
|
|
|
return $this; |
2139
|
|
|
} |
2140
|
|
|
if ( null === json_decode($this->value) && JSON_ERROR_NONE !== json_last_error() ) |
2141
|
|
|
{ |
2142
|
|
|
$message = sprintf( |
2143
|
|
|
$message ?: 'Value "%s" is not a valid JSON string.', |
2144
|
|
|
$this->stringify($this->value) |
2145
|
|
|
); |
2146
|
|
|
throw $this->createException($message, self::INVALID_JSON_STRING, $propertyPath); |
2147
|
|
|
} |
2148
|
|
|
return $this; |
2149
|
|
|
} |
2150
|
|
|
|
2151
|
|
|
/** |
2152
|
|
|
* Assert that the given string is a valid UUID |
2153
|
|
|
* |
2154
|
|
|
* Uses code from {@link https://github.com/ramsey/uuid} that is MIT licensed. |
2155
|
|
|
* |
2156
|
|
|
* @param string|null $message |
2157
|
|
|
* @param string|null $propertyPath |
2158
|
|
|
* @return Assert |
2159
|
|
|
* @throws AssertionFailedException |
2160
|
|
|
*/ |
2161
|
|
|
public function uuid($message = null, $propertyPath = null) |
2162
|
|
|
{ |
2163
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
2164
|
|
|
{ |
2165
|
|
|
return $this; |
2166
|
|
|
} |
2167
|
|
|
$this->value = str_replace(['urn:', 'uuid:', '{', '}'], '', $this->value); |
2168
|
|
|
if ( $this->value === '00000000-0000-0000-0000-000000000000' ) |
2169
|
|
|
{ |
2170
|
|
|
return $this; |
2171
|
|
|
} |
2172
|
|
|
if ( !preg_match('/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/', $this->value) ) |
2173
|
|
|
{ |
2174
|
|
|
$message = sprintf( |
2175
|
|
|
$message ?: 'Value "%s" is not a valid UUID.', |
2176
|
|
|
$this->stringify($this->value) |
2177
|
|
|
); |
2178
|
|
|
throw $this->createException($message, self::INVALID_UUID, $propertyPath); |
2179
|
|
|
} |
2180
|
|
|
return $this; |
2181
|
|
|
} |
2182
|
|
|
|
2183
|
|
|
/** |
2184
|
|
|
* Assert that the count of countable is equal to count. |
2185
|
|
|
* |
2186
|
|
|
* @param int $count |
2187
|
|
|
* @param string $message |
2188
|
|
|
* @param string $propertyPath |
2189
|
|
|
* @return Assert |
2190
|
|
|
* @throws AssertionFailedException |
2191
|
|
|
*/ |
2192
|
|
|
public function count($count, $message = null, $propertyPath = null) |
2193
|
|
|
{ |
2194
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
2195
|
|
|
{ |
2196
|
|
|
return $this; |
2197
|
|
|
} |
2198
|
|
|
if ( $count !== count($this->value) ) |
2199
|
|
|
{ |
2200
|
|
|
$message = sprintf( |
2201
|
|
|
$message ?: 'List does not contain exactly "%d" elements.', |
2202
|
|
|
$this->stringify($this->value), |
2203
|
|
|
$this->stringify($count) |
2204
|
|
|
); |
2205
|
|
|
throw $this->createException($message, self::INVALID_COUNT, $propertyPath, ['count' => $count]); |
2206
|
|
|
} |
2207
|
|
|
return $this; |
2208
|
|
|
} |
2209
|
|
|
|
2210
|
|
|
/** |
2211
|
|
|
* @param $func |
2212
|
|
|
* @param $args |
2213
|
|
|
* @return bool |
2214
|
|
|
* @throws AssertionFailedException |
2215
|
|
|
*/ |
2216
|
|
|
protected function doAllOrNullOr($func, $args) |
2217
|
|
|
{ |
2218
|
|
|
if ( $this->nullOr && is_null($this->value) ) |
2219
|
|
|
{ |
2220
|
|
|
return true; |
2221
|
|
|
} |
2222
|
|
|
if ( $this->emptyOr && empty($this->value) ) |
2223
|
|
|
{ |
2224
|
|
|
return true; |
2225
|
|
|
} |
2226
|
|
|
if ( $this->all && (new Assert($this->value))->setExceptionClass($this->exceptionClass)->isTraversable() ) |
2227
|
|
|
{ |
2228
|
|
|
foreach ( $this->value as $idx => $value ) |
2229
|
|
|
{ |
2230
|
|
|
$object = (new Assert($value))->setExceptionClass($this->exceptionClass); |
2231
|
|
|
call_user_func_array([$object, $func], $args); |
2232
|
|
|
} |
2233
|
|
|
return true; |
2234
|
|
|
} |
2235
|
|
|
return ( $this->nullOr && is_null($this->value) ) || ( $this->emptyOr && empty($this->value) ) ? true : false; |
2236
|
|
|
} |
2237
|
|
|
|
2238
|
|
|
/** |
2239
|
|
|
* Determines if the values array has every choice as key and that this choice has content. |
2240
|
|
|
* |
2241
|
|
|
* @param array $choices |
2242
|
|
|
* @param string|null $message |
2243
|
|
|
* @param string|null $propertyPath |
2244
|
|
|
* @return $this |
2245
|
|
|
*/ |
2246
|
|
|
public function choicesNotEmpty(array $choices, $message = null, $propertyPath = null) |
2247
|
|
|
{ |
2248
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
2249
|
|
|
{ |
2250
|
|
|
return $this; |
2251
|
|
|
} |
2252
|
|
|
$this->notEmpty($message, $propertyPath); |
2253
|
|
|
foreach ( $choices as $choice ) |
2254
|
|
|
{ |
2255
|
|
|
$this->notEmptyKey($choice, $message, $propertyPath); |
2256
|
|
|
} |
2257
|
|
|
return $this; |
2258
|
|
|
} |
2259
|
|
|
|
2260
|
|
|
/** |
2261
|
|
|
* Determines that the named method is defined in the provided object. |
2262
|
|
|
* |
2263
|
|
|
* @param mixed $object |
2264
|
|
|
* @param string|null $message |
2265
|
|
|
* @param string|null $propertyPath |
2266
|
|
|
* @returns Assert |
2267
|
|
|
* @throws |
2268
|
|
|
*/ |
2269
|
|
View Code Duplication |
public function methodExists($object, $message = null, $propertyPath = null) |
|
|
|
|
2270
|
|
|
{ |
2271
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
2272
|
|
|
{ |
2273
|
|
|
return $this; |
2274
|
|
|
} |
2275
|
|
|
(new Assert($object))->setExceptionClass($this->exceptionClass)->isObject($message, $propertyPath); |
2276
|
|
|
if ( !method_exists($object, $this->value) ) |
2277
|
|
|
{ |
2278
|
|
|
$message = sprintf( |
2279
|
|
|
$message ?: 'Expected "%s" does not a exist in provided object.', |
2280
|
|
|
$this->stringify($this->value) |
2281
|
|
|
); |
2282
|
|
|
throw $this->createException($message, self::INVALID_METHOD, $propertyPath); |
2283
|
|
|
} |
2284
|
|
|
return $this; |
2285
|
|
|
} |
2286
|
|
|
|
2287
|
|
|
/** |
2288
|
|
|
* Determines that the provided value is an object. |
2289
|
|
|
* |
2290
|
|
|
* @param string|null $message |
2291
|
|
|
* @param string|null $propertyPath |
2292
|
|
|
* @return $this |
2293
|
|
|
* @throws AssertionFailedException |
2294
|
|
|
*/ |
2295
|
|
|
public function isObject($message = null, $propertyPath = null) |
2296
|
|
|
{ |
2297
|
|
|
if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) ) |
2298
|
|
|
{ |
2299
|
|
|
return $this; |
2300
|
|
|
} |
2301
|
|
|
if ( !is_object($this->value) ) |
2302
|
|
|
{ |
2303
|
|
|
$message = sprintf( |
2304
|
|
|
$message ?: 'Provided "%s" is not a valid object.', |
2305
|
|
|
$this->stringify($this->value) |
2306
|
|
|
); |
2307
|
|
|
throw $this->createException($message, self::INVALID_OBJECT, $propertyPath); |
2308
|
|
|
} |
2309
|
|
|
return $this; |
2310
|
|
|
} |
2311
|
|
|
|
2312
|
|
|
/** |
2313
|
|
|
* Make a string version of a value. |
2314
|
|
|
* |
2315
|
|
|
* @param $value |
2316
|
|
|
* @return string |
2317
|
|
|
*/ |
2318
|
|
|
private function stringify($value) |
2319
|
|
|
{ |
2320
|
|
|
if ( is_bool($value) ) |
2321
|
|
|
{ |
2322
|
|
|
return $value ? '<TRUE>' : '<FALSE>'; |
2323
|
|
|
} |
2324
|
|
|
if ( is_scalar($value) ) |
2325
|
|
|
{ |
2326
|
|
|
$val = (string)$value; |
2327
|
|
|
if ( strlen($val) > 100 ) |
2328
|
|
|
{ |
2329
|
|
|
$val = substr($val, 0, 97) . '...'; |
2330
|
|
|
} |
2331
|
|
|
return $val; |
2332
|
|
|
} |
2333
|
|
|
if ( is_array($value) ) |
2334
|
|
|
{ |
2335
|
|
|
return '<ARRAY>'; |
2336
|
|
|
} |
2337
|
|
|
if ( is_object($value) ) |
2338
|
|
|
{ |
2339
|
|
|
return get_class($value); |
2340
|
|
|
} |
2341
|
|
|
if ( is_resource($value) ) |
2342
|
|
|
{ |
2343
|
|
|
return '<RESOURCE>'; |
2344
|
|
|
} |
2345
|
|
|
if ( $value === null ) |
2346
|
|
|
{ |
2347
|
|
|
return '<NULL>'; |
2348
|
|
|
} |
2349
|
|
|
return 'unknown'; |
2350
|
|
|
} |
2351
|
|
|
} |
2352
|
|
|
|
2353
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.