Completed
Push — master ( 8f4851...229728 )
by Terry
04:10
created

Assert   D

Complexity

Total Complexity 508

Size/Duplication

Total Lines 2543
Duplicated Lines 15.26 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 388
loc 2543
rs 4.4102
c 0
b 0
f 0
wmc 508
lcom 1
cbo 1

99 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B that() 22 22 5
A reset() 0 4 1
A value() 0 5 1
A nullOr() 0 5 1
A emptyOr() 0 5 1
A all() 0 5 1
A createException() 0 8 3
A setExceptionClass() 0 5 1
A code() 0 5 1
A level() 0 5 1
A error() 0 5 1
A name() 0 5 1
B eq() 10 18 6
B greaterThan() 10 18 6
B greaterThanOrEq() 10 18 6
B lessThan() 10 18 6
B lessThanOrEq() 10 18 6
B same() 10 18 6
B notEq() 10 18 6
B isCallable() 0 17 6
B notSame() 10 18 6
A id() 0 6 3
A unsignedInt() 0 7 3
A flag() 0 6 3
A status() 0 6 3
A nullOrId() 0 4 1
A allIds() 0 4 1
A int() 0 4 1
B integer() 0 17 6
B float() 0 17 6
B digit() 0 17 6
B date() 0 18 6
B integerish() 0 17 9
B boolean() 0 17 6
B scalar() 0 17 6
B notEmpty() 17 17 8
B noContent() 0 17 6
B notNull() 0 17 6
B string() 0 18 6
B regex() 9 18 6
B ipAddress() 0 19 6
B notRegex() 9 18 6
B length() 0 21 6
B minLength() 0 22 6
B maxLength() 0 21 6
D betweenLength() 0 34 10
B startsWith() 20 20 6
B endsWith() 0 21 6
B contains() 20 20 6
B choice() 0 18 6
A inArray() 0 9 2
B numeric() 0 17 6
A nonEmptyArray() 0 5 2
A nonEmptyInt() 0 5 2
A nonEmptyString() 0 5 2
B isArray() 0 17 6
B isTraversable() 0 17 7
B isArrayAccessible() 0 17 7
B keyExists() 0 18 6
B keysExist() 0 21 6
B propertyExists() 0 18 6
C propertiesExist() 0 22 7
B utf8() 18 18 5
B ascii() 18 18 5
B keyIsset() 0 18 6
A notEmptyKey() 0 10 2
B notBlank() 17 17 8
B isInstanceOf() 10 18 6
B notIsInstanceOf() 10 18 6
B subclassOf() 10 18 6
C range() 0 23 7
B min() 10 19 6
B max() 10 19 6
B file() 0 19 6
B fileExists() 0 19 6
B directory() 18 18 6
B readable() 18 18 6
B writeable() 18 18 6
C email() 0 32 11
A emailPrefix() 0 5 1
B url() 0 34 6
B domainName() 0 19 6
B ausMobile() 22 22 6
B alnum() 22 22 6
B true() 0 18 6
B truthy() 0 17 6
B false() 0 17 6
B notFalse() 0 17 6
B classExists() 0 17 6
B implementsInterface() 0 19 5
B isJsonString() 0 17 7
C uuid() 0 22 7
B count() 10 18 6
C doAllOrNullOr() 0 21 12
A choicesNotEmpty() 0 13 3
B methodExists() 0 18 6
B isObject() 0 17 6
D stringify() 0 33 9

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Assert often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Assert, and based on these observations, apply Extract Interface, too.

1
<?php declare(strict_types=1);
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
    const INVALID_IP_ADDRESS            = 313;
93
    const INVALID_AUS_MOBILE            = 314;
94
95
    const EMERGENCY                     = 'emergency';
96
    const ALERT                         = 'alert';
97
    const CRITICAL                      = 'critical';
98
    const ERROR                         = 'error';
99
    const WARNING                       = 'warning';
100
    const NOTICE                        = 'notice';
101
    const INFO                          = 'info';
102
    const DEBUG                         = 'debug';
103
104
    /** @var bool */
105
    protected $nullOr                   = false;
106
107
    /** @var bool */
108
    protected $emptyOr                  = false;
109
110
    /** @var mixed */
111
    protected $value                    = null;
112
113
    /** @var bool */
114
    protected $all                      = false;
115
116
    /** @var null|string */
117
    protected $propertyPath             = null;
118
119
    /** @var null|string */
120
    protected $level                    = 'critical';
121
122
    /** @var int */
123
    protected $overrideCode             = null;
124
125
    /** @var string */
126
    protected $overrideError            = '';
127
    /**
128
     * Exception to throw when an assertion failed.
129
     *
130
     * @var string
131
     */
132
    protected $exceptionClass           = 'Terah\Assert\AssertionFailedException';
133
134
    /**
135
     * @param mixed $value
136
     */
137
    public function __construct($value)
138
    {
139
        $this->value($value);
140
    }
141
142
    /**
143
     * @param        $value
144
     * @param string $name
145
     * @param int    $code
146
     * @param string $error
147
     * @param string $level
148
     * @return Assert
149
     */
150 View Code Duplication
    public static function that($value, $name='', $code=0, $error='', $level=Assert::WARNING)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
151
    {
152
        $assert = new static($value);
153
        if ( $name )
154
        {
155
            $assert->name($name);
156
        }
157
        if ( $code )
158
        {
159
            $assert->code($code);
160
        }
161
        if ( $error )
162
        {
163
            $assert->error($error);
164
        }
165
        if ( $level )
166
        {
167
            $assert->level($level);
168
        }
169
170
        return $assert;
171
    }
172
173
    /**
174
     * @param mixed $value
175
     * @return Assert
176
     */
177
    public function reset($value)
178
    {
179
        return $this->all(false)->nullOr(false)->value($value);
180
    }
181
182
    /**
183
     * @param mixed $value
184
     * @return Assert
185
     */
186
    public function value($value)
187
    {
188
        $this->value = $value;
189
        return $this;
190
    }
191
192
    /**
193
     * @param bool $nullOr
194
     * @return Assert
195
     */
196
    public function nullOr($nullOr = true)
197
    {
198
        $this->nullOr = $nullOr;
199
        return $this;
200
    }
201
202
    /**
203
     * @param bool $emptyOr
204
     * @return Assert
205
     */
206
    public function emptyOr($emptyOr = true)
207
    {
208
        $this->emptyOr = $emptyOr;
209
        return $this;
210
    }
211
212
    /**
213
     * @param bool $all
214
     * @return Assert
215
     */
216
    public function all($all = true)
217
    {
218
        $this->all = $all;
219
        return $this;
220
    }
221
222
    /**
223
     * Helper method that handles building the assertion failure exceptions.
224
     * They are returned from this method so that the stack trace still shows
225
     * the assertions method.
226
     *
227
     * @param string $message
228
     * @param int    $code
229
     * @param string $propertyPath
230
     * @param array  $constraints
231
     * @param string $level
232
     * @return AssertionFailedException
233
     */
234
    protected function createException($message, $code, $propertyPath, array $constraints = [], $level=null)
235
    {
236
        $exceptionClass = $this->exceptionClass;
237
        $propertyPath   = is_null($propertyPath) ? $this->propertyPath : $propertyPath;
238
        $level          = is_null($level) ? $this->level : $level;
239
240
        return new $exceptionClass($message, $code, $propertyPath, $this->value, $constraints, $level);
241
    }
242
243
    /**
244
     * @param $exceptionClass
245
     * @return Assert
246
     */
247
    public function setExceptionClass($exceptionClass)
248
    {
249
        $this->exceptionClass = $exceptionClass;
250
        return $this;
251
    }
252
253
    /**
254
     * @param int $code
255
     * @return Assert
256
     */
257
    public function code($code)
258
    {
259
        $this->overrideCode = $code;
260
        return $this;
261
    }
262
263
    /**
264
     * @param int $level
265
     * @return Assert
266
     */
267
    public function level($level)
268
    {
269
        $this->level = $level;
0 ignored issues
show
Documentation Bug introduced by
It seems like $level of type integer is incompatible with the declared type null|string of property $level.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
270
        return $this;
271
    }
272
273
    /**
274
     * @param string $error
275
     * @return Assert
276
     */
277
    public function error($error)
278
    {
279
        $this->overrideError = $error;
280
        return $this;
281
    }
282
283
    /**
284
     * @param string $name
285
     * @return Assert
286
     */
287
    public function name($name)
288
    {
289
        $this->propertyPath = $name;
290
        return $this;
291
    }
292
293
    /**
294
     * Assert that two values are equal (using == ).
295
     *
296
     * @param mixed       $value2
297
     * @param string|null $message
298
     * @param string|null $propertyPath
299
     * @return Assert
300
     * @throws AssertionFailedException
301
     */
302
    public function eq($value2, $message = null, $propertyPath = null)
303
    {
304
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
305
        {
306
            return $this;
307
        }
308 View Code Duplication
        if ( $this->value != $value2 )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
309
        {
310
            $message = $message ?: $this->overrideError;
311
            $message = sprintf(
312
                $message ?: 'Value "%s" does not equal expected value "%s".',
313
                $this->stringify($this->value),
314
                $this->stringify($value2)
315
            );
316
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_EQ, $propertyPath, ['expected' => $value2]);
317
        }
318
        return $this;
319
    }
320
321
    /**
322
     *
323
     * @param mixed       $value2
324
     * @param string|null $message
325
     * @param string|null $propertyPath
326
     * @return Assert
327
     * @throws AssertionFailedException
328
     */
329
    public function greaterThan($value2, $message = null, $propertyPath = null)
330
    {
331
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
332
        {
333
            return $this;
334
        }
335 View Code Duplication
        if ( ! ( $this->value > $value2 ) )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
336
        {
337
            $message = $message ?: $this->overrideError;
338
            $message = sprintf(
339
                $message ?: 'Value "%s" does not greater then expected value "%s".',
340
                $this->stringify($this->value),
341
                $this->stringify($value2)
342
            );
343
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_EQ, $propertyPath, ['expected' => $value2]);
344
        }
