Completed
Push — master ( a1d593...d46f84 )
by Terry
02:09
created

Assert::that()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 22
Code Lines 11

Duplication

Lines 22
Ratio 100 %

Importance

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