Completed
Pull Request — master (#2)
by
unknown
01:33
created

Assert::samAccountName()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 17
Code Lines 10

Duplication

Lines 17
Ratio 100 %

Importance

Changes 0
Metric Value
cc 6
eloc 10
nc 4
nop 2
dl 17
loc 17
rs 8.8571
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_SAMACCOUNTNAME             = 47;
64
    const INVALID_DIRECTORY             = 101;
65
    const INVALID_FILE                  = 102;
66
    const INVALID_READABLE              = 103;
67
    const INVALID_WRITEABLE             = 104;
68
    const INVALID_CLASS                 = 105;
69
    const INVALID_EMAIL                 = 201;
70
    const INTERFACE_NOT_IMPLEMENTED     = 202;
71
    const INVALID_URL                   = 203;
72
    const INVALID_NOT_INSTANCE_OF       = 204;
73
    const VALUE_NOT_EMPTY               = 205;
74
    const INVALID_JSON_STRING           = 206;
75
    const INVALID_OBJECT                = 207;
76
    const INVALID_METHOD                = 208;
77
    const INVALID_SCALAR                = 209;
78
    const INVALID_DATE                  = 210;
79
    const INVALID_CALLABLE              = 211;
80
    const INVALID_KEYS_EXIST            = 300;
81
    const INVALID_PROPERTY_EXISTS       = 301;
82
    const INVALID_PROPERTIES_EXIST      = 302;
83
    const INVALID_UTF8                  = 303;
84
    const INVALID_DOMAIN_NAME           = 304;
85
    const INVALID_NOT_FALSE             = 305;
86
    const INVALID_FILE_OR_DIR           = 306;
87
    const INVALID_ASCII                 = 307;
88
    const INVALID_NOT_REGEX             = 308;
89
    const INVALID_GREATER_THAN          = 309;
90
    const INVALID_LESS_THAN             = 310;
91
    const INVALID_GREATER_THAN_OR_EQ    = 311;
92
    const INVALID_LESS_THAN_OR_EQ       = 312;
93
    const INVALID_IP_ADDRESS            = 313;
94
    const INVALID_AUS_MOBILE            = 314;
95
96
    const EMERGENCY                     = 'emergency';
97
    const ALERT                         = 'alert';
98
    const CRITICAL                      = 'critical';
99
    const ERROR                         = 'error';
100
    const WARNING                       = 'warning';
101
    const NOTICE                        = 'notice';
102
    const INFO                          = 'info';
103
    const DEBUG                         = 'debug';
104
105
    /** @var bool */
106
    protected $nullOr                   = false;
107
108
    /** @var bool */
109
    protected $emptyOr                  = false;
110
111
    /** @var mixed */
112
    protected $value                    = null;
113
114
    /** @var bool */
115
    protected $all                      = false;
116
117
    /** @var null|string */
118
    protected $propertyPath             = null;
119
120
    /** @var null|string */
121
    protected $level                    = 'critical';
122
123
    /** @var int */
124
    protected $overrideCode             = null;
125
126
    /** @var string */
127
    protected $overrideError            = '';
128
    /**
129
     * Exception to throw when an assertion failed.
130
     *
131
     * @var string
132
     */
133
    protected $exceptionClass           = 'Terah\Assert\AssertionFailedException';
134
135
    /**
136
     * @param mixed $value
137
     */
138
    public function __construct($value)
139
    {
140
        $this->value($value);
141
    }
142
143
    /**
144
     * @param        $value
145
     * @param string $name
146
     * @param int    $code
147
     * @param string $error
148
     * @param string $level
149
     * @return Assert
150
     */
151 View Code Duplication
    public static function that($value, $name='', $code=0, $error='', $level=Assert::WARNING)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

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

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2118
    {
2119
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2120
        {
2121
            return $this;
2122
        }
2123
        try
2124
        {
2125
            $this->regex('/^04[0-9]{8})$/', $message, $propertyPath);
2126
        }
2127
        catch ( AssertionFailedException $e )
2128
        {
2129
            $message = $message ?: $this->overrideError;
2130
            $message = sprintf(
2131
                $message
2132
                    ?: 'Value "%s" is not an australian mobile number.',
2133
                $this->stringify($this->value)
2134
            );
2135
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_AUS_MOBILE, $propertyPath);
2136
        }
2137
        return $this;
2138
    }
2139
2140
    /**
2141
     * Assert that value is alphanumeric.
2142
     *
2143
     * @param string|null $message
2144
     * @param string|null $propertyPath
2145
     * @return Assert
2146
     * @throws AssertionFailedException
2147
     */