345
        return $this;
346
    }
347
348
    /**
349
     *
350
     * @param mixed       $value2
351
     * @param string|null $message
352
     * @param string|null $propertyPath
353
     * @return Assert
354
     * @throws AssertionFailedException
355
     */
356
    public function greaterThanOrEq($value2, $message = null, $propertyPath = null)
357
    {
358
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
359
        {
360
            return $this;
361
        }
362 View Code Duplication
        if ( ! ( $this->value >= $value2 ) )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
363
        {
364
            $message = $message ?: $this->overrideError;
365
            $message = sprintf(
366
                $message ?: 'Value "%s" does not greater than or equal to expected value "%s".',
367
                $this->stringify($this->value),
368
                $this->stringify($value2)
369
            );
370
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_EQ, $propertyPath, ['expected' => $value2]);
371
        }
372
        return $this;
373
    }
374
375
    /**
376
     *
377
     * @param mixed       $value2
378
     * @param string|null $message
379
     * @param string|null $propertyPath
380
     * @return Assert
381
     * @throws AssertionFailedException
382
     */
383
    public function lessThan($value2, $message = null, $propertyPath = null)
384
    {
385
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
386
        {
387
            return $this;
388
        }
389 View Code Duplication
        if ( ! ( $this->value < $value2 ) )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
390
        {
391
            $message = $message ?: $this->overrideError;
392
            $message = sprintf(
393
                $message ?: 'Value "%s" does not less then expected value "%s".',
394
                $this->stringify($this->value),
395
                $this->stringify($value2)
396
            );
397
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_LESS_THAN, $propertyPath, ['expected' => $value2]);
398
        }
399
        return $this;
400
    }
401
402
    /**
403
     *
404
     * @param mixed       $value2
405
     * @param string|null $message
406
     * @param string|null $propertyPath
407
     * @return Assert
408
     * @throws AssertionFailedException
409
     */
410
    public function lessThanOrEq($value2, $message = null, $propertyPath = null)
411
    {
412
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
413
        {
414
            return $this;
415
        }
416 View Code Duplication
        if ( ! ( $this->value <= $value2 ) )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
417
        {
418
            $message = $message ?: $this->overrideError;
419
            $message = sprintf(
420
                $message ?: 'Value "%s" does not less than or equal to expected value "%s".',
421
                $this->stringify($this->value),
422
                $this->stringify($value2)
423
            );
424
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_LESS_THAN_OR_EQ, $propertyPath, ['expected' => $value2]);
425
        }
426
        return $this;
427
    }
428
429
    /**
430
     * Assert that two values are the same (using ===).
431
     *
432
     * @param mixed       $value2
433
     * @param string|null $message
434
     * @param string|null $propertyPath
435
     * @return Assert
436
     * @throws AssertionFailedException
437
     */
438
    public function same($value2, $message = null, $propertyPath = null)
439
    {
440
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
441
        {
442
            return $this;
443
        }
444 View Code Duplication
        if ( $this->value !== $value2 )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
445
        {
446
            $message = $message ?: $this->overrideError;
447
            $message = sprintf(
448
                $message ?: 'Value "%s" is not the same as expected value "%s".',
449
                $this->stringify($this->value),
450
                $this->stringify($value2)
451
            );
452
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_SAME, $propertyPath, ['expected' => $value2]);
453
        }
454
        return $this;
455
    }
456
457
    /**
458
     * Assert that two values are not equal (using == ).
459
     *
460
     * @param mixed       $value2
461
     * @param string|null $message
462
     * @param string|null $propertyPath
463
     * @return Assert
464
     * @throws AssertionFailedException
465
     */
466
    public function notEq($value2, $message = null, $propertyPath = null)
467
    {
468
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
469
        {
470
            return $this;
471
        }
472 View Code Duplication
        if ( $this->value == $value2 )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
473
        {
474
            $message = $message ?: $this->overrideError;
475
            $message = sprintf(
476
                $message ?: 'Value "%s" is equal to expected value "%s".',
477
                $this->stringify($this->value),
478
                $this->stringify($value2)
479
            );
480
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NOT_EQ, $propertyPath, ['expected' => $value2]);
481
        }
482
        return $this;
483
    }
484
485
    /**
486
     * @param string|null $message
487
     * @param string|null        $propertyPath
488
     *
489
     * @return $this
490
     * @throws AssertionFailedException
491
     */
492
    public function isCallable($message = null, $propertyPath = null)
493
    {
494
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
495
        {
496
            return $this;
497
        }
498
        if ( !is_callable($this->value) )
499
        {
500
            $message = $message ?: $this->overrideError;
501
            $message = sprintf(
502
                $message ?: 'Value "%s" is not callable.',
503
                $this->stringify($this->value)
504
            );
505
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NOT_EQ, $propertyPath);
506
        }
507
        return $this;
508
    }
509
510
    /**
511
     * Assert that two values are not the same (using === ).
512
     *
513
     * @param mixed       $value2
514
     * @param string|null $message
515
     * @param string|null $propertyPath
516
     * @return Assert
517
     * @throws AssertionFailedException
518
     */
519
    public function notSame($value2, $message = null, $propertyPath = null)
520
    {
521
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
522
        {
523
            return $this;
524
        }
525 View Code Duplication
        if ( $this->value === $value2 )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
526
        {
527
            $message = $message ?: $this->overrideError;
528
            $message = sprintf(
529
                $message ?: 'Value "%s" is the same as expected value "%s".',
530
                $this->stringify($this->value),
531
                $this->stringify($value2)
532
            );
533
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NOT_SAME, $propertyPath, ['expected' => $value2]);
534
        }
535
        return $this;
536
    }
537
538
    /**
539
     * @param string|null $message
540
     * @param string|null $propertyPath
541
     * @return Assert
542
     * @throws AssertionFailedException
543
     */
544
    public function id($message = null, $propertyPath = null)
545
    {
546
        $message = $message ?: $this->overrideError;
547
        $message = $message ?: 'Value "%s" is not an integer id.';
548
        return $this->nonEmptyInt($message, $propertyPath)->range(1, PHP_INT_MAX);
549
    }
550
551
    /**
552
     * @param string|null $message
553
     * @param string|null $propertyPath
554
     * @return Assert
555
     * @throws AssertionFailedException
556
     */
557
    public function unsignedInt($message=null, $propertyPath=null)
558
    {
559
        $message = $message ?: $this->overrideError;
560
        $message = $message ?: 'Value "%s" is not an integer id.';
561
562
        return $this->int($message, $propertyPath)->range(0, PHP_INT_MAX);
563
    }
564
565
    /**
566
     * @param string|null $message
567
     * @param string|null $propertyPath
568
     * @return Assert
569
     * @throws AssertionFailedException
570
     */
571
    public function flag($message = null, $propertyPath = null)
572
    {
573
        $message = $message ?: $this->overrideError;
574
        $message = $message ?: 'Value "%s" is not a 0 or 1.';
575
        return $this->range(0, 1, $message, $propertyPath);
576
    }
577
578
    /**
579
     * @param string|null $message
580
     * @param string|null $propertyPath
581
     * @return Assert
582
     * @throws AssertionFailedException
583
     */
584
    public function status($message = null, $propertyPath = null)
585
    {
586
        $message = $message ?: $this->overrideError;
587
        $message = $message ?: 'Value "%s" is not a valid status.';
588
        return $this->integer($message, $propertyPath)->inArray([-1, 0, 1]);
589
    }
590
591
    /**
592
     * @param string|null $message
593
     * @param string|null $propertyPath
594
     * @return Assert
595
     */
596
    public function nullOrId($message = null, $propertyPath = null)
597
    {
598
        return $this->nullOr()->id($message, $propertyPath);
599
    }
600
601
    /**
602
     * @param string|null $message
603
     * @param string|null $propertyPath
604
     * @return Assert
605
     */
606
    public function allIds($message = null, $propertyPath = null)
607
    {
608
        return $this->all()->id($message, $propertyPath);
609
    }
610
611
    /**
612
     * @param string|null $message
613
     * @param string|null $propertyPath
614
     * @return Assert
615
     * @throws AssertionFailedException
616
     */
617
    public function int($message = null, $propertyPath = null)
618
    {
619
        return $this->integer($message, $propertyPath);
620
    }
621
622
    /**
623
     * Assert that value is a php integer.
624
     *
625
     * @param string|null $message
626
     * @param string|null $propertyPath
627
     * @return Assert
628
     * @throws AssertionFailedException
629
     */
630
    public function integer($message = null, $propertyPath = null)
631
    {
632
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
633
        {
634
            return $this;
635
        }
636
        if ( !is_int($this->value) )
637
        {
638
            $message = $message ?: $this->overrideError;
639
            $message = sprintf(
640
                $message ?: 'Value "%s" is not an integer.',
641
                $this->stringify($this->value)
642
            );
643
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_INTEGER, $propertyPath);
644
        }
645
        return $this;
646
    }
647
648
    /**
649
     * Assert that value is a php float.
650
     *
651
     * @param string|null $message
652
     * @param string|null $propertyPath
653
     * @return Assert
654
     * @throws AssertionFailedException
655
     */
656
    public function float($message = null, $propertyPath = null)
657
    {
658
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
659
        {
660
            return $this;
661
        }
662
        if ( ! is_float($this->value) )
663
        {
664
            $message = $message ?: $this->overrideError;
665
            $message = sprintf(
666
                $message ?: 'Value "%s" is not a float.',
667
                $this->stringify($this->value)
668
            );
669
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_FLOAT, $propertyPath);
670
        }
671
        return $this;
672
    }
673
674
    /**
675
     * Validates if an integer or integerish is a digit.
676
     *
677
     * @param string|null $message
678
     * @param string|null $propertyPath
679
     * @return Assert
680
     * @throws AssertionFailedException
681
     */
682
    public function digit($message = null, $propertyPath = null)
