Completed
Push — master ( dbe86b...83d160 )
by Terry
02:56
created

Assert::unsignedInt()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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