2148 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...
2149
    {
2150
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2151
        {
2152
            return $this;
2153
        }
2154
        try
2155
        {
2156
            $this->regex('(^([a-zA-Z]{1}[a-zA-Z0-9]*)$)', $message, $propertyPath);
2157
        }
2158
        catch (AssertionFailedException $e)
2159
        {
2160
            $message = $message ?: $this->overrideError;
2161
            $message = sprintf(
2162
                $message
2163
                    ?: 'Value "%s" is not alphanumeric, starting with letters and containing only letters and numbers.',
2164
                $this->stringify($this->value)
2165
            );
2166
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_ALNUM, $propertyPath);
2167
        }
2168
        return $this;
2169
    }
2170
2171
    /**
2172
     * Assert that the value is boolean True.
2173
     *
2174
     * @param string|null $message
2175
     * @param string|null $propertyPath
2176
     * @return Assert
2177
     * @throws AssertionFailedException
2178
     */
2179
    public function true($message = null, $propertyPath = null)
2180
    {
2181
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2182
        {
2183
            return $this;
2184
        }
2185
        if ( $this->value !== true )
2186
        {
2187
            $message = $message ?: $this->overrideError;
2188
            $message = sprintf(
2189
                $message ?: 'Value "%s" is not TRUE.',
2190
                $this->stringify($this->value)
2191
            );
2192
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_TRUE, $propertyPath);
2193
        }
2194
2195
        return $this;
2196
    }
2197
2198
    /**
2199
     * Assert that the value is boolean True.
2200
     *
2201
     * @param string|null $message
2202
     * @param string|null $propertyPath
2203
     * @return Assert
2204
     * @throws AssertionFailedException
2205
     */
2206
    public function truthy($message = null, $propertyPath = null)
2207
    {
2208
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2209
        {
2210
            return $this;
2211
        }
2212
        if ( ! $this->value )
2213
        {
2214
            $message = $message ?: $this->overrideError;
2215
            $message = sprintf(
2216
                $message ?: 'Value "%s" is not truthy.',
2217
                $this->stringify($this->value)
2218
            );
2219
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_TRUE, $propertyPath);
2220
        }
2221
        return $this;
2222
    }
2223
2224
    /**
2225
     * Assert that the value is boolean False.
2226
     *
2227
     * @param string|null $message
2228
     * @param string|null $propertyPath
2229
     * @return Assert
2230
     * @throws AssertionFailedException
2231
     */
2232
    public function false($message = null, $propertyPath = null)
2233
    {
2234
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2235
        {
2236
            return $this;
2237
        }
2238
        if ( $this->value !== false )
2239
        {
2240
            $message = $message ?: $this->overrideError;
2241
            $message = sprintf(
2242
                $message ?: 'Value "%s" is not FALSE.',
2243
                $this->stringify($this->value)
2244
            );
2245
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_FALSE, $propertyPath);
2246
        }
2247
        return $this;
2248
    }
2249
2250
    /**
2251
     * Assert that the value is not boolean False.
2252
     *
2253
     * @param string|null $message
2254
     * @param string|null $propertyPath
2255
     * @return Assert
2256
     * @throws AssertionFailedException
2257
     */
2258
    public function notFalse($message = null, $propertyPath = null)
2259
    {
2260
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2261
        {
2262
            return $this;
2263
        }
2264
        if ( $this->value === false )
2265
        {
2266
            $message = $message ?: $this->overrideError;
2267
            $message = sprintf(
2268
                $message ?: 'Value "%s" is not FALSE.',
2269
                $this->stringify($this->value)
2270
            );
2271
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NOT_FALSE, $propertyPath);
2272
        }
2273
        return $this;
2274
    }
2275
2276
    /**
2277
     * Assert that the class exists.
2278
     *
2279
     * @param string|null $message
2280
     * @param string|null $propertyPath
2281
     * @return Assert
2282
     * @throws AssertionFailedException
2283
     */
2284
    public function classExists($message = null, $propertyPath = null)
2285
    {
2286
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2287
        {
2288
            return $this;
2289
        }
2290
        if ( !class_exists($this->value) )
2291
        {
2292
            $message = $message ?: $this->overrideError;
2293
            $message = sprintf(
2294
                $message ?: 'Class "%s" does not exist.',
2295
                $this->stringify($this->value)
2296
            );
2297
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_CLASS, $propertyPath);
2298
        }
2299
        return $this;
2300
    }
2301
2302
    /**
2303
     * Assert that the class implements the interface
2304
     *
2305
     * @param string      $interfaceName
2306
     * @param string|null $message
2307
     * @param string|null $propertyPath
2308
     * @return Assert
2309
     * @throws AssertionFailedException
2310
     */
2311
    public function implementsInterface($interfaceName, $message = null, $propertyPath = null)