683
    {
684
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
685
        {
686
            return $this;
687
        }
688
        if ( ! ctype_digit((string)$this->value) )
689
        {
690
            $message = $message ?: $this->overrideError;
691
            $message = sprintf(
692
                $message ?: 'Value "%s" is not a digit.',
693
                $this->stringify($this->value)
694
            );
695
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_DIGIT, $propertyPath);
696
        }
697
        return $this;
698
    }
699
700
    /**
701
     * Validates if an string is a date .
702
     *
703
     * @param string|null $message
704
     * @param string|null $propertyPath
705
     * @return Assert
706
     * @throws AssertionFailedException
707
     */
708
    public function date($message = null, $propertyPath = null)
709
    {
710
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
711
        {
712
            return $this;
713
        }
714
        $this->notEmpty($message, $propertyPath);
715
        if ( strtotime($this->value) === false )
716
        {
717
            $message = $message ?: $this->overrideError;
718
            $message = sprintf(
719
                $message ?: 'Value "%s" is not a date.',
720
                $this->stringify($this->value)
721
            );
722
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_DATE, $propertyPath);
723
        }
724
        return $this;
725
    }
726
727
    /**
728
     * Assert that value is a php integer'ish.
729
     *
730
     * @param string|null $message
731
     * @param string|null $propertyPath
732
     * @return Assert
733
     * @throws AssertionFailedException
734
     */
735
    public function integerish($message = null, $propertyPath = null)
736
    {
737
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
738
        {
739
            return $this;
740
        }
741
        if ( is_object($this->value) || strval(intval($this->value)) != $this->value || is_bool($this->value) || is_null($this->value) )
742
        {
743
            $message = $message ?: $this->overrideError;
744
            $message = sprintf(
745
                $message ?: 'Value "%s" is not an integer or a number castable to integer.',
746
                $this->stringify($this->value)
747
            );
748
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_INTEGERISH, $propertyPath);
749
        }
750
        return $this;
751
    }
752
753
    /**
754
     * Assert that value is php boolean
755
     *
756
     * @param string|null $message
757
     * @param string|null $propertyPath
758
     * @return Assert
759
     * @throws AssertionFailedException
760
     */
761
    public function boolean($message = null, $propertyPath = null)
762
    {
763
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
764
        {
765
            return $this;
766
        }
767
        if ( ! is_bool($this->value) )
768
        {
769
            $message = $message ?: $this->overrideError;
770
            $message = sprintf(
771
                $message ?: 'Value "%s" is not a boolean.',
772
                $this->stringify($this->value)
773
            );
774
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_BOOLEAN, $propertyPath);
775
        }
776
        return $this;
777
    }
778
779
    /**
780
     * Assert that value is a PHP scalar
781
     *
782
     * @param string|null $message
783
     * @param string|null $propertyPath
784
     * @return Assert
785
     * @throws AssertionFailedException
786
     */
787
    public function scalar($message = null, $propertyPath = null)
788
    {
789
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
790
        {
791
            return $this;
792
        }
793
        if ( ! is_scalar($this->value) )
794
        {
795
            $message = $message ?: $this->overrideError;
796
            $message = sprintf(
797
                $message ?: 'Value "%s" is not a scalar.',
798
                $this->stringify($this->value)
799
            );
800
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_SCALAR, $propertyPath);
801
        }
802
        return $this;
803
    }
804
805
    /**
806
     * Assert that value is not empty
807
     *
808
     * @param string|null $message
809
     * @param string|null $propertyPath
810
     * @return Assert
811
     * @throws AssertionFailedException
812
     */
813 View Code Duplication
    public function notEmpty($message = null, $propertyPath = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
814
    {
815
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
816
        {
817
            return $this;
818
        }
819
        if ( ( is_object($this->value) && empty((array)$this->value) ) || empty($this->value) )
820
        {
821
            $message = $message ?: $this->overrideError;
822
            $message = sprintf(
823
                $message ?: 'Value "%s" is empty, but non empty value was expected.',
824
                $this->stringify($this->value)
825
            );
826
            throw $this->createException($message, $this->overrideCode ?: self::VALUE_EMPTY, $propertyPath);
827
        }
828
        return $this;
829
    }
830
831
    /**
832
     * Assert that value is empty
833
     *
834
     * @param string|null $message
835
     * @param string|null $propertyPath
836
     * @return Assert
837
     * @throws AssertionFailedException
838
     */
839
    public function noContent($message = null, $propertyPath = null)
840
    {
841
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
842
        {
843
            return $this;
844
        }
845
        if ( !empty( $this->value ) )
846
        {
847
            $message = $message ?: $this->overrideError;
848
            $message = sprintf(
849
                $message ?: 'Value "%s" is not empty, but empty value was expected.',
850
                $this->stringify($this->value)
851
            );
852
            throw $this->createException($message, $this->overrideCode ?: self::VALUE_NOT_EMPTY, $propertyPath);
853
        }
854
        return $this;
855
    }
856
857
    /**
858
     * Assert that value is not null
859
     *
860
     * @param string|null $message
861
     * @param string|null $propertyPath
862
     * @return Assert
863
     * @throws AssertionFailedException
864
     */
865
    public function notNull($message = null, $propertyPath = null)
866
    {
867
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
868
        {
869
            return $this;
870
        }
871
        if ( $this->value === null )
872
        {
873
            $message = $message ?: $this->overrideError;
874
            $message = sprintf(
875
                $message ?: 'Value "%s" is null, but non null value was expected.',
876
                $this->stringify($this->value)
877
            );
878
            throw $this->createException($message, $this->overrideCode ?: self::VALUE_NULL, $propertyPath);
879
        }
880
        return $this;
881
    }
882
883
    /**
884
     * Assert that value is a string
885
     *
886
     * @param string|null $message
887
     * @param string|null $propertyPath
888
     * @return Assert
889
     * @throws AssertionFailedException
890
     */
891
    public function string($message = null, $propertyPath = null)
892
    {
893
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
894
        {
895
            return $this;
896
        }
897
        if ( !is_string($this->value) )
898
        {
899
            $message = $message ?: $this->overrideError;
900
            $message = sprintf(
901
                $message ?: 'Value "%s" expected to be string, type %s given.',
902
                $this->stringify($this->value),
903
                gettype($this->value)
904
            );
905
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_STRING, $propertyPath);
906
        }
907
        return $this;
908
    }
909
910
    /**
911
     * Assert that value matches a regex
912
     *
913
     * @param string      $pattern
914
     * @param string|null $message
915
     * @param string|null $propertyPath
916
     * @return Assert
917
     * @throws AssertionFailedException
918
     */
919
    public function regex($pattern, $message=null, $propertyPath=null)
920
    {
921
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
922
        {
923
            return $this;
924
        }
925
        $this->string($message, $propertyPath);
926 View Code Duplication
        if ( ! preg_match($pattern, $this->value) )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
927
        {
928
            $message = $message ?: $this->overrideError;
929
            $message = sprintf(
930
                $message ?: 'Value "%s" does not match expression.',
931
                $this->stringify($this->value)
932
            );
933
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_REGEX, $propertyPath, ['pattern' => $pattern]);
934
        }
935
        return $this;
936
    }
937
938
    /**
939
     * @param string $message
940
     * @param string $propertyPath
941
     * @return $this
942
     * @throws AssertionFailedException
943
     */
944
    public function ipAddress($message = null, $propertyPath = null)
945
    {
946
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
947
        {
948
            return $this;
949
        }
950
        $this->string($message, $propertyPath);
951
        $pattern   = '/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/';
952
        if ( ! preg_match($pattern, $this->value) )
953
        {
954
            $message = $message ?: $this->overrideError;
955
            $message = sprintf(
956
                $message ?: 'Value "%s" was expected to be a valid IP Address',
957
                $this->stringify($this->value)
958
            );
959
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_IP_ADDRESS, $propertyPath);
960
        }
961
        return $this;
962
    }
963
964
    /**
965
     * @param string $pattern
966
     * @param string|null $message
967
     * @param string|null $propertyPath
968
     * @return $this
969
     * @throws AssertionFailedException
970
     */
971
    public function notRegex($pattern, $message = null, $propertyPath = null)
972
    {
973
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
974
        {
975
            return $this;
976
        }
977
        $this->string($message, $propertyPath);
978 View Code Duplication
        if ( preg_match($pattern, $this->value) )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
979
        {
980
            $message = $message ?: $this->overrideError;
981
            $message = sprintf(
982
                $message ?: 'Value "%s" does not match expression.',
983
                $this->stringify($this->value)
984
            );
985
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_REGEX, $propertyPath, ['pattern' => $pattern]);
986
        }
987
        return $this;
988
    }
989
990
    /**
991
     * Assert that string has a given length.
992
     *
993
     * @param int         $length
994
     * @param string|null $message
995
     * @param string|null $propertyPath
996
     * @param string      $encoding
997
     * @return Assert
998
     * @throws AssertionFailedException
999
     */
1000
    public function length($length, $message = null, $propertyPath = null, $encoding = 'utf8')
1001
    {
1002
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1003
        {
1004
            return $this;
1005
        }
1006
        $this->string($message, $propertyPath);
1007
        if ( mb_strlen($this->value, $encoding) !== $length )
1008
        {
1009
            $message    = $message ?: $this->overrideError;
1010
            $message    = sprintf(
1011
                $message ?: 'Value "%s" has to be %d exactly characters long, but length is %d.',
1012
                $this->stringify($this->value),
1013
                $length,
1014
                mb_strlen($this->value, $encoding)
1015
            );
1016
            $constraints = ['length' => $length, 'encoding' => $encoding];
1017
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_LENGTH, $propertyPath, $constraints);
1018
        }
1019
        return $this;
1020
    }
1021
1022
    /**
1023
     * Assert that a string is at least $minLength chars long.
1024
     *
1025
     * @param int         $minLength
1026
     * @param string|null $message
1027
     * @param string|null $propertyPath
1028
     * @param string      $encoding
1029
     * @return Assert
1030
     * @throws AssertionFailedException
1031
     */
1032
    public function minLength($minLength, $message = null, $propertyPath = null, $encoding = 'utf8')
1033
    {
1034
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1035
        {
1036
            return $this;
1037
        }
1038
        $this->string($message, $propertyPath);
1039
        if ( mb_strlen($this->value, $encoding) < $minLength )
1040
        {
1041
            $message = $message ?: $this->overrideError;
1042
            $message     = sprintf(
1043
                $message
1044
                    ?: 'Value "%s" is too short, it should have more than %d characters, but only has %d characters.',
1045
                $this->stringify($this->value),
1046
                $minLength,
1047
                mb_strlen($this->value, $encoding)
1048
            );
1049
            $constraints = ['min_length' => $minLength, 'encoding' => $encoding];
1050
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MIN_LENGTH, $propertyPath, $constraints);
1051
        }
1052
        return $this;
1053
    }
1054
1055
    /**
1056
     * Assert that string value is not longer than $maxLength chars.
1057
     *
1058
     * @param integer     $maxLength
1059
     * @param string|null $message
1060
     * @param string|null $propertyPath
1061
     * @param string      $encoding
1062
     * @return Assert
1063
     * @throws AssertionFailedException
1064
     */
1065
    public function maxLength($maxLength, $message = null, $propertyPath = null, $encoding = 'utf8')
1066
    {
1067
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1068
        {
1069
            return $this;
1070
        }
1071
        $this->string($message, $propertyPath);
1072
        if ( mb_strlen($this->value, $encoding) > $maxLength )
1073
        {
1074
            $message = $message ?: $this->overrideError;
1075
            $message     = sprintf(
1076
                $message ?: 'Value "%s" is too long, it should have no more than %d characters, but has %d characters.',
1077
                $this->stringify($this->value),
1078
                $maxLength,
1079
                mb_strlen($this->value, $encoding)
1080
            );
1081
            $constraints = ['max_length' => $maxLength, 'encoding' => $encoding];
1082
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MAX_LENGTH, $propertyPath, $constraints);
1083
        }
1084
        return $this;
1085
    }
1086
1087
    /**
1088
     * Assert that string length is between min,max lengths.
1089
     *
1090
     * @param integer     $minLength
1091
     * @param integer     $maxLength
1092
     * @param string|null $message
1093
     * @param string|null $propertyPath
1094
     * @param string      $encoding
1095
     * @return Assert
1096
     * @throws AssertionFailedException
1097
     */
1098
    public function betweenLength($minLength, $maxLength, $message = null, $propertyPath = null, $encoding = 'utf8')
1099
    {
1100
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1101
        {
1102
            return $this;
1103
        }
1104
        $this->string($message, $propertyPath);
1105
        if ( mb_strlen($this->value, $encoding) < $minLength )
1106
        {
1107
            $message = $message ?: $this->overrideError;
1108
            $message     = sprintf(
1109
                $message
1110
                    ?: 'Value "%s" is too short, it should have more than %d characters, but only has %d characters.',
1111
                $this->stringify($this->value),
1112
                $minLength,
1113
                mb_strlen($this->value, $encoding)
1114
            );
1115
            $constraints = ['min_length' => $minLength, 'encoding' => $encoding];
1116
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MIN_LENGTH, $propertyPath, $constraints);
1117
        }
1118
        if ( mb_strlen($this->value, $encoding) > $maxLength )
1119
        {
1120
            $message = $message ?: $this->overrideError;
1121
            $message     = sprintf(
1122
                $message ?: 'Value "%s" is too long, it should have no more than %d characters, but has %d characters.',
1123
                $this->stringify($this->value),
1124
                $maxLength,
1125
                mb_strlen($this->value, $encoding)
1126
            );
1127
            $constraints = ['max_length' => $maxLength, 'encoding' => $encoding];
1128
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MAX_LENGTH, $propertyPath, $constraints);
1129
        }
1130
        return $this;
1131
    }
1132
1133
    /**
1134
     * Assert that string starts with a sequence of chars.
1135
     *
1136
     * @param string      $needle
1137
     * @param string|null $message
1138
     * @param string|null $propertyPath
1139
     * @param string      $encoding
1140
     * @return Assert
1141
     * @throws AssertionFailedException
1142
     */
1143 View Code Duplication
    public function startsWith($needle, $message = null, $propertyPath = null, $encoding = 'utf8')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
1144
    {
1145
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1146
        {
1147
            return $this;
1148
        }
1149
        $this->string($message, $propertyPath);
1150
        if ( mb_strpos($this->value, $needle, null, $encoding) !== 0 )
1151
        {
1152
            $message = $message ?: $this->overrideError;
1153
            $message     = sprintf(
1154
                $message ?: 'Value "%s" does not start with "%s".',
1155
                $this->stringify($this->value),
1156
                $this->stringify($needle)
1157
            );
1158
            $constraints = ['needle' => $needle, 'encoding' => $encoding];
1159
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_STRING_START, $propertyPath, $constraints);
1160
        }
1161
        return $this;
1162
    }
1163
1164
    /**
1165
     * Assert that string ends with a sequence of chars.
1166
     *
1167
     * @param string      $needle
1168
     * @param string|null $message
1169
     * @param string|null $propertyPath
1170
     * @param string      $encoding
1171
     * @return Assert
1172
     * @throws AssertionFailedException
1173
     */
1174
    public function endsWith($needle, $message = null, $propertyPath = null, $encoding = 'utf8')
1175
    {
1176
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1177
        {
1178
            return $this;
1179
        }
1180
        $this->string($message, $propertyPath);
1181
        $stringPosition = mb_strlen($this->value, $encoding) - mb_strlen($needle, $encoding);
1182
        if ( mb_strripos($this->value, $needle, null, $encoding) !== $stringPosition )
1183
        {
1184
            $message = $message ?: $this->overrideError;
1185
            $message     = sprintf(
1186
                $message ?: 'Value "%s" does not end with "%s".',
1187
                $this->stringify($this->value),
1188
                $this->stringify($needle)
1189
            );
1190
            $constraints = ['needle' => $needle, 'encoding' => $encoding];
1191
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_STRING_END, $propertyPath, $constraints);
1192
        }
1193
        return $this;
1194
    }
1195
1196
    /**
1197
     * Assert that string contains a sequence of chars.
1198
     *
1199
     * @param string      $needle
1200
     * @param string|null $message
1201
     * @param string|null $propertyPath
1202
     * @param string      $encoding
1203
     * @return Assert
1204
     * @throws AssertionFailedException
1205
     */
1206 View Code Duplication
    public function contains($needle, $message = null, $propertyPath = null, $encoding = 'utf8')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
1207
    {
1208
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1209
        {
1210
            return $this;
1211
        }
1212
        $this->string($message, $propertyPath);
1213
        if ( mb_strpos($this->value, $needle, null, $encoding) === false )
1214
        {
1215
            $message = $message ?: $this->overrideError;
1216
            $message     = sprintf(
1217
                $message ?: 'Value "%s" does not contain "%s".',
1218
                $this->stringify($this->value),
1219
                $this->stringify($needle)
1220
            );
1221
            $constraints = ['needle' => $needle, 'encoding' => $encoding];
1222
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_STRING_CONTAINS, $propertyPath, $constraints);
1223
        }
1224
        return $this;
1225
    }
1226
1227
    /**
1228
     * Assert that value is in array of choices.
1229
     *
1230
     * @param array       $choices
1231
     * @param string|null $message
1232
     * @param string|null $propertyPath
1233
     * @return Assert
1234
     * @throws AssertionFailedException
1235
     */
1236
    public function choice(array $choices, $message = null, $propertyPath = null)
1237
    {
1238
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1239
        {
1240
            return $this;
1241
        }
1242
        if ( !in_array($this->value, $choices, true) )
1243
        {
1244
            $message = $message ?: $this->overrideError;
1245
            $message = sprintf(
1246
                $message ?: 'Value "%s" is not an element of the valid values: %s',
1247
                $this->stringify($this->value),
1248
                implode(", ", array_map('Terah\Assert\Assert::stringify', $choices))
1249
            );
1250
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_CHOICE, $propertyPath, ['choices' => $choices]);
1251
        }
1252
        return $this;
1253
    }
1254
1255
    /**
1256
     * Alias of {@see choice()}
1257
     *
1258
     * @throws AssertionFailedException
1259
     *
1260
     * @param array $choices
1261
     * @param string|null $message
1262
     * @param string|null $propertyPath
1263
     * @return $this
1264
     */
1265
    public function inArray(array $choices, $message = null, $propertyPath = null)
1266
    {
1267
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1268
        {
1269
            return $this;
1270
        }
1271
        $this->choice($choices, $message, $propertyPath);
1272
        return $this;
1273
    }
1274
1275
    /**
1276
     * Assert that value is numeric.
1277
     *
1278
     * @param string|null $message
1279
     * @param string|null $propertyPath
1280
     * @return Assert
1281
     * @throws AssertionFailedException
1282
     */
1283
    public function numeric($message = null, $propertyPath = null)
1284
    {
1285
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1286
        {
1287
            return $this;
1288
        }
1289
        if ( ! is_numeric($this->value) )
1290
        {
1291
            $message = $message ?: $this->overrideError;
1292
            $message = sprintf(
1293
                $message ?: 'Value "%s" is not numeric.',
1294
                $this->stringify($this->value)
1295
            );
1296
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NUMERIC, $propertyPath);
1297
        }
1298
        return $this;
1299
    }
1300
1301
    /**
1302
     * @param string|null $message
1303
     * @param string|null $propertyPath
1304
     * @return Assert
1305
     * @throws AssertionFailedException
1306
     */
1307
    public function nonEmptyArray($message = null, $propertyPath = null)
1308
    {
1309
        $message = $message ?: 'Value "%s" is not a non-empty array.';
1310
        return $this->isArray($message, $propertyPath)->notEmpty($message, $propertyPath);
1311
    }