2312
    {
2313
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2314
        {
2315
            return $this;
2316
        }
2317
        $reflection = new \ReflectionClass($this->value);
2318
        if ( !$reflection->implementsInterface($interfaceName) )
2319
        {
2320
            $message = $message ?: $this->overrideError;
2321
            $message = sprintf(
2322
                $message ?: 'Class "%s" does not implement interface "%s".',
2323
                $this->stringify($this->value),
2324
                $this->stringify($interfaceName)
2325
            );
2326
            throw $this->createException($message, self::INTERFACE_NOT_IMPLEMENTED, $propertyPath, ['interface' => $interfaceName]);
2327
        }
2328
        return $this;
2329
    }
2330
2331
    /**
2332
     * Assert that the given string is a valid json string.
2333
     *
2334
     * NOTICE:
2335
     * Since this does a json_decode to determine its validity
2336
     * you probably should consider, when using the variable
2337
     * content afterwards, just to decode and check for yourself instead
2338
     * of using this assertion.
2339
     *
2340
     * @param string|null $message
2341
     * @param string|null $propertyPath
2342
     * @return Assert
2343
     * @throws AssertionFailedException
2344
     */
2345
    public function isJsonString($message = null, $propertyPath = null)
2346
    {
2347
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2348
        {
2349
            return $this;
2350
        }
2351
        if ( null === json_decode($this->value) && JSON_ERROR_NONE !== json_last_error() )
2352
        {
2353
            $message = $message ?: $this->overrideError;
2354
            $message = sprintf(
2355
                $message ?: 'Value "%s" is not a valid JSON string.',
2356
                $this->stringify($this->value)
2357
            );
2358
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_JSON_STRING, $propertyPath);
2359
        }
2360
        return $this;
2361
    }
2362
2363
    /**
2364
     * Assert that the given string is a valid UUID
2365
     *
2366
     * Uses code from {@link https://github.com/ramsey/uuid} that is MIT licensed.
2367
     *
2368
     * @param string|null $message
2369
     * @param string|null $propertyPath
2370
     * @return Assert
2371
     * @throws AssertionFailedException
2372
     */
2373
    public function uuid($message = null, $propertyPath = null)
2374
    {
2375
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2376
        {
2377
            return $this;
2378
        }
2379
        $this->value = str_replace(['urn:', 'uuid:', '{', '}'], '', $this->value);
2380
        if ( $this->value === '00000000-0000-0000-0000-000000000000' )
2381
        {
2382
            return $this;
2383
        }
2384
        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) )
2385
        {
2386
            $message = $message ?: $this->overrideError;
2387
            $message = sprintf(
2388
                $message ?: 'Value "%s" is not a valid UUID.',
2389
                $this->stringify($this->value)
2390
            );
2391
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_UUID, $propertyPath);
2392
        }
2393
        return $this;
2394
    }
2395
    /**
2396
     * Assert that the given string is a valid samAccountName (in line with Active directory sAMAccountName restrictions for users)
2397
     *
2398
     * From: https://social.technet.microsoft.com/wiki/contents/articles/11216.active-directory-requirements-for-creating-objects.aspx#Objects_with_sAMAccountName_Attribute
2399
     *      The schema allows 256 characters in sAMAccountName values. However, the system limits sAMAccountName to 20 characters for user objects and 16 characters for computer objects.
2400
     *      The following characters are not allowed in sAMAccountName values: " [ ] : ; | = + * ? < > / \ ,
2401
     *      you cannot logon to a domain using a sAMAccountName that includes the "@" character. If a user has a sAMAccountName with this character, they must logon using their userPrincipalName (UPN).
2402
     *
2403
     * @param string|null $message
2404
     * @param string|null $propertyPath
2405
     * @return Assert
2406
     * @throws AssertionFailedException
2407
     */
2408 View Code Duplication
    public function samAccountName($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...
2409
    {
2410
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2411
        {
2412
            return $this;
2413
        }
2414
        if ( !preg_match('/^([a-z0-9]{4,20})$/', $this->value) )
2415
        {
2416
            $message = $message ?: $this->overrideError;
2417
            $message = sprintf(
2418
                $message ?: 'Value "%s" is not a valid samAccountName.',
2419
                $this->stringify($this->value)
2420
            );
2421
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_SAMACCOUNTNAME, $propertyPath);
2422
        }
2423
        return $this;
2424
    }
2425
    /**
2426
     * Assert that the count of countable is equal to count.
2427
     *
2428
     * @param int    $count
2429
     * @param string $message
2430
     * @param string $propertyPath
2431
     * @return Assert
2432
     * @throws AssertionFailedException
2433
     */
2434
    public function count($count, $message = null, $propertyPath = null)