1312
1313
    /**
1314
     * @param string|null $message
1315
     * @param string|null $propertyPath
1316
     * @return Assert
1317
     * @throws AssertionFailedException
1318
     */
1319
    public function nonEmptyInt($message = null, $propertyPath = null)
1320
    {
1321
        $message = $message ?: 'Value "%s" is not a non-empty integer.';
1322
        return $this->integer($message, $propertyPath)->notEmpty($message, $propertyPath);
1323
    }
1324
1325
    /**
1326
     * @param string|null $message
1327
     * @param string|null $propertyPath
1328
     * @return Assert
1329
     * @throws AssertionFailedException
1330
     */
1331
    public function nonEmptyString($message = null, $propertyPath = null)
1332
    {
1333
        $message = $message ?: 'Value "%s" is not a non-empty string.';
1334
        return $this->integer($message, $propertyPath)->notEmpty($message, $propertyPath);
1335
    }
1336
1337
    /**
1338
     * Assert that value is an array.
1339
     *
1340
     * @param string|null $message
1341
     * @param string|null $propertyPath
1342
     * @return Assert
1343
     * @throws AssertionFailedException
1344
     */
1345
    public function isArray($message = null, $propertyPath = null)
1346
    {
1347
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1348
        {
1349
            return $this;
1350
        }
1351
        if ( !is_array($this->value) )
1352
        {
1353
            $message = $message ?: $this->overrideError;
1354
            $message = sprintf(
1355
                $message ?: 'Value "%s" is not an array.',
1356
                $this->stringify($this->value)
1357
            );
1358
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_ARRAY, $propertyPath);
1359
        }
1360
        return $this;
1361
    }
1362
1363
    /**
1364
     * Assert that value is an array or a traversable object.
1365
     *
1366
     * @param string|null $message
1367
     * @param string|null $propertyPath
1368
     * @return Assert
1369
     * @throws AssertionFailedException
1370
     */
1371
    public function isTraversable($message = null, $propertyPath = null)
1372
    {
1373
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1374
        {
1375
            return $this;
1376
        }
1377
        if ( !is_array($this->value) && !$this->value instanceof \Traversable )
1378
        {
1379
            $message = $message ?: $this->overrideError;
1380
            $message = sprintf(
1381
                $message ?: 'Value "%s" is not an array and does not implement Traversable.',
1382
                $this->stringify($this->value)
1383
            );
1384
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_TRAVERSABLE, $propertyPath);
1385
        }
1386
        return $this;
1387
    }
1388
1389
    /**
1390
     * Assert that value is an array or an array-accessible object.
1391
     *
1392
     * @param string|null $message
1393
     * @param string|null $propertyPath
1394
     * @return Assert
1395
     * @throws AssertionFailedException
1396
     */
1397
    public function isArrayAccessible($message = null, $propertyPath = null)
1398
    {
1399
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1400
        {
1401
            return $this;
1402
        }
1403
        if ( !is_array($this->value) && !$this->value instanceof \ArrayAccess )
1404
        {
1405
            $message = $message ?: $this->overrideError;
1406
            $message = sprintf(
1407
                $message ?: 'Value "%s" is not an array and does not implement ArrayAccess.',
1408
                $this->stringify($this->value)
1409
            );
1410
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_ARRAY_ACCESSIBLE, $propertyPath);
1411
        }
1412
        return $this;
1413
    }
1414
1415
    /**
1416
     * Assert that key exists in an array
1417
     *
1418
     * @param string|integer $key
1419
     * @param string|null    $message
1420
     * @param string|null    $propertyPath
1421
     * @return Assert
1422
     * @throws AssertionFailedException
1423
     */
1424
    public function keyExists($key, $message = null, $propertyPath = null)
1425
    {
1426
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1427
        {
1428
            return $this;
1429
        }
1430
        $this->isArray($message, $propertyPath);
1431
        if ( !array_key_exists($key, $this->value) )
1432
        {
1433
            $message = $message ?: $this->overrideError;
1434
            $message = sprintf(
1435
                $message ?: 'Array does not contain an element with key "%s"',
1436
                $this->stringify($key)
1437
            );
1438
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_KEY_EXISTS, $propertyPath, ['key' => $key]);
1439
        }
1440
        return $this;
1441
    }
1442
1443
    /**
1444
     * Assert that keys exist in array
1445
     *
1446
     * @param array       $keys
1447
     * @param string|null $message
1448
     * @param string|null $propertyPath
1449
     * @return Assert
1450
     * @throws AssertionFailedException
1451
     */
1452
    public function keysExist($keys, $message = null, $propertyPath = null)
1453
    {
1454
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1455
        {
1456
            return $this;
1457
        }
1458
        $this->isArray($message, $propertyPath);
1459
        foreach ( $keys as $key )
1460
        {
1461
            if ( !array_key_exists($key, $this->value) )
1462
            {
1463
                $message = $message
1464
                    ?: sprintf(
1465
                        'Array does not contain an element with key "%s"',
1466
                        $this->stringify($key)
1467
                    );
1468
                throw $this->createException($message, $this->overrideCode ?: self::INVALID_KEYS_EXIST, $propertyPath, ['key' => $key]);
1469
            }
1470
        }
1471
        return $this;
1472
    }
1473
1474
    /**
1475
     * Assert that property exists in array
1476
     *
1477
     * @param string|integer $key
1478
     * @param string|null    $message
1479
     * @param string|null    $propertyPath
1480
     * @return Assert
1481
     * @throws AssertionFailedException
1482
     */
1483
    public function propertyExists($key, $message = null, $propertyPath = null)
1484
    {
1485
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1486
        {
1487
            return $this;
1488
        }
1489
        $this->isObject($message, $propertyPath);
1490
        if ( !property_exists($this->value, $key) && !isset( $this->value->{$key} ) )
1491
        {
1492
            $message = $message
1493
                ?: sprintf(
1494
                    'Object does not contain a property with key "%s"',
1495
                    $this->stringify($key)
1496
                );
1497
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_PROPERTY_EXISTS, $propertyPath, ['key' => $key]);
1498
        }
1499
        return $this;
1500
    }
1501
1502
    /**
1503
     * Assert that properties exists in array
1504
     *
1505
     * @param array       $keys
1506
     * @param string|null $message
1507
     * @param string|null $propertyPath
1508
     * @return Assert
1509
     * @throws AssertionFailedException
1510
     */
1511
    public function propertiesExist(array $keys, $message = null, $propertyPath = null)
1512
    {
1513
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1514
        {
1515
            return $this;
1516
        }
1517
        $this->isObject($message, $propertyPath);
1518
        foreach ( $keys as $key )
1519
        {
1520
            // Using isset to allow resolution of magically defined properties
1521
            if ( !property_exists($this->value, $key) && !isset( $this->value->{$key} ) )
1522
            {
1523
                $message = $message
1524
                    ?: sprintf(
1525
                        'Object does not contain a property with key "%s"',
1526
                        $this->stringify($key)
1527
                    );
1528
                throw $this->createException($message, $this->overrideCode ?: self::INVALID_PROPERTIES_EXIST, $propertyPath, ['key' => $key]);
1529
            }
1530
        }
1531
        return $this;
1532
    }
1533
1534
    /**
1535
     * Assert that string is valid utf8
1536
     *
1537
     * @param string|null $message
1538
     * @param string|null $propertyPath
1539
     * @return Assert
1540
     * @throws AssertionFailedException
1541
     */
1542 View Code Duplication
    public function utf8($message = null, $propertyPath = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
1543
    {
1544
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1545
        {
1546
            return $this;
1547
        }
1548
        $this->string($message, $propertyPath);
1549
        if ( mb_detect_encoding($this->value, 'UTF-8', true) !== 'UTF-8' )
1550
        {
1551
            $message = $message
1552
                ?: sprintf(
1553
                    'Value "%s" was expected to be a valid UTF8 string',
1554
                    $this->stringify($this->value)
1555
                );
1556
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_UTF8, $propertyPath);
1557
        }
1558
        return $this;
1559
    }
1560
1561
1562
    /**
1563
     * Assert that string is valid utf8
1564
     *
1565
     * @param string|null $message
1566
     * @param string|null $propertyPath
1567
     * @return Assert
1568
     * @throws AssertionFailedException
1569
     */
1570 View Code Duplication
    public function ascii($message = null, $propertyPath = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
1571
    {
1572
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1573
        {
1574
            return $this;
1575
        }
1576
        $this->string($message, $propertyPath);
1577
        if ( ! preg_match('/^[ -~]+$/', $this->value) )
1578
        {
1579
            $message = $message
1580
                ?: sprintf(
1581
                    'Value "%s" was expected to be a valid ASCII string',
1582
                    $this->stringify($this->value)
1583
                );
1584
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_ASCII, $propertyPath);
1585
        }
1586
        return $this;
1587
    }
1588
1589
    /**
1590
     * Assert that key exists in an array/array-accessible object using isset()
1591
     *
1592
     * @param string|integer $key
1593
     * @param string|null    $message
1594
     * @param string|null    $propertyPath
1595
     * @return Assert
1596
     * @throws AssertionFailedException
1597
     */
1598
    public function keyIsset($key, $message = null, $propertyPath = null)
1599
    {
1600
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1601
        {
1602
            return $this;
1603
        }
1604
        $this->isArrayAccessible($message, $propertyPath);
1605
        if ( !isset( $this->value[$key] ) )
1606
        {
1607
            $message = $message ?: $this->overrideError;
1608
            $message = sprintf(
1609
                $message ?: 'The element with key "%s" was not found',
1610
                $this->stringify($key)
1611
            );
1612
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_KEY_ISSET, $propertyPath, ['key' => $key]);
1613
        }
1614
        return $this;
1615
    }
1616
1617
    /**
1618
     * Assert that key exists in an array/array-accessible object and it's value is not empty.
1619
     *
1620
     * @param string|integer $key
1621
     * @param string|null    $message
1622
     * @param string|null    $propertyPath
1623
     * @return Assert
1624
     * @throws AssertionFailedException
1625
     */
1626
    public function notEmptyKey($key, $message = null, $propertyPath = null)
1627
    {
1628
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1629
        {
1630
            return $this;
1631
        }
1632
        $this->keyIsset($key, $message, $propertyPath);
1633
        (new Assert($this->value[$key]))->setExceptionClass($this->exceptionClass)->notEmpty($message, $propertyPath);
1634
        return $this;
1635
    }
1636
1637
    /**
1638
     * Assert that value is not blank
1639
     *
1640
     * @param string|null $message
1641
     * @param string|null $propertyPath
1642
     * @return Assert
1643
     * @throws AssertionFailedException
1644
     */
1645 View Code Duplication
    public function notBlank($message = null, $propertyPath = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
1646
    {
1647
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1648
        {
1649
            return $this;
1650
        }
1651
        if ( false === $this->value || ( empty( $this->value ) && '0' != $this->value ) )
1652
        {
1653
            $message = $message ?: $this->overrideError;
1654
            $message = sprintf(
1655
                $message ?: 'Value "%s" is blank, but was expected to contain a value.',
1656
                $this->stringify($this->value)
1657
            );
1658
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NOT_BLANK, $propertyPath);
1659
        }
1660
        return $this;
1661
    }
1662
1663
    /**
1664
     * Assert that value is instance of given class-name.
1665
     *
1666
     * @param string      $className
1667
     * @param string|null $message
1668
     * @param string|null $propertyPath
1669
     * @return Assert
1670
     * @throws AssertionFailedException
1671
     */
1672
    public function isInstanceOf($className, $message = null, $propertyPath = null)
1673
    {
1674
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1675
        {
1676
            return $this;
1677
        }
1678 View Code Duplication
        if ( !( $this->value instanceof $className ) )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
1679
        {
1680
            $message = $message ?: $this->overrideError;
1681
            $message = sprintf(
1682
                $message ?: 'Class "%s" was expected to be instanceof of "%s" but is not.',
1683
                $this->stringify($this->value),
1684
                $className
1685
            );
1686
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_INSTANCE_OF, $propertyPath, ['class' => $className]);
1687
        }
1688
        return $this;
1689
    }
1690
1691
    /**
1692
     * Assert that value is not instance of given class-name.
1693
     *
1694
     * @param string      $className
1695
     * @param string|null $message
1696
     * @param string|null $propertyPath
1697
     * @return Assert
1698
     * @throws AssertionFailedException
1699
     */
1700
    public function notIsInstanceOf($className, $message = null, $propertyPath = null)
1701
    {
1702
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1703
        {
1704
            return $this;
1705
        }
1706 View Code Duplication
        if ( $this->value instanceof $className )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
1707
        {
1708
            $message = $message ?: $this->overrideError;
1709
            $message = sprintf(
1710
                $message ?: 'Class "%s" was not expected to be instanceof of "%s".',
1711
                $this->stringify($this->value),
1712
                $className
1713
            );
1714
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NOT_INSTANCE_OF, $propertyPath, ['class' => $className]);
1715
        }
1716
        return $this;
1717
    }
1718
1719
    /**
1720
     * Assert that value is subclass of given class-name.
1721
     *
1722
     * @param string      $className
1723
     * @param string|null $message
1724
     * @param string|null $propertyPath
1725
     * @return Assert
1726
     * @throws AssertionFailedException
1727
     */
1728
    public function subclassOf($className, $message = null, $propertyPath = null)
1729
    {
1730
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1731
        {
1732
            return $this;
1733
        }
1734 View Code Duplication
        if ( !is_subclass_of($this->value, $className) )
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if $className can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
1735
        {
1736
            $message = $message ?: $this->overrideError;
1737
            $message = sprintf(
1738
                $message ?: 'Class "%s" was expected to be subclass of "%s".',
1739
                $this->stringify($this->value),
1740
                $className
1741
            );
1742
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_SUBCLASS_OF, $propertyPath, ['class' => $className]);
1743
        }
1744
        return $this;
1745
    }
1746
1747
    /**
1748
     * Assert that value is in range of numbers.
1749
     *
1750
     * @param integer     $minValue
1751
     * @param integer     $maxValue
1752
     * @param string|null $message
1753
     * @param string|null $propertyPath
1754
     * @return Assert
1755
     * @throws AssertionFailedException
1756
     */
1757
    public function range($minValue, $maxValue, $message = null, $propertyPath = null)
1758
    {
1759
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1760
        {
1761
            return $this;
1762
        }
1763
        $this->numeric($message, $propertyPath);
1764
        if ( $this->value < $minValue || $this->value > $maxValue )
1765
        {
1766
            $message = $message ?: $this->overrideError;
1767
            $message = sprintf(
1768
                $message ?: 'Number "%s" was expected to be at least "%d" and at most "%d".',
1769
                $this->stringify($this->value),
1770
                $this->stringify($minValue),
1771
                $this->stringify($maxValue)
1772
            );
1773
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_RANGE, $propertyPath, [
1774
                'min' => $minValue,
1775
                'max' => $maxValue
1776
            ]);
1777
        }
1778
        return $this;
1779
    }
1780
1781
    /**
1782
     * Assert that a value is at least as big as a given limit
1783
     *
1784
     * @param mixed       $minValue
1785
     * @param string|null $message
1786
     * @param string|null $propertyPath
1787
     * @return Assert
1788
     * @throws AssertionFailedException
1789
     */
1790
    public function min($minValue, $message = null, $propertyPath = null)
1791
    {
1792
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1793
        {
1794
            return $this;
1795
        }
1796
        $this->numeric($message, $propertyPath);
1797 View Code Duplication
        if ( $this->value < $minValue )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
1798
        {
1799
            $message = $message ?: $this->overrideError;
1800
            $message = sprintf(
1801
                $message ?: 'Number "%s" was expected to be at least "%d".',
1802
                $this->stringify($this->value),
1803
                $this->stringify($minValue)
1804
            );
1805
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MIN, $propertyPath, ['min' => $minValue]);
1806
        }
1807
        return $this;
1808
    }
1809
1810
    /**
1811
     * Assert that a number is smaller as a given limit
1812
     *
1813
     * @param mixed       $maxValue
1814
     * @param string|null $message
1815
     * @param string|null $propertyPath
1816
     * @return Assert
1817
     * @throws AssertionFailedException
1818
     */
1819
    public function max($maxValue, $message = null, $propertyPath = null)
1820
    {
1821
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1822
        {
1823
            return $this;
1824
        }
1825
        $this->numeric($message, $propertyPath);
1826 View Code Duplication
        if ( $this->value > $maxValue )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
1827
        {
1828
            $message = $message ?: $this->overrideError;
1829
            $message = sprintf(
1830
                $message ?: 'Number "%s" was expected to be at most "%d".',
1831
                $this->stringify($this->value),
1832
                $this->stringify($maxValue)
1833
            );
1834
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MAX, $propertyPath, ['max' => $maxValue]);
1835
        }
1836
        return $this;
1837
    }
1838
1839
    /**
1840
     * Assert that a file exists
1841
     *
1842
     * @param string|null $message
1843
     * @param string|null $propertyPath
1844
     * @return Assert
1845
     * @throws AssertionFailedException
1846
     */
1847
    public function file($message = null, $propertyPath = null)
1848
    {
1849
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1850
        {
1851
            return $this;
1852
        }
1853
        $this->string($message, $propertyPath);
1854
        $this->notEmpty($message, $propertyPath);
1855
        if ( !is_file($this->value) )
1856
        {
1857
            $message = $message ?: $this->overrideError;
1858
            $message = sprintf(
1859
                $message ?: 'File "%s" was expected to exist.',
1860
                $this->stringify($this->value)
1861
            );
1862
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_FILE, $propertyPath);
1863
        }
1864
        return $this;
1865
    }
1866
1867
    /**
1868
     * @param string|null $message
1869
     * @param string|null $propertyPath
1870
     * @return $this
1871
     * @throws AssertionFailedException
1872
     */
1873
    public function fileExists($message = null, $propertyPath = null)
1874
    {
1875
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1876
        {
1877
            return $this;
1878
        }
1879
        $this->string($message, $propertyPath);
1880
        $this->notEmpty($message, $propertyPath);
1881
        if ( ! file_exists($this->value) )
1882
        {
1883
            $message = $message ?: $this->overrideError;
1884
            $message = sprintf(
1885
                $message ?: 'File or directory "%s" was expected to exist.',
1886
                $this->stringify($this->value)
1887
            );
1888
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_FILE_OR_DIR, $propertyPath);
1889
        }
1890
        return $this;
1891
    }
1892
1893
    /**
1894
     * Assert that a directory exists
1895
     *
1896
     * @param string|null $message
1897
     * @param string|null $propertyPath
1898
     * @return Assert
1899
     * @throws AssertionFailedException
1900
     */
1901 View Code Duplication
    public function directory($message = null, $propertyPath = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
1902
    {
1903
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1904
        {
1905
            return $this;
1906
        }
1907
        $this->string($message, $propertyPath);
1908
        if ( !is_dir($this->value) )
1909
        {
1910
            $message = $message ?: $this->overrideError;
1911
            $message = sprintf(
1912
                $message ?: 'Path "%s" was expected to be a directory.',
1913
                $this->stringify($this->value)
1914
            );
1915
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_DIRECTORY, $propertyPath);
1916
        }
1917
        return $this;
1918
    }
1919
1920
    /**
1921
     * Assert that the value is something readable
1922
     *
1923
     * @param string|null $message
1924
     * @param string|null $propertyPath
1925
     * @return Assert
1926
     * @throws AssertionFailedException
1927
     */