2435
    {
2436
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2437
        {
2438
            return $this;
2439
        }
2440
        if ( $count !== count($this->value) )
2441
        {
2442
            $message = $message ?: $this->overrideError;
2443
            $message = sprintf(
2444
                $message ?: 'List does not contain exactly "%d" elements.',
2445
                $this->stringify($this->value),
2446
                $this->stringify($count)
2447
            );
2448
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_COUNT, $propertyPath, ['count' => $count]);
2449
        }
2450
        return $this;
2451
    }
2452
2453
    /**
2454
     * @param $func
2455
     * @param $args
2456
     * @return bool
2457
     * @throws AssertionFailedException
2458
     */
2459
    protected function doAllOrNullOr($func, $args)
2460
    {
2461
        if ( $this->nullOr && is_null($this->value) )
2462
        {
2463
            return true;
2464
        }
2465
        if ( $this->emptyOr && empty($this->value) )
2466
        {
2467
            return true;
2468
        }
2469
        if ( $this->all && (new Assert($this->value))->setExceptionClass($this->exceptionClass)->isTraversable() )
2470
        {
2471
            foreach ( $this->value as $idx => $value )
2472
            {
2473
                $object = (new Assert($value))->setExceptionClass($this->exceptionClass);
2474
                call_user_func_array([$object, $func], $args);
2475
            }
2476
            return true;
2477
        }
2478
        return ( $this->nullOr && is_null($this->value) ) || ( $this->emptyOr && empty($this->value) ) ? true : false;
2479
    }
2480
2481
    /**
2482
     * Determines if the values array has every choice as key and that this choice has content.
2483
     *
2484
     * @param array $choices
2485
     * @param string|null $message
2486
     * @param string|null $propertyPath
2487
     * @return $this
2488
     */
2489
    public function choicesNotEmpty(array $choices, $message = null, $propertyPath = null)
2490
    {
2491
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2492
        {
2493
            return $this;
2494
        }
2495
        $this->notEmpty($message, $propertyPath);
2496
        foreach ( $choices as $choice )
2497
        {
2498
            $this->notEmptyKey($choice, $message, $propertyPath);
2499
        }
2500
        return $this;
2501
    }
2502
2503
    /**
2504
     * Determines that the named method is defined in the provided object.
2505
     *
2506
     * @param mixed $object
2507
     * @param string|null $message
2508
     * @param string|null $propertyPath
2509
     * @returns Assert
2510
     * @throws
2511
     */
2512
    public function methodExists($object, $message = null, $propertyPath = null)
2513
    {
2514
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2515
        {
2516
            return $this;
2517
        }
2518
        (new Assert($object))->setExceptionClass($this->exceptionClass)->isObject($message, $propertyPath);
2519
        if ( !method_exists($object, $this->value) )
2520
        {
2521
            $message = $message ?: $this->overrideError;
2522
            $message = sprintf(
2523
                $message ?: 'Expected "%s" does not a exist in provided object.',
2524
                $this->stringify($this->value)
2525
            );
2526
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_METHOD, $propertyPath);
2527
        }
2528
        return $this;
2529
    }
2530
2531
    /**
2532
     * Determines that the provided value is an object.
2533
     *
2534
     * @param string|null $message
2535
     * @param string|null $propertyPath
2536
     * @return $this
2537
     * @throws AssertionFailedException
2538
     */
2539
    public function isObject($message = null, $propertyPath = null)
2540
    {
2541
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2542
        {
2543
            return $this;
2544
        }
2545
        if ( !is_object($this->value) )
2546
        {
2547
            $message = $message ?: $this->overrideError;
2548
            $message = sprintf(
2549
                $message ?: 'Provided "%s" is not a valid object.',
2550
                $this->stringify($this->value)
2551
            );
2552
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_OBJECT, $propertyPath);
2553
        }
2554
        return $this;
2555
    }
2556
2557
    /**
2558
     * Make a string version of a value.
2559
     *
2560
     * @param $value
2561
     * @return string
2562
     */
2563
    private function stringify($value)
2564
    {
2565
        if ( is_bool($value) )
2566
        {
2567
            return $value ? '<TRUE>' : '<FALSE>';
2568
        }
2569
        if ( is_scalar($value) )
2570
        {
2571
            $val = (string)$value;
2572
            if ( strlen($val) > 100 )
2573
            {
2574
                $val = substr($val, 0, 97) . '...';
2575
            }
2576
            return $val;
2577
        }
2578
        if ( is_array($value) )
2579
        {
2580
            return '<ARRAY>';
2581
        }
2582
        if ( is_object($value) )
2583
        {
2584
            return get_class($value);
2585
        }
2586
        if ( is_resource($value) )
2587
        {
2588
            return '<RESOURCE>';
2589
        }
2590
        if ( $value === null )
2591
        {
2592
            return '<NULL>';
2593
        }
2594
        return 'unknown';
2595
    }
2596
}
2597
2598