1928 View Code Duplication
    public function readable($message = null, $propertyPath = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
1929
    {
1930
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1931
        {
1932
            return $this;
1933
        }
1934
        $this->string($message, $propertyPath);
1935
        if ( !is_readable($this->value) )
1936
        {
1937
            $message = $message ?: $this->overrideError;
1938
            $message = sprintf(
1939
                $message ?: 'Path "%s" was expected to be readable.',
1940
                $this->stringify($this->value)
1941
            );
1942
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_READABLE, $propertyPath);
1943
        }
1944
        return $this;
1945
    }
1946
1947
    /**
1948
     * Assert that the value is something writeable
1949
     *
1950
     * @param string|null $message
1951
     * @param string|null $propertyPath
1952
     * @return Assert
1953
     * @throws AssertionFailedException
1954
     */
1955 View Code Duplication
    public function writeable($message = null, $propertyPath = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
1956
    {
1957
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1958
        {
1959
            return $this;
1960
        }
1961
        $this->string($message, $propertyPath);
1962
        if ( !is_writeable($this->value) )
1963
        {
1964
            $message = $message ?: $this->overrideError;
1965
            $message = sprintf(
1966
                $message ?: 'Path "%s" was expected to be writeable.',
1967
                $this->stringify($this->value)
1968
            );
1969
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_WRITEABLE, $propertyPath);
1970
        }
1971
        return $this;
1972
    }
1973
1974
    /**
1975
     * Assert that value is an email adress (using
1976
     * input_filter/FILTER_VALIDATE_EMAIL).
1977
     *
1978
     * @param string|null $message
1979
     * @param string|null $propertyPath
1980
     * @return Assert
1981
     * @throws AssertionFailedException
1982
     */
1983
    public function email($message = null, $propertyPath = null)
1984
    {
1985
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1986
        {
1987
            return $this;
1988
        }
1989
        $this->string($message, $propertyPath);
1990
        if ( ! filter_var($this->value, FILTER_VALIDATE_EMAIL) )
1991
        {
1992
            $message = $message ?: $this->overrideError;
1993
            $message = sprintf(
1994
                $message ?: 'Value "%s" was expected to be a valid e-mail address.',
1995
                $this->stringify($this->value)
1996
            );
1997
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_EMAIL, $propertyPath);
1998
        }
1999
        else
2000
        {
2001
            $host = substr($this->value, strpos($this->value, '@') + 1);
2002
            // Likely not a FQDN, bug in PHP FILTER_VALIDATE_EMAIL prior to PHP 5.3.3
2003
            if ( version_compare(PHP_VERSION, '5.3.3', '<') && strpos($host, '.') === false )
2004
            {
2005
                $message = $message ?: $this->overrideError;
2006
                $message = sprintf(
2007
                    $message ?: 'Value "%s" was expected to be a valid e-mail address.',
2008
                    $this->stringify($this->value)
2009
                );
2010
                throw $this->createException($message, $this->overrideCode ?: self::INVALID_EMAIL, $propertyPath);
2011
            }
2012
        }
2013
        return $this;
2014
    }
2015
2016
    /**
2017
     * @param null $message
2018
     * @param null $propertyPath
2019
     * @return Assert
2020
     * @throws AssertionFailedException
2021
     */
2022
    public function emailPrefix($message = null, $propertyPath = null)
2023
    {
2024
        $this->value($this->value . '@example.com');
2025
        return $this->email($message, $propertyPath);
2026
    }
2027
2028
    /**
2029
     * Assert that value is an URL.
2030
     *
2031
     * This code snipped was taken from the Symfony project and modified to the special demands of this method.
2032
     *
2033
     * @param string|null $message
2034
     * @param string|null $propertyPath
2035
     * @return Assert
2036
     * @throws AssertionFailedException
2037
     *
2038
     *
2039
     * @link https://github.com/symfony/Validator/blob/master/Constraints/UrlValidator.php
2040
     * @link https://github.com/symfony/Validator/blob/master/Constraints/Url.php
2041
     */
2042
    public function url($message = null, $propertyPath = null)
2043
    {
2044
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2045
        {
2046
            return $this;
2047
        }
2048
        $this->string($message, $propertyPath);
2049
        $protocols = ['http', 'https'];
2050
        $pattern   = '~^
2051
            (%s)://                                 # protocol
2052
            (
2053
                ([\pL\pN\pS-]+\.)+[\pL]+                   # a domain name
2054
                    |                                     #  or
2055
                \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}      # a IP address
2056
                    |                                     #  or
2057
                \[
2058
                    (?:(?:(?:(?:(?:(?:(?:[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})))?::))))
2059
                \]  # a IPv6 address
2060
            )
2061
            (:[0-9]+)?                              # a port (optional)
2062
            (/?|/\S+)                               # a /, nothing or a / with something
2063
        $~ixu';
2064
        $pattern   = sprintf($pattern, implode('|', $protocols));
2065
        if ( !preg_match($pattern, $this->value) )
2066
        {
2067
            $message = $message ?: $this->overrideError;
2068
            $message = sprintf(
2069
                $message ?: 'Value "%s" was expected to be a valid URL starting with http or https',
2070
                $this->stringify($this->value)
2071
            );
2072
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_URL, $propertyPath);
2073
        }
2074
        return $this;
2075
    }
2076
2077
    /**
2078
     * Assert that value is domain name.
2079
     *
2080
     * This code snipped was taken from the Symfony project and modified to the special demands of this method.
2081
     *
2082
     * @param string|null $message
2083
     * @param string|null $propertyPath
2084
     * @return Assert
2085
     * @throws AssertionFailedException
2086
     *
2087
     */
2088
    public function domainName($message = null, $propertyPath = null)
2089
    {
2090
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2091
        {
2092
            return $this;
2093
        }
2094
        $this->string($message, $propertyPath);
2095
        $pattern   = '/^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6}$/';
2096
        if ( ! preg_match($pattern, $this->value) )
2097
        {
2098
            $message = $message ?: $this->overrideError;
2099
            $message = sprintf(
2100
                $message ?: 'Value "%s" was expected to be a valid domain name',
2101
                $this->stringify($this->value)
2102
            );
2103
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_DOMAIN_NAME, $propertyPath);
2104
        }
2105
        return $this;
2106
    }
2107
2108
    /**
2109
     * Assert that value is alphanumeric.
2110
     *
2111
     * @param string|null $message
2112
     * @param string|null $propertyPath
2113
     * @return Assert
2114
     * @throws AssertionFailedException
2115
     */
2116 View Code Duplication
    public function ausMobile($message = null, $propertyPath = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
2117
    {
2118
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2119
        {
2120
            return $this;
2121
        }
2122
        try
2123
        {
2124
            $this->regex('/^04[0-9]{8})$/', $message, $propertyPath);
2125
        }
2126
        catch ( AssertionFailedException $e )
2127
        {
2128
            $message = $message ?: $this->overrideError;
2129
            $message = sprintf(
2130
                $message
2131
                    ?: 'Value "%s" is not an australian mobile number.',
2132
                $this->stringify($this->value)
2133
            );
2134
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_AUS_MOBILE, $propertyPath);
2135
        }
2136
        return $this;
2137
    }
2138
2139
    /**
2140
     * Assert that value is alphanumeric.
2141
     *
2142
     * @param string|null $message
2143
     * @param string|null $propertyPath
2144
     * @return Assert
2145
     * @throws AssertionFailedException
2146
     */
2147 View Code Duplication
    public function alnum($message = null, $propertyPath = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
2148
    {
2149
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2150
        {
2151
            return $this;
2152
        }
2153
        try
2154
        {
2155
            $this->regex('(^([a-zA-Z]{1}[a-zA-Z0-9]*)$)', $message, $propertyPath);
2156
        }
2157
        catch (AssertionFailedException $e)
2158
        {
2159
            $message = $message ?: $this->overrideError;
2160
            $message = sprintf(
2161
                $message
2162
                    ?: 'Value "%s" is not alphanumeric, starting with letters and containing only letters and numbers.',
2163
                $this->stringify($this->value)
2164
            );
2165
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_ALNUM, $propertyPath);
2166
        }
2167
        return $this;
2168
    }
2169
2170
    /**
2171
     * Assert that the value is boolean True.
2172
     *
2173
     * @param string|null $message
2174
     * @param string|null $propertyPath
2175
     * @return Assert
2176
     * @throws AssertionFailedException
2177
     */
2178
    public function true($message = null, $propertyPath = null)
2179
    {
2180
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2181
        {
2182
            return $this;
2183
        }
2184
        if ( $this->value !== true )
2185
        {
2186
            $message = $message ?: $this->overrideError;
2187
            $message = sprintf(
2188
                $message ?: 'Value "%s" is not TRUE.',
2189
                $this->stringify($this->value)
2190
            );
2191
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_TRUE, $propertyPath);
2192
        }
2193
2194
        return $this;
2195
    }
2196
2197
    /**
2198
     * Assert that the value is boolean True.
2199
     *
2200
     * @param string|null $message
2201
     * @param string|null $propertyPath
2202
     * @return Assert
2203
     * @throws AssertionFailedException
2204
     */
2205
    public function truthy($message = null, $propertyPath = null)
2206
    {
2207
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2208
        {
2209
            return $this;
2210
        }
2211
        if ( ! $this->value )
2212
        {
2213
            $message = $message ?: $this->overrideError;
2214
            $message = sprintf(
2215
                $message ?: 'Value "%s" is not truthy.',
2216
                $this->stringify($this->value)
2217
            );
2218
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_TRUE, $propertyPath);
2219
        }
2220
        return $this;
2221
    }
2222
2223
    /**
2224
     * Assert that the value is boolean False.
2225
     *
2226
     * @param string|null $message
2227
     * @param string|null $propertyPath
2228
     * @return Assert
2229
     * @throws AssertionFailedException
2230
     */
2231
    public function false($message = null, $propertyPath = null)
2232
    {
2233
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2234
        {
2235
            return $this;
2236
        }
2237
        if ( $this->value !== false )
2238
        {
2239
            $message = $message ?: $this->overrideError;
2240
            $message = sprintf(
2241
                $message ?: 'Value "%s" is not FALSE.',
2242
                $this->stringify($this->value)
2243
            );
2244
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_FALSE, $propertyPath);
2245
        }
2246
        return $this;
2247
    }
2248
2249
    /**
2250
     * Assert that the value is not boolean False.
2251
     *
2252
     * @param string|null $message
2253
     * @param string|null $propertyPath
2254
     * @return Assert
2255
     * @throws AssertionFailedException
2256
     */
2257
    public function notFalse($message = null, $propertyPath = null)
2258
    {
2259
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2260
        {
2261
            return $this;
2262
        }
2263
        if ( $this->value === false )
2264
        {
2265
            $message = $message ?: $this->overrideError;
2266
            $message = sprintf(
2267
                $message ?: 'Value "%s" is not FALSE.',
2268
                $this->stringify($this->value)
2269
            );
2270
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NOT_FALSE, $propertyPath);
2271
        }
2272
        return $this;
2273
    }
2274
2275
    /**
2276
     * Assert that the class exists.
2277
     *
2278
     * @param string|null $message
2279
     * @param string|null $propertyPath
2280
     * @return Assert
2281
     * @throws AssertionFailedException
2282
     */
2283
    public function classExists($message = null, $propertyPath = null)
2284
    {
2285
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2286
        {
2287
            return $this;
2288
        }
2289
        if ( !class_exists($this->value) )
2290
        {
2291
            $message = $message ?: $this->overrideError;
2292
            $message = sprintf(
2293
                $message ?: 'Class "%s" does not exist.',
2294
                $this->stringify($this->value)
2295
            );
2296
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_CLASS, $propertyPath);
2297
        }
2298
        return $this;
2299
    }
2300
2301
    /**
2302
     * Assert that the class implements the interface
2303
     *
2304
     * @param string      $interfaceName
2305
     * @param string|null $message
2306
     * @param string|null $propertyPath
2307
     * @return Assert
2308
     * @throws AssertionFailedException
2309
     */
2310
    public function implementsInterface($interfaceName, $message = null, $propertyPath = null)
2311
    {
2312
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2313
        {
2314
            return $this;
2315
        }
2316
        $reflection = new \ReflectionClass($this->value);
2317
        if ( !$reflection->implementsInterface($interfaceName) )
2318
        {
2319
            $message = $message ?: $this->overrideError;
2320
            $message = sprintf(
2321
                $message ?: 'Class "%s" does not implement interface "%s".',
2322
                $this->stringify($this->value),
2323
                $this->stringify($interfaceName)
2324
            );
2325
            throw $this->createException($message, self::INTERFACE_NOT_IMPLEMENTED, $propertyPath, ['interface' => $interfaceName]);
2326
        }
2327
        return $this;
2328
    }
2329
2330
    /**
2331
     * Assert that the given string is a valid json string.
2332
     *
2333
     * NOTICE:
2334
     * Since this does a json_decode to determine its validity
2335
     * you probably should consider, when using the variable
2336
     * content afterwards, just to decode and check for yourself instead
2337
     * of using this assertion.
2338
     *
2339
     * @param string|null $message
2340
     * @param string|null $propertyPath
2341
     * @return Assert
2342
     * @throws AssertionFailedException
2343
     */
2344
    public function isJsonString($message = null, $propertyPath = null)
2345
    {
2346
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2347
        {
2348
            return $this;
2349
        }
2350
        if ( null === json_decode($this->value) && JSON_ERROR_NONE !== json_last_error() )
2351
        {
2352
            $message = $message ?: $this->overrideError;
2353
            $message = sprintf(
2354
                $message ?: 'Value "%s" is not a valid JSON string.',
2355
                $this->stringify($this->value)
2356
            );
2357
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_JSON_STRING, $propertyPath);
2358
        }
2359
        return $this;
2360
    }
2361
2362
    /**
2363
     * Assert that the given string is a valid UUID
2364
     *
2365
     * Uses code from {@link https://github.com/ramsey/uuid} that is MIT licensed.
2366
     *
2367
     * @param string|null $message
2368
     * @param string|null $propertyPath
2369
     * @return Assert
2370
     * @throws AssertionFailedException
2371
     */
2372
    public function uuid($message = null, $propertyPath = null)
2373
    {
2374
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2375
        {
2376
            return $this;
2377
        }
2378
        $this->value = str_replace(['urn:', 'uuid:', '{', '}'], '', $this->value);
2379
        if ( $this->value === '00000000-0000-0000-0000-000000000000' )
2380
        {
2381
            return $this;
2382
        }
2383
        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) )
2384
        {
2385
            $message = $message ?: $this->overrideError;
2386
            $message = sprintf(
2387
                $message ?: 'Value "%s" is not a valid UUID.',
2388
                $this->stringify($this->value)
2389
            );
2390
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_UUID, $propertyPath);
2391
        }
2392
        return $this;
2393
    }
2394
2395
    /**
2396
     * Assert that the count of countable is equal to count.
2397
     *
2398
     * @param int    $count
2399
     * @param string $message
2400
     * @param string $propertyPath
2401
     * @return Assert
2402
     * @throws AssertionFailedException
2403
     */
2404
    public function count($count, $message = null, $propertyPath = null)
2405
    {
2406
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2407
        {
2408
            return $this;
2409
        }
2410 View Code Duplication
        if ( $count !== count($this->value) )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
2411
        {
2412
            $message = $message ?: $this->overrideError;
2413
            $message = sprintf(
2414
                $message ?: 'List does not contain exactly "%d" elements.',
2415
                $this->stringify($this->value),
2416
                $this->stringify($count)
2417
            );
2418
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_COUNT, $propertyPath, ['count' => $count]);
2419
        }
2420
        return $this;
2421
    }
2422
2423
    /**
2424
     * @param $func
2425
     * @param $args
2426
     * @return bool
2427
     * @throws AssertionFailedException
2428
     */
2429
    protected function doAllOrNullOr($func, $args)
2430
    {
2431
        if ( $this->nullOr && is_null($this->value) )
2432
        {
2433
            return true;
2434
        }
2435
        if ( $this->emptyOr && empty($this->value) )
2436
        {
2437
            return true;
2438
        }
2439
        if ( $this->all && (new Assert($this->value))->setExceptionClass($this->exceptionClass)->isTraversable() )
2440
        {
2441
            foreach ( $this->value as $idx => $value )
2442
            {
2443
                $object = (new Assert($value))->setExceptionClass($this->exceptionClass);
2444
                call_user_func_array([$object, $func], $args);
2445
            }
2446
            return true;
2447
        }
2448
        return ( $this->nullOr && is_null($this->value) ) || ( $this->emptyOr && empty($this->value) ) ? true : false;
2449
    }
2450
2451
    /**
2452
     * Determines if the values array has every choice as key and that this choice has content.
2453
     *
2454
     * @param array $choices
2455
     * @param string|null $message
2456
     * @param string|null $propertyPath
2457
     * @return $this
2458
     */
2459
    public function choicesNotEmpty(array $choices, $message = null, $propertyPath = null)
2460
    {
2461
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2462
        {
2463
            return $this;
2464
        }
2465
        $this->notEmpty($message, $propertyPath);
2466
        foreach ( $choices as $choice )
2467
        {
2468
            $this->notEmptyKey($choice, $message, $propertyPath);
2469
        }
2470
        return $this;
2471
    }
2472
2473
    /**
2474
     * Determines that the named method is defined in the provided object.
2475
     *
2476
     * @param mixed $object
2477
     * @param string|null $message
2478
     * @param string|null $propertyPath
2479
     * @returns Assert
2480
     * @throws
2481
     */
2482
    public function methodExists($object, $message = null, $propertyPath = null)
2483
    {
2484
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2485
        {
2486
            return $this;
2487
        }
2488
        (new Assert($object))->setExceptionClass($this->exceptionClass)->isObject($message, $propertyPath);
2489
        if ( !method_exists($object, $this->value) )
2490
        {
2491
            $message = $message ?: $this->overrideError;
2492
            $message = sprintf(
2493
                $message ?: 'Expected "%s" does not a exist in provided object.',
2494
                $this->stringify($this->value)
2495
            );
2496
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_METHOD, $propertyPath);
2497
        }
2498
        return $this;
2499
    }
2500
2501
    /**
2502
     * Determines that the provided value is an object.
2503
     *
2504
     * @param string|null $message
2505
     * @param string|null $propertyPath
2506
     * @return $this
2507
     * @throws AssertionFailedException
2508
     */
2509
    public function isObject($message = null, $propertyPath = null)
2510
    {
2511
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2512
        {
2513
            return $this;
2514
        }
2515
        if ( !is_object($this->value) )
2516
        {
2517
            $message = $message ?: $this->overrideError;
2518
            $message = sprintf(
2519
                $message ?: 'Provided "%s" is not a valid object.',
2520
                $this->stringify($this->value)
2521
            );
2522
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_OBJECT, $propertyPath);
2523
        }
2524
        return $this;
2525
    }
2526
2527
    /**
2528
     * Make a string version of a value.
2529
     *
2530
     * @param $value
2531
     * @return string
2532
     */
2533
    private function stringify($value)
2534
    {
2535
        if ( is_bool($value) )
2536
        {
2537
            return $value ? '<TRUE>' : '<FALSE>';
2538
        }
2539
        if ( is_scalar($value) )
2540
        {
2541
            $val = (string)$value;
2542
            if ( strlen($val) > 100 )
2543
            {
2544
                $val = substr($val, 0, 97) . '...';
2545
            }
2546
            return $val;
2547
        }
2548
        if ( is_array($value) )
2549
        {
2550
            return '<ARRAY>';
2551
        }
2552
        if ( is_object($value) )
2553
        {
2554
            return get_class($value);
2555
        }
2556
        if ( is_resource($value) )
2557
        {
2558
            return '<RESOURCE>';
2559
        }
2560
        if ( $value === null )
2561
        {
2562
            return '<NULL>';
2563
        }
2564
        return 'unknown';
2565
    }
2566
}
2567
2568