Completed
Push — master ( 402bf1...e7dba6 )
by Terry
03:00
created

Assert::isJsonString()   B

Complexity

Conditions 7
Paths 4

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 10
nc 4
nop 2
dl 0
loc 17
rs 8.2222
c 0
b 0
f 0
1
<?php
2
3
namespace Terah\Assert;
4
5
    /**
6
     * Assert
7
     *
8
     * LICENSE
9
     *
10
     * This source file is subject to the new BSD license that is bundled
11
     * with this package in the file LICENSE.txt.
12
     * If you did not receive a copy of the license and are unable to
13
     * obtain it through the world-wide-web, please send an email
14
     * to [email protected] so I can send you a copy immediately.
15
     */
16
17
/**
18
 * Assert library
19
 *
20
 * @author Benjamin Eberlei <[email protected]>
21
 * @author Terry Cullen <[email protected]>
22
 *
23
 */
24
class Assert
25
{
26
    const INVALID_FLOAT                 = 9;
27
    const INVALID_INTEGER               = 10;
28
    const INVALID_DIGIT                 = 11;
29
    const INVALID_INTEGERISH            = 12;
30
    const INVALID_BOOLEAN               = 13;
31
    const VALUE_EMPTY                   = 14;
32
    const VALUE_NULL                    = 15;
33
    const INVALID_STRING                = 16;
34
    const INVALID_REGEX                 = 17;
35
    const INVALID_MIN_LENGTH            = 18;
36
    const INVALID_MAX_LENGTH            = 19;
37
    const INVALID_STRING_START          = 20;
38
    const INVALID_STRING_CONTAINS       = 21;
39
    const INVALID_CHOICE                = 22;
40
    const INVALID_NUMERIC               = 23;
41
    const INVALID_ARRAY                 = 24;
42
    const INVALID_KEY_EXISTS            = 26;
43
    const INVALID_NOT_BLANK             = 27;
44
    const INVALID_INSTANCE_OF           = 28;
45
    const INVALID_SUBCLASS_OF           = 29;
46
    const INVALID_RANGE                 = 30;
47
    const INVALID_ALNUM                 = 31;
48
    const INVALID_TRUE                  = 32;
49
    const INVALID_EQ                    = 33;
50
    const INVALID_SAME                  = 34;
51
    const INVALID_MIN                   = 35;
52
    const INVALID_MAX                   = 36;
53
    const INVALID_LENGTH                = 37;
54
    const INVALID_FALSE                 = 38;
55
    const INVALID_STRING_END            = 39;
56
    const INVALID_UUID                  = 40;
57
    const INVALID_COUNT                 = 41;
58
    const INVALID_NOT_EQ                = 42;
59
    const INVALID_NOT_SAME              = 43;
60
    const INVALID_TRAVERSABLE           = 44;
61
    const INVALID_ARRAY_ACCESSIBLE      = 45;
62
    const INVALID_KEY_ISSET             = 46;
63
    const INVALID_DIRECTORY             = 101;
64
    const INVALID_FILE                  = 102;
65
    const INVALID_READABLE              = 103;
66
    const INVALID_WRITEABLE             = 104;
67
    const INVALID_CLASS                 = 105;
68
    const INVALID_EMAIL                 = 201;
69
    const INTERFACE_NOT_IMPLEMENTED     = 202;
70
    const INVALID_URL                   = 203;
71
    const INVALID_NOT_INSTANCE_OF       = 204;
72
    const VALUE_NOT_EMPTY               = 205;
73
    const INVALID_JSON_STRING           = 206;
74
    const INVALID_OBJECT                = 207;
75
    const INVALID_METHOD                = 208;
76
    const INVALID_SCALAR                = 209;
77
    const INVALID_DATE                  = 210;
78
    const INVALID_CALLABLE              = 211;
79
    const INVALID_KEYS_EXIST            = 300;
80
    const INVALID_PROPERTY_EXISTS       = 301;
81
    const INVALID_PROPERTIES_EXIST      = 302;
82
    const INVALID_UTF8                  = 303;
83
    const INVALID_DOMAIN_NAME           = 304;
84
    const INVALID_NOT_FALSE             = 305;
85
    const INVALID_FILE_OR_DIR           = 306;
86
    const INVALID_ASCII                 = 307;
87
    const INVALID_NOT_REGEX             = 308;
88
    const INVALID_GREATER_THAN          = 309;
89
    const INVALID_LESS_THAN             = 310;
90
    const INVALID_GREATER_THAN_OR_EQ    = 311;
91
    const INVALID_LESS_THAN_OR_EQ       = 312;
92
    const INVALID_IP_ADDRESS            = 313;
93
94
    const EMERGENCY                     = 'emergency';
95
    const ALERT                         = 'alert';
96
    const CRITICAL                      = 'critical';
97
    const ERROR                         = 'error';
98
    const WARNING                       = 'warning';
99
    const NOTICE                        = 'notice';
100
    const INFO                          = 'info';
101
    const DEBUG                         = 'debug';
102
103
    /** @var bool */
104
    protected $nullOr                   = false;
105
106
    /** @var bool */
107
    protected $emptyOr                  = false;
108
109
    /** @var mixed */
110
    protected $value                    = null;
111
112
    /** @var bool */
113
    protected $all                      = false;
114
115
    /** @var null|string */
116
    protected $propertyPath             = null;
117
118
    /** @var null|string */
119
    protected $level                    = 'critical';
120
121
    /** @var int */
122
    protected $overrideCode             = null;
123
124
    /** @var string */
125
    protected $overrideError            = '';
126
    /**
127
     * Exception to throw when an assertion failed.
128
     *
129
     * @var string
130
     */
131
    protected $exceptionClass           = 'Terah\Assert\AssertionFailedException';
132
133
    /**
134
     * @param mixed $value
135
     */
136
    public function __construct($value)
137
    {
138
        $this->value($value);
139
    }
140
141
    /**
142
     * @param $value
143
     * @return Assert
144
     */
145
    public static function that($value)
146
    {
147
        return new Assert($value);
148
    }
149
150
    /**
151
     * @param mixed $value
152
     * @return Assert
153
     */
154
    public function reset($value)
155
    {
156
        return $this->all(false)->nullOr(false)->value($value);
157
    }
158
159
    /**
160
     * @param mixed $value
161
     * @return Assert
162
     */
163
    public function value($value)
164
    {
165
        $this->value = $value;
166
        return $this;
167
    }
168
169
    /**
170
     * @param bool $nullOr
171
     * @return Assert
172
     */
173
    public function nullOr($nullOr = true)
174
    {
175
        $this->nullOr = $nullOr;
176
        return $this;
177
    }
178
179
    /**
180
     * @param bool $emptyOr
181
     * @return Assert
182
     */
183
    public function emptyOr($emptyOr = true)
184
    {
185
        $this->emptyOr = $emptyOr;
186
        return $this;
187
    }
188
189
    /**
190
     * @param bool $all
191
     * @return Assert
192
     */
193
    public function all($all = true)
194
    {
195
        $this->all = $all;
196
        return $this;
197
    }
198
199
    /**
200
     * Helper method that handles building the assertion failure exceptions.
201
     * They are returned from this method so that the stack trace still shows
202
     * the assertions method.
203
     *
204
     * @param string $message
205
     * @param int    $code
206
     * @param string $propertyPath
207
     * @param array  $constraints
208
     * @param string $level
209
     * @return AssertionFailedException
210
     */
211
    protected function createException($message, $code, $propertyPath, array $constraints = [], $level=null)
212
    {
213
        $exceptionClass = $this->exceptionClass;
214
        $propertyPath   = is_null($propertyPath) ? $this->propertyPath : $propertyPath;
215
        $level          = is_null($level) ? $this->level : $level;
216
217
        return new $exceptionClass($message, $code, $propertyPath, $this->value, $constraints, $level);
218
    }
219
220
    /**
221
     * @param $exceptionClass
222
     * @return Assert
223
     */
224
    public function setExceptionClass($exceptionClass)
225
    {
226
        $this->exceptionClass = $exceptionClass;
227
        return $this;
228
    }
229
230
    /**
231
     * @param int $code
232
     * @return Assert
233
     */
234
    public function code($code)
235
    {
236
        $this->overrideCode = $code;
237
        return $this;
238
    }
239
240
    /**
241
     * @param int $level
242
     * @return Assert
243
     */
244
    public function level($level)
245
    {
246
        $this->level = $level;
0 ignored issues
show
Documentation Bug introduced by
It seems like $level of type integer is incompatible with the declared type null|string of property $level.

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

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

Loading history...
247
        return $this;
248
    }
249
250
    /**
251
     * @param string $error
252
     * @return Assert
253
     */
254
    public function error($error)
255
    {
256
        $this->overrideError = $error;
257
        return $this;
258
    }
259
260
    /**
261
     * @param string $name
262
     * @return Assert
263
     */
264
    public function name($name)
265
    {
266
        $this->propertyPath = $name;
267
        return $this;
268
    }
269
270
    /**
271
     * Assert that two values are equal (using == ).
272
     *
273
     * @param mixed       $value2
274
     * @param string|null $message
275
     * @param string|null $propertyPath
276
     * @return Assert
277
     * @throws AssertionFailedException
278
     */
279
    public function eq($value2, $message = null, $propertyPath = null)
280
    {
281
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
282
        {
283
            return $this;
284
        }
285 View Code Duplication
        if ( $this->value != $value2 )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
286
        {
287
            $message = $message ?: $this->overrideError;
288
            $message = sprintf(
289
                $message ?: 'Value "%s" does not equal expected value "%s".',
290
                $this->stringify($this->value),
291
                $this->stringify($value2)
292
            );
293
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_EQ, $propertyPath, ['expected' => $value2]);
294
        }
295
        return $this;
296
    }
297
298
    /**
299
     *
300
     * @param mixed       $value2
301
     * @param string|null $message
302
     * @param string|null $propertyPath
303
     * @return Assert
304
     * @throws AssertionFailedException
305
     */
306
    public function greaterThan($value2, $message = null, $propertyPath = null)
307
    {
308
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
309
        {
310
            return $this;
311
        }
312 View Code Duplication
        if ( ! ( $this->value > $value2 ) )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading history...
450
        {
451
            $message = $message ?: $this->overrideError;
452
            $message = sprintf(
453
                $message ?: 'Value "%s" is equal to expected value "%s".',
454
                $this->stringify($this->value),
455
                $this->stringify($value2)
456
            );
457
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NOT_EQ, $propertyPath, ['expected' => $value2]);
458
        }
459
        return $this;
460
    }
461
462
    /**
463
     * @param string|null $message
464
     * @param string|null        $propertyPath
465
     *
466
     * @return $this
467
     * @throws AssertionFailedException
468
     */
469
    public function isCallable($message = null, $propertyPath = null)
470
    {
471
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
472
        {
473
            return $this;
474
        }
475
        if ( !is_callable($this->value) )
476
        {
477
            $message = $message ?: $this->overrideError;
478
            $message = sprintf(
479
                $message ?: 'Value "%s" is not callable.',
480
                $this->stringify($this->value)
481
            );
482
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NOT_EQ, $propertyPath);
483
        }
484
        return $this;
485
    }
486
487
    /**
488
     * Assert that two values are not the same (using === ).
489
     *
490
     * @param mixed       $value2
491
     * @param string|null $message
492
     * @param string|null $propertyPath
493
     * @return Assert
494
     * @throws AssertionFailedException
495
     */
496
    public function notSame($value2, $message = null, $propertyPath = null)
497
    {
498
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
499
        {
500
            return $this;
501
        }
502 View Code Duplication
        if ( $this->value === $value2 )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
503
        {
504
            $message = $message ?: $this->overrideError;
505
            $message = sprintf(
506
                $message ?: 'Value "%s" is the same as expected value "%s".',
507
                $this->stringify($this->value),
508
                $this->stringify($value2)
509
            );
510
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NOT_SAME, $propertyPath, ['expected' => $value2]);
511
        }
512
        return $this;
513
    }
514
515
    /**
516
     * @param string|null $message
517
     * @param string|null $propertyPath
518
     * @return Assert
519
     * @throws AssertionFailedException
520
     */
521
    public function id($message = null, $propertyPath = null)
522
    {
523
        $message = $message ?: $this->overrideError;
524
        $message = $message ?: 'Value "%s" is not an integer id.';
525
        return $this->nonEmptyInt($message, $propertyPath)->range(1, PHP_INT_MAX);
526
    }
527
528
    /**
529
     * @param string|null $message
530
     * @param string|null $propertyPath
531
     * @return Assert
532
     * @throws AssertionFailedException
533
     */
534
    public function flag($message = null, $propertyPath = null)
535
    {
536
        $message = $message ?: $this->overrideError;
537
        $message = $message ?: 'Value "%s" is not a 0 or 1.';
538
        return $this->range(0, 1, $message, $propertyPath);
539
    }
540
541
    /**
542
     * @param string|null $message
543
     * @param string|null $propertyPath
544
     * @return Assert
545
     * @throws AssertionFailedException
546
     */
547
    public function status($message = null, $propertyPath = null)
548
    {
549
        $message = $message ?: $this->overrideError;
550
        $message = $message ?: 'Value "%s" is not a valid status.';
551
        return $this->integer($message, $propertyPath)->inArray([-1, 0, 1]);
552
    }
553
554
    /**
555
     * @param string|null $message
556
     * @param string|null $propertyPath
557
     * @return Assert
558
     */
559
    public function nullOrId($message = null, $propertyPath = null)
560
    {
561
        return $this->nullOr()->id($message, $propertyPath);
562
    }
563
564
    /**
565
     * @param string|null $message
566
     * @param string|null $propertyPath
567
     * @return Assert
568
     */
569
    public function allIds($message = null, $propertyPath = null)
570
    {
571
        return $this->all()->id($message, $propertyPath);
572
    }
573
574
    /**
575
     * @param string|null $message
576
     * @param string|null $propertyPath
577
     * @return Assert
578
     * @throws AssertionFailedException
579
     */
580
    public function int($message = null, $propertyPath = null)
581
    {
582
        return $this->integer($message, $propertyPath);
583
    }
584
585
    /**
586
     * Assert that value is a php integer.
587
     *
588
     * @param string|null $message
589
     * @param string|null $propertyPath
590
     * @return Assert
591
     * @throws AssertionFailedException
592
     */
593
    public function integer($message = null, $propertyPath = null)
594
    {
595
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
596
        {
597
            return $this;
598
        }
599
        if ( !is_int($this->value) )
600
        {
601
            $message = $message ?: $this->overrideError;
602
            $message = sprintf(
603
                $message ?: 'Value "%s" is not an integer.',
604
                $this->stringify($this->value)
605
            );
606
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_INTEGER, $propertyPath);
607
        }
608
        return $this;
609
    }
610
611
    /**
612
     * Assert that value is a php float.
613
     *
614
     * @param string|null $message
615
     * @param string|null $propertyPath
616
     * @return Assert
617
     * @throws AssertionFailedException
618
     */
619
    public function float($message = null, $propertyPath = null)
620
    {
621
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
622
        {
623
            return $this;
624
        }
625
        if ( ! is_float($this->value) )
626
        {
627
            $message = $message ?: $this->overrideError;
628
            $message = sprintf(
629
                $message ?: 'Value "%s" is not a float.',
630
                $this->stringify($this->value)
631
            );
632
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_FLOAT, $propertyPath);
633
        }
634
        return $this;
635
    }
636
637
    /**
638
     * Validates if an integer or integerish is a digit.
639
     *
640
     * @param string|null $message
641
     * @param string|null $propertyPath
642
     * @return Assert
643
     * @throws AssertionFailedException
644
     */
645
    public function digit($message = null, $propertyPath = null)
646
    {
647
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
648
        {
649
            return $this;
650
        }
651
        if ( ! ctype_digit((string)$this->value) )
652
        {
653
            $message = $message ?: $this->overrideError;
654
            $message = sprintf(
655
                $message ?: 'Value "%s" is not a digit.',
656
                $this->stringify($this->value)
657
            );
658
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_DIGIT, $propertyPath);
659
        }
660
        return $this;
661
    }
662
663
    /**
664
     * Validates if an string is a date .
665
     *
666
     * @param string|null $message
667
     * @param string|null $propertyPath
668
     * @return Assert
669
     * @throws AssertionFailedException
670
     */
671
    public function date($message = null, $propertyPath = null)
672
    {
673
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
674
        {
675
            return $this;
676
        }
677
        $this->notEmpty($message, $propertyPath);
678
        if ( strtotime($this->value) === false )
679
        {
680
            $message = $message ?: $this->overrideError;
681
            $message = sprintf(
682
                $message ?: 'Value "%s" is not a date.',
683
                $this->stringify($this->value)
684
            );
685
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_DATE, $propertyPath);
686
        }
687
        return $this;
688
    }
689
690
    /**
691
     * Assert that value is a php integer'ish.
692
     *
693
     * @param string|null $message
694
     * @param string|null $propertyPath
695
     * @return Assert
696
     * @throws AssertionFailedException
697
     */
698
    public function integerish($message = null, $propertyPath = null)
699
    {
700
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
701
        {
702
            return $this;
703
        }
704
        if ( is_object($this->value) || strval(intval($this->value)) != $this->value || is_bool($this->value) || is_null($this->value) )
705
        {
706
            $message = $message ?: $this->overrideError;
707
            $message = sprintf(
708
                $message ?: 'Value "%s" is not an integer or a number castable to integer.',
709
                $this->stringify($this->value)
710
            );
711
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_INTEGERISH, $propertyPath);
712
        }
713
        return $this;
714
    }
715
716
    /**
717
     * Assert that value is php boolean
718
     *
719
     * @param string|null $message
720
     * @param string|null $propertyPath
721
     * @return Assert
722
     * @throws AssertionFailedException
723
     */
724
    public function boolean($message = null, $propertyPath = null)
725
    {
726
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
727
        {
728
            return $this;
729
        }
730
        if ( ! is_bool($this->value) )
731
        {
732
            $message = $message ?: $this->overrideError;
733
            $message = sprintf(
734
                $message ?: 'Value "%s" is not a boolean.',
735
                $this->stringify($this->value)
736
            );
737
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_BOOLEAN, $propertyPath);
738
        }
739
        return $this;
740
    }
741
742
    /**
743
     * Assert that value is a PHP scalar
744
     *
745
     * @param string|null $message
746
     * @param string|null $propertyPath
747
     * @return Assert
748
     * @throws AssertionFailedException
749
     */
750
    public function scalar($message = null, $propertyPath = null)
751
    {
752
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
753
        {
754
            return $this;
755
        }
756
        if ( !is_scalar($this->value) )
757
        {
758
            $message = $message ?: $this->overrideError;
759
            $message = sprintf(
760
                $message ?: 'Value "%s" is not a scalar.',
761
                $this->stringify($this->value)
762
            );
763
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_SCALAR, $propertyPath);
764
        }
765
        return $this;
766
    }
767
768
    /**
769
     * Assert that value is not empty
770
     *
771
     * @param string|null $message
772
     * @param string|null $propertyPath
773
     * @return Assert
774
     * @throws AssertionFailedException
775
     */
776 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...
777
    {
778
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
779
        {
780
            return $this;
781
        }
782
        if ( ( is_object($this->value) && empty((array)$this->value) ) || empty($this->value) )
783
        {
784
            $message = $message ?: $this->overrideError;
785
            $message = sprintf(
786
                $message ?: 'Value "%s" is empty, but non empty value was expected.',
787
                $this->stringify($this->value)
788
            );
789
            throw $this->createException($message, $this->overrideCode ?: self::VALUE_EMPTY, $propertyPath);
790
        }
791
        return $this;
792
    }
793
794
    /**
795
     * Assert that value is empty
796
     *
797
     * @param string|null $message
798
     * @param string|null $propertyPath
799
     * @return Assert
800
     * @throws AssertionFailedException
801
     */
802
    public function noContent($message = null, $propertyPath = null)
803
    {
804
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
805
        {
806
            return $this;
807
        }
808
        if ( !empty( $this->value ) )
809
        {
810
            $message = $message ?: $this->overrideError;
811
            $message = sprintf(
812
                $message ?: 'Value "%s" is not empty, but empty value was expected.',
813
                $this->stringify($this->value)
814
            );
815
            throw $this->createException($message, $this->overrideCode ?: self::VALUE_NOT_EMPTY, $propertyPath);
816
        }
817
        return $this;
818
    }
819
820
    /**
821
     * Assert that value is not null
822
     *
823
     * @param string|null $message
824
     * @param string|null $propertyPath
825
     * @return Assert
826
     * @throws AssertionFailedException
827
     */
828
    public function notNull($message = null, $propertyPath = null)
829
    {
830
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
831
        {
832
            return $this;
833
        }
834
        if ( $this->value === null )
835
        {
836
            $message = $message ?: $this->overrideError;
837
            $message = sprintf(
838
                $message ?: 'Value "%s" is null, but non null value was expected.',
839
                $this->stringify($this->value)
840
            );
841
            throw $this->createException($message, $this->overrideCode ?: self::VALUE_NULL, $propertyPath);
842
        }
843
        return $this;
844
    }
845
846
    /**
847
     * Assert that value is a string
848
     *
849
     * @param string|null $message
850
     * @param string|null $propertyPath
851
     * @return Assert
852
     * @throws AssertionFailedException
853
     */
854
    public function string($message = null, $propertyPath = null)
855
    {
856
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
857
        {
858
            return $this;
859
        }
860
        if ( !is_string($this->value) )
861
        {
862
            $message = $message ?: $this->overrideError;
863
            $message = sprintf(
864
                $message ?: 'Value "%s" expected to be string, type %s given.',
865
                $this->stringify($this->value),
866
                gettype($this->value)
867
            );
868
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_STRING, $propertyPath);
869
        }
870
        return $this;
871
    }
872
873
    /**
874
     * Assert that value matches a regex
875
     *
876
     * @param string      $pattern
877
     * @param string|null $message
878
     * @param string|null $propertyPath
879
     * @return Assert
880
     * @throws AssertionFailedException
881
     */
882
    public function regex($pattern, $message=null, $propertyPath=null)
883
    {
884
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
885
        {
886
            return $this;
887
        }
888
        $this->string($message, $propertyPath);
889 View Code Duplication
        if ( ! preg_match($pattern, $this->value) )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
890
        {
891
            $message = $message ?: $this->overrideError;
892
            $message = sprintf(
893
                $message ?: 'Value "%s" does not match expression.',
894
                $this->stringify($this->value)
895
            );
896
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_REGEX, $propertyPath, ['pattern' => $pattern]);
897
        }
898
        return $this;
899
    }
900
901
    /**
902
     * @param string $message
903
     * @param string $propertyPath
904
     * @return $this
905
     * @throws AssertionFailedException
906
     */
907
    public function ipAddress($message = null, $propertyPath = null)
908
    {
909
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
910
        {
911
            return $this;
912
        }
913
        $this->string($message, $propertyPath);
914
        $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])$/';
915
        if ( ! preg_match($pattern, $this->value) )
916
        {
917
            $message = $message ?: $this->overrideError;
918
            $message = sprintf(
919
                $message ?: 'Value "%s" was expected to be a valid IP Address',
920
                $this->stringify($this->value)
921
            );
922
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_IP_ADDRESS, $propertyPath);
923
        }
924
        return $this;
925
    }
926
927
    /**
928
     * @param string $pattern
929
     * @param string|null $message
930
     * @param string|null $propertyPath
931
     * @return $this
932
     * @throws AssertionFailedException
933
     */
934
    public function notRegex($pattern, $message = null, $propertyPath = null)
935
    {
936
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
937
        {
938
            return $this;
939
        }
940
        $this->string($message, $propertyPath);
941 View Code Duplication
        if ( preg_match($pattern, $this->value) )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
942
        {
943
            $message = $message ?: $this->overrideError;
944
            $message = sprintf(
945
                $message ?: 'Value "%s" does not match expression.',
946
                $this->stringify($this->value)
947
            );
948
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_REGEX, $propertyPath, ['pattern' => $pattern]);
949
        }
950
        return $this;
951
    }
952
953
    /**
954
     * Assert that string has a given length.
955
     *
956
     * @param int         $length
957
     * @param string|null $message
958
     * @param string|null $propertyPath
959
     * @param string      $encoding
960
     * @return Assert
961
     * @throws AssertionFailedException
962
     */
963
    public function length($length, $message = null, $propertyPath = null, $encoding = 'utf8')
964
    {
965
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
966
        {
967
            return $this;
968
        }
969
        $this->string($message, $propertyPath);
970
        if ( mb_strlen($this->value, $encoding) !== $length )
971
        {
972
            $message    = $message ?: $this->overrideError;
973
            $message    = sprintf(
974
                $message ?: 'Value "%s" has to be %d exactly characters long, but length is %d.',
975
                $this->stringify($this->value),
976
                $length,
977
                mb_strlen($this->value, $encoding)
978
            );
979
            $constraints = ['length' => $length, 'encoding' => $encoding];
980
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_LENGTH, $propertyPath, $constraints);
981
        }
982
        return $this;
983
    }
984
985
    /**
986
     * Assert that a string is at least $minLength chars long.
987
     *
988
     * @param int         $minLength
989
     * @param string|null $message
990
     * @param string|null $propertyPath
991
     * @param string      $encoding
992
     * @return Assert
993
     * @throws AssertionFailedException
994
     */
995
    public function minLength($minLength, $message = null, $propertyPath = null, $encoding = 'utf8')
996
    {
997
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
998
        {
999
            return $this;
1000
        }
1001
        $this->string($message, $propertyPath);
1002
        if ( mb_strlen($this->value, $encoding) < $minLength )
1003
        {
1004
            $message = $message ?: $this->overrideError;
1005
            $message     = sprintf(
1006
                $message
1007
                    ?: 'Value "%s" is too short, it should have more than %d characters, but only has %d characters.',
1008
                $this->stringify($this->value),
1009
                $minLength,
1010
                mb_strlen($this->value, $encoding)
1011
            );
1012
            $constraints = ['min_length' => $minLength, 'encoding' => $encoding];
1013
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MIN_LENGTH, $propertyPath, $constraints);
1014
        }
1015
        return $this;
1016
    }
1017
1018
    /**
1019
     * Assert that string value is not longer than $maxLength chars.
1020
     *
1021
     * @param integer     $maxLength
1022
     * @param string|null $message
1023
     * @param string|null $propertyPath
1024
     * @param string      $encoding
1025
     * @return Assert
1026
     * @throws AssertionFailedException
1027
     */
1028
    public function maxLength($maxLength, $message = null, $propertyPath = null, $encoding = 'utf8')
1029
    {
1030
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1031
        {
1032
            return $this;
1033
        }
1034
        $this->string($message, $propertyPath);
1035
        if ( mb_strlen($this->value, $encoding) > $maxLength )
1036
        {
1037
            $message = $message ?: $this->overrideError;
1038
            $message     = sprintf(
1039
                $message ?: 'Value "%s" is too long, it should have no more than %d characters, but has %d characters.',
1040
                $this->stringify($this->value),
1041
                $maxLength,
1042
                mb_strlen($this->value, $encoding)
1043
            );
1044
            $constraints = ['max_length' => $maxLength, 'encoding' => $encoding];
1045
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MAX_LENGTH, $propertyPath, $constraints);
1046
        }
1047
        return $this;
1048
    }
1049
1050
    /**
1051
     * Assert that string length is between min,max lengths.
1052
     *
1053
     * @param integer     $minLength
1054
     * @param integer     $maxLength
1055
     * @param string|null $message
1056
     * @param string|null $propertyPath
1057
     * @param string      $encoding
1058
     * @return Assert
1059
     * @throws AssertionFailedException
1060
     */
1061
    public function betweenLength($minLength, $maxLength, $message = null, $propertyPath = null, $encoding = 'utf8')
1062
    {
1063
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1064
        {
1065
            return $this;
1066
        }
1067
        $this->string($message, $propertyPath);
1068
        if ( mb_strlen($this->value, $encoding) < $minLength )
1069
        {
1070
            $message = $message ?: $this->overrideError;
1071
            $message     = sprintf(
1072
                $message
1073
                    ?: 'Value "%s" is too short, it should have more than %d characters, but only has %d characters.',
1074
                $this->stringify($this->value),
1075
                $minLength,
1076
                mb_strlen($this->value, $encoding)
1077
            );
1078
            $constraints = ['min_length' => $minLength, 'encoding' => $encoding];
1079
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MIN_LENGTH, $propertyPath, $constraints);
1080
        }
1081
        if ( mb_strlen($this->value, $encoding) > $maxLength )
1082
        {
1083
            $message = $message ?: $this->overrideError;
1084
            $message     = sprintf(
1085
                $message ?: 'Value "%s" is too long, it should have no more than %d characters, but has %d characters.',
1086
                $this->stringify($this->value),
1087
                $maxLength,
1088
                mb_strlen($this->value, $encoding)
1089
            );
1090
            $constraints = ['max_length' => $maxLength, 'encoding' => $encoding];
1091
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MAX_LENGTH, $propertyPath, $constraints);
1092
        }
1093
        return $this;
1094
    }
1095
1096
    /**
1097
     * Assert that string starts with a sequence of chars.
1098
     *
1099
     * @param string      $needle
1100
     * @param string|null $message
1101
     * @param string|null $propertyPath
1102
     * @param string      $encoding
1103
     * @return Assert
1104
     * @throws AssertionFailedException
1105
     */
1106 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...
1107
    {
1108
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1109
        {
1110
            return $this;
1111
        }
1112
        $this->string($message, $propertyPath);
1113
        if ( mb_strpos($this->value, $needle, null, $encoding) !== 0 )
1114
        {
1115
            $message = $message ?: $this->overrideError;
1116
            $message     = sprintf(
1117
                $message ?: 'Value "%s" does not start with "%s".',
1118
                $this->stringify($this->value),
1119
                $this->stringify($needle)
1120
            );
1121
            $constraints = ['needle' => $needle, 'encoding' => $encoding];
1122
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_STRING_START, $propertyPath, $constraints);
1123
        }
1124
        return $this;
1125
    }
1126
1127
    /**
1128
     * Assert that string ends with a sequence of chars.
1129
     *
1130
     * @param string      $needle
1131
     * @param string|null $message
1132
     * @param string|null $propertyPath
1133
     * @param string      $encoding
1134
     * @return Assert
1135
     * @throws AssertionFailedException
1136
     */
1137
    public function endsWith($needle, $message = null, $propertyPath = null, $encoding = 'utf8')
1138
    {
1139
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1140
        {
1141
            return $this;
1142
        }
1143
        $this->string($message, $propertyPath);
1144
        $stringPosition = mb_strlen($this->value, $encoding) - mb_strlen($needle, $encoding);
1145
        if ( mb_strripos($this->value, $needle, null, $encoding) !== $stringPosition )
1146
        {
1147
            $message = $message ?: $this->overrideError;
1148
            $message     = sprintf(
1149
                $message ?: 'Value "%s" does not end with "%s".',
1150
                $this->stringify($this->value),
1151
                $this->stringify($needle)
1152
            );
1153
            $constraints = ['needle' => $needle, 'encoding' => $encoding];
1154
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_STRING_END, $propertyPath, $constraints);
1155
        }
1156
        return $this;
1157
    }
1158
1159
    /**
1160
     * Assert that string contains a sequence of chars.
1161
     *
1162
     * @param string      $needle
1163
     * @param string|null $message
1164
     * @param string|null $propertyPath
1165
     * @param string      $encoding
1166
     * @return Assert
1167
     * @throws AssertionFailedException
1168
     */
1169 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...
1170
    {
1171
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1172
        {
1173
            return $this;
1174
        }
1175
        $this->string($message, $propertyPath);
1176
        if ( mb_strpos($this->value, $needle, null, $encoding) === false )
1177
        {
1178
            $message = $message ?: $this->overrideError;
1179
            $message     = sprintf(
1180
                $message ?: 'Value "%s" does not contain "%s".',
1181
                $this->stringify($this->value),
1182
                $this->stringify($needle)
1183
            );
1184
            $constraints = ['needle' => $needle, 'encoding' => $encoding];
1185
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_STRING_CONTAINS, $propertyPath, $constraints);
1186
        }
1187
        return $this;
1188
    }
1189
1190
    /**
1191
     * Assert that value is in array of choices.
1192
     *
1193
     * @param array       $choices
1194
     * @param string|null $message
1195
     * @param string|null $propertyPath
1196
     * @return Assert
1197
     * @throws AssertionFailedException
1198
     */
1199
    public function choice(array $choices, $message = null, $propertyPath = null)
1200
    {
1201
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1202
        {
1203
            return $this;
1204
        }
1205
        if ( !in_array($this->value, $choices, true) )
1206
        {
1207
            $message = $message ?: $this->overrideError;
1208
            $message = sprintf(
1209
                $message ?: 'Value "%s" is not an element of the valid values: %s',
1210
                $this->stringify($this->value),
1211
                implode(", ", array_map('Terah\Assert\Assert::stringify', $choices))
1212
            );
1213
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_CHOICE, $propertyPath, ['choices' => $choices]);
1214
        }
1215
        return $this;
1216
    }
1217
1218
    /**
1219
     * Alias of {@see choice()}
1220
     *
1221
     * @throws AssertionFailedException
1222
     *
1223
     * @param array $choices
1224
     * @param string|null $message
1225
     * @param string|null $propertyPath
1226
     * @return $this
1227
     */
1228
    public function inArray(array $choices, $message = null, $propertyPath = null)
1229
    {
1230
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1231
        {
1232
            return $this;
1233
        }
1234
        $this->choice($choices, $message, $propertyPath);
1235
        return $this;
1236
    }
1237
1238
    /**
1239
     * Assert that value is numeric.
1240
     *
1241
     * @param string|null $message
1242
     * @param string|null $propertyPath
1243
     * @return Assert
1244
     * @throws AssertionFailedException
1245
     */
1246
    public function numeric($message = null, $propertyPath = null)
1247
    {
1248
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1249
        {
1250
            return $this;
1251
        }
1252
        if ( ! is_numeric($this->value) )
1253
        {
1254
            $message = $message ?: $this->overrideError;
1255
            $message = sprintf(
1256
                $message ?: 'Value "%s" is not numeric.',
1257
                $this->stringify($this->value)
1258
            );
1259
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NUMERIC, $propertyPath);
1260
        }
1261
        return $this;
1262
    }
1263
1264
    /**
1265
     * @param string|null $message
1266
     * @param string|null $propertyPath
1267
     * @return Assert
1268
     * @throws AssertionFailedException
1269
     */
1270
    public function nonEmptyArray($message = null, $propertyPath = null)
1271
    {
1272
        $message = $message ?: 'Value "%s" is not a non-empty array.';
1273
        return $this->isArray($message, $propertyPath)->notEmpty($message, $propertyPath);
1274
    }
1275
1276
    /**
1277
     * @param string|null $message
1278
     * @param string|null $propertyPath
1279
     * @return Assert
1280
     * @throws AssertionFailedException
1281
     */
1282
    public function nonEmptyInt($message = null, $propertyPath = null)
1283
    {
1284
        $message = $message ?: 'Value "%s" is not a non-empty integer.';
1285
        return $this->integer($message, $propertyPath)->notEmpty($message, $propertyPath);
1286
    }
1287
1288
    /**
1289
     * @param string|null $message
1290
     * @param string|null $propertyPath
1291
     * @return Assert
1292
     * @throws AssertionFailedException
1293
     */
1294
    public function nonEmptyString($message = null, $propertyPath = null)
1295
    {
1296
        $message = $message ?: 'Value "%s" is not a non-empty string.';
1297
        return $this->integer($message, $propertyPath)->notEmpty($message, $propertyPath);
1298
    }
1299
1300
    /**
1301
     * Assert that value is an array.
1302
     *
1303
     * @param string|null $message
1304
     * @param string|null $propertyPath
1305
     * @return Assert
1306
     * @throws AssertionFailedException
1307
     */
1308
    public function isArray($message = null, $propertyPath = null)
1309
    {
1310
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1311
        {
1312
            return $this;
1313
        }
1314
        if ( !is_array($this->value) )
1315
        {
1316
            $message = $message ?: $this->overrideError;
1317
            $message = sprintf(
1318
                $message ?: 'Value "%s" is not an array.',
1319
                $this->stringify($this->value)
1320
            );
1321
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_ARRAY, $propertyPath);
1322
        }
1323
        return $this;
1324
    }
1325
1326
    /**
1327
     * Assert that value is an array or a traversable object.
1328
     *
1329
     * @param string|null $message
1330
     * @param string|null $propertyPath
1331
     * @return Assert
1332
     * @throws AssertionFailedException
1333
     */
1334
    public function isTraversable($message = null, $propertyPath = null)
1335
    {
1336
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1337
        {
1338
            return $this;
1339
        }
1340
        if ( !is_array($this->value) && !$this->value instanceof \Traversable )
1341
        {
1342
            $message = $message ?: $this->overrideError;
1343
            $message = sprintf(
1344
                $message ?: 'Value "%s" is not an array and does not implement Traversable.',
1345
                $this->stringify($this->value)
1346
            );
1347
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_TRAVERSABLE, $propertyPath);
1348
        }
1349
        return $this;
1350
    }
1351
1352
    /**
1353
     * Assert that value is an array or an array-accessible object.
1354
     *
1355
     * @param string|null $message
1356
     * @param string|null $propertyPath
1357
     * @return Assert
1358
     * @throws AssertionFailedException
1359
     */
1360
    public function isArrayAccessible($message = null, $propertyPath = null)
1361
    {
1362
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1363
        {
1364
            return $this;
1365
        }
1366
        if ( !is_array($this->value) && !$this->value instanceof \ArrayAccess )
1367
        {
1368
            $message = $message ?: $this->overrideError;
1369
            $message = sprintf(
1370
                $message ?: 'Value "%s" is not an array and does not implement ArrayAccess.',
1371
                $this->stringify($this->value)
1372
            );
1373
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_ARRAY_ACCESSIBLE, $propertyPath);
1374
        }
1375
        return $this;
1376
    }
1377
1378
    /**
1379
     * Assert that key exists in an array
1380
     *
1381
     * @param string|integer $key
1382
     * @param string|null    $message
1383
     * @param string|null    $propertyPath
1384
     * @return Assert
1385
     * @throws AssertionFailedException
1386
     */
1387
    public function keyExists($key, $message = null, $propertyPath = null)
1388
    {
1389
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1390
        {
1391
            return $this;
1392
        }
1393
        $this->isArray($message, $propertyPath);
1394
        if ( !array_key_exists($key, $this->value) )
1395
        {
1396
            $message = $message ?: $this->overrideError;
1397
            $message = sprintf(
1398
                $message ?: 'Array does not contain an element with key "%s"',
1399
                $this->stringify($key)
1400
            );
1401
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_KEY_EXISTS, $propertyPath, ['key' => $key]);
1402
        }
1403
        return $this;
1404
    }
1405
1406
    /**
1407
     * Assert that keys exist in array
1408
     *
1409
     * @param array       $keys
1410
     * @param string|null $message
1411
     * @param string|null $propertyPath
1412
     * @return Assert
1413
     * @throws AssertionFailedException
1414
     */
1415
    public function keysExist($keys, $message = null, $propertyPath = null)
1416
    {
1417
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1418
        {
1419
            return $this;
1420
        }
1421
        $this->isArray($message, $propertyPath);
1422
        foreach ( $keys as $key )
1423
        {
1424
            if ( !array_key_exists($key, $this->value) )
1425
            {
1426
                $message = $message
1427
                    ?: sprintf(
1428
                        'Array does not contain an element with key "%s"',
1429
                        $this->stringify($key)
1430
                    );
1431
                throw $this->createException($message, $this->overrideCode ?: self::INVALID_KEYS_EXIST, $propertyPath, ['key' => $key]);
1432
            }
1433
        }
1434
        return $this;
1435
    }
1436
1437
    /**
1438
     * Assert that property exists in array
1439
     *
1440
     * @param string|integer $key
1441
     * @param string|null    $message
1442
     * @param string|null    $propertyPath
1443
     * @return Assert
1444
     * @throws AssertionFailedException
1445
     */
1446
    public function propertyExists($key, $message = null, $propertyPath = null)
1447
    {
1448
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1449
        {
1450
            return $this;
1451
        }
1452
        $this->isObject($message, $propertyPath);
1453
        if ( !property_exists($this->value, $key) && !isset( $this->value->{$key} ) )
1454
        {
1455
            $message = $message
1456
                ?: sprintf(
1457
                    'Object does not contain a property with key "%s"',
1458
                    $this->stringify($key)
1459
                );
1460
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_PROPERTY_EXISTS, $propertyPath, ['key' => $key]);
1461
        }
1462
        return $this;
1463
    }
1464
1465
    /**
1466
     * Assert that properties exists in array
1467
     *
1468
     * @param array       $keys
1469
     * @param string|null $message
1470
     * @param string|null $propertyPath
1471
     * @return Assert
1472
     * @throws AssertionFailedException
1473
     */
1474
    public function propertiesExist(array $keys, $message = null, $propertyPath = null)
1475
    {
1476
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1477
        {
1478
            return $this;
1479
        }
1480
        $this->isObject($message, $propertyPath);
1481
        foreach ( $keys as $key )
1482
        {
1483
            // Using isset to allow resolution of magically defined properties
1484
            if ( !property_exists($this->value, $key) && !isset( $this->value->{$key} ) )
1485
            {
1486
                $message = $message
1487
                    ?: sprintf(
1488
                        'Object does not contain a property with key "%s"',
1489
                        $this->stringify($key)
1490
                    );
1491
                throw $this->createException($message, $this->overrideCode ?: self::INVALID_PROPERTIES_EXIST, $propertyPath, ['key' => $key]);
1492
            }
1493
        }
1494
        return $this;
1495
    }
1496
1497
    /**
1498
     * Assert that string is valid utf8
1499
     *
1500
     * @param string|null $message
1501
     * @param string|null $propertyPath
1502
     * @return Assert
1503
     * @throws AssertionFailedException
1504
     */
1505 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...
1506
    {
1507
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1508
        {
1509
            return $this;
1510
        }
1511
        $this->string($message, $propertyPath);
1512
        if ( mb_detect_encoding($this->value, 'UTF-8', true) !== 'UTF-8' )
1513
        {
1514
            $message = $message
1515
                ?: sprintf(
1516
                    'Value "%s" was expected to be a valid UTF8 string',
1517
                    $this->stringify($this->value)
1518
                );
1519
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_UTF8, $propertyPath);
1520
        }
1521
        return $this;
1522
    }
1523
1524
1525
    /**
1526
     * Assert that string is valid utf8
1527
     *
1528
     * @param string|null $message
1529
     * @param string|null $propertyPath
1530
     * @return Assert
1531
     * @throws AssertionFailedException
1532
     */
1533 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...
1534
    {
1535
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1536
        {
1537
            return $this;
1538
        }
1539
        $this->string($message, $propertyPath);
1540
        if ( ! preg_match('/^[ -~]+$/', $this->value) )
1541
        {
1542
            $message = $message
1543
                ?: sprintf(
1544
                    'Value "%s" was expected to be a valid ASCII string',
1545
                    $this->stringify($this->value)
1546
                );
1547
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_ASCII, $propertyPath);
1548
        }
1549
        return $this;
1550
    }
1551
1552
    /**
1553
     * Assert that key exists in an array/array-accessible object using isset()
1554
     *
1555
     * @param string|integer $key
1556
     * @param string|null    $message
1557
     * @param string|null    $propertyPath
1558
     * @return Assert
1559
     * @throws AssertionFailedException
1560
     */
1561
    public function keyIsset($key, $message = null, $propertyPath = null)
1562
    {
1563
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1564
        {
1565
            return $this;
1566
        }
1567
        $this->isArrayAccessible($message, $propertyPath);
1568
        if ( !isset( $this->value[$key] ) )
1569
        {
1570
            $message = $message ?: $this->overrideError;
1571
            $message = sprintf(
1572
                $message ?: 'The element with key "%s" was not found',
1573
                $this->stringify($key)
1574
            );
1575
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_KEY_ISSET, $propertyPath, ['key' => $key]);
1576
        }
1577
        return $this;
1578
    }
1579
1580
    /**
1581
     * Assert that key exists in an array/array-accessible object and it's value is not empty.
1582
     *
1583
     * @param string|integer $key
1584
     * @param string|null    $message
1585
     * @param string|null    $propertyPath
1586
     * @return Assert
1587
     * @throws AssertionFailedException
1588
     */
1589
    public function notEmptyKey($key, $message = null, $propertyPath = null)
1590
    {
1591
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1592
        {
1593
            return $this;
1594
        }
1595
        $this->keyIsset($key, $message, $propertyPath);
1596
        (new Assert($this->value[$key]))->setExceptionClass($this->exceptionClass)->notEmpty($message, $propertyPath);
1597
        return $this;
1598
    }
1599
1600
    /**
1601
     * Assert that value is not blank
1602
     *
1603
     * @param string|null $message
1604
     * @param string|null $propertyPath
1605
     * @return Assert
1606
     * @throws AssertionFailedException
1607
     */
1608 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...
1609
    {
1610
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1611
        {
1612
            return $this;
1613
        }
1614
        if ( false === $this->value || ( empty( $this->value ) && '0' != $this->value ) )
1615
        {
1616
            $message = $message ?: $this->overrideError;
1617
            $message = sprintf(
1618
                $message ?: 'Value "%s" is blank, but was expected to contain a value.',
1619
                $this->stringify($this->value)
1620
            );
1621
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NOT_BLANK, $propertyPath);
1622
        }
1623
        return $this;
1624
    }
1625
1626
    /**
1627
     * Assert that value is instance of given class-name.
1628
     *
1629
     * @param string      $className
1630
     * @param string|null $message
1631
     * @param string|null $propertyPath
1632
     * @return Assert
1633
     * @throws AssertionFailedException
1634
     */
1635
    public function isInstanceOf($className, $message = null, $propertyPath = null)
1636
    {
1637
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1638
        {
1639
            return $this;
1640
        }
1641 View Code Duplication
        if ( !( $this->value instanceof $className ) )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1642
        {
1643
            $message = $message ?: $this->overrideError;
1644
            $message = sprintf(
1645
                $message ?: 'Class "%s" was expected to be instanceof of "%s" but is not.',
1646
                $this->stringify($this->value),
1647
                $className
1648
            );
1649
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_INSTANCE_OF, $propertyPath, ['class' => $className]);
1650
        }
1651
        return $this;
1652
    }
1653
1654
    /**
1655
     * Assert that value is not instance of given class-name.
1656
     *
1657
     * @param string      $className
1658
     * @param string|null $message
1659
     * @param string|null $propertyPath
1660
     * @return Assert
1661
     * @throws AssertionFailedException
1662
     */
1663
    public function notIsInstanceOf($className, $message = null, $propertyPath = null)
1664
    {
1665
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1666
        {
1667
            return $this;
1668
        }
1669 View Code Duplication
        if ( $this->value instanceof $className )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1670
        {
1671
            $message = $message ?: $this->overrideError;
1672
            $message = sprintf(
1673
                $message ?: 'Class "%s" was not expected to be instanceof of "%s".',
1674
                $this->stringify($this->value),
1675
                $className
1676
            );
1677
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NOT_INSTANCE_OF, $propertyPath, ['class' => $className]);
1678
        }
1679
        return $this;
1680
    }
1681
1682
    /**
1683
     * Assert that value is subclass of given class-name.
1684
     *
1685
     * @param string      $className
1686
     * @param string|null $message
1687
     * @param string|null $propertyPath
1688
     * @return Assert
1689
     * @throws AssertionFailedException
1690
     */
1691
    public function subclassOf($className, $message = null, $propertyPath = null)
1692
    {
1693
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1694
        {
1695
            return $this;
1696
        }
1697 View Code Duplication
        if ( !is_subclass_of($this->value, $className) )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1698
        {
1699
            $message = $message ?: $this->overrideError;
1700
            $message = sprintf(
1701
                $message ?: 'Class "%s" was expected to be subclass of "%s".',
1702
                $this->stringify($this->value),
1703
                $className
1704
            );
1705
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_SUBCLASS_OF, $propertyPath, ['class' => $className]);
1706
        }
1707
        return $this;
1708
    }
1709
1710
    /**
1711
     * Assert that value is in range of numbers.
1712
     *
1713
     * @param integer     $minValue
1714
     * @param integer     $maxValue
1715
     * @param string|null $message
1716
     * @param string|null $propertyPath
1717
     * @return Assert
1718
     * @throws AssertionFailedException
1719
     */
1720
    public function range($minValue, $maxValue, $message = null, $propertyPath = null)
1721
    {
1722
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1723
        {
1724
            return $this;
1725
        }
1726
        $this->numeric($message, $propertyPath);
1727
        if ( $this->value < $minValue || $this->value > $maxValue )
1728
        {
1729
            $message = $message ?: $this->overrideError;
1730
            $message = sprintf(
1731
                $message ?: 'Number "%s" was expected to be at least "%d" and at most "%d".',
1732
                $this->stringify($this->value),
1733
                $this->stringify($minValue),
1734
                $this->stringify($maxValue)
1735
            );
1736
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_RANGE, $propertyPath, [
1737
                'min' => $minValue,
1738
                'max' => $maxValue
1739
            ]);
1740
        }
1741
        return $this;
1742
    }
1743
1744
    /**
1745
     * Assert that a value is at least as big as a given limit
1746
     *
1747
     * @param mixed       $minValue
1748
     * @param string|null $message
1749
     * @param string|null $propertyPath
1750
     * @return Assert
1751
     * @throws AssertionFailedException
1752
     */
1753
    public function min($minValue, $message = null, $propertyPath = null)
1754
    {
1755
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1756
        {
1757
            return $this;
1758
        }
1759
        $this->numeric($message, $propertyPath);
1760 View Code Duplication
        if ( $this->value < $minValue )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1761
        {
1762
            $message = $message ?: $this->overrideError;
1763
            $message = sprintf(
1764
                $message ?: 'Number "%s" was expected to be at least "%d".',
1765
                $this->stringify($this->value),
1766
                $this->stringify($minValue)
1767
            );
1768
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MIN, $propertyPath, ['min' => $minValue]);
1769
        }
1770
        return $this;
1771
    }
1772
1773
    /**
1774
     * Assert that a number is smaller as a given limit
1775
     *
1776
     * @param mixed       $maxValue
1777
     * @param string|null $message
1778
     * @param string|null $propertyPath
1779
     * @return Assert
1780
     * @throws AssertionFailedException
1781
     */
1782
    public function max($maxValue, $message = null, $propertyPath = null)
1783
    {
1784
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1785
        {
1786
            return $this;
1787
        }
1788
        $this->numeric($message, $propertyPath);
1789 View Code Duplication
        if ( $this->value > $maxValue )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1790
        {
1791
            $message = $message ?: $this->overrideError;
1792
            $message = sprintf(
1793
                $message ?: 'Number "%s" was expected to be at most "%d".',
1794
                $this->stringify($this->value),
1795
                $this->stringify($maxValue)
1796
            );
1797
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MAX, $propertyPath, ['max' => $maxValue]);
1798
        }
1799
        return $this;
1800
    }
1801
1802
    /**
1803
     * Assert that a file exists
1804
     *
1805
     * @param string|null $message
1806
     * @param string|null $propertyPath
1807
     * @return Assert
1808
     * @throws AssertionFailedException
1809
     */
1810
    public function file($message = null, $propertyPath = null)
1811
    {
1812
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1813
        {
1814
            return $this;
1815
        }
1816
        $this->string($message, $propertyPath);
1817
        $this->notEmpty($message, $propertyPath);
1818
        if ( !is_file($this->value) )
1819
        {
1820
            $message = $message ?: $this->overrideError;
1821
            $message = sprintf(
1822
                $message ?: 'File "%s" was expected to exist.',
1823
                $this->stringify($this->value)
1824
            );
1825
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_FILE, $propertyPath);
1826
        }
1827
        return $this;
1828
    }
1829
1830
    /**
1831
     * @param string|null $message
1832
     * @param string|null $propertyPath
1833
     * @return $this
1834
     * @throws AssertionFailedException
1835
     */
1836
    public function fileExists($message = null, $propertyPath = null)
1837
    {
1838
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1839
        {
1840
            return $this;
1841
        }
1842
        $this->string($message, $propertyPath);
1843
        $this->notEmpty($message, $propertyPath);
1844
        if ( ! file_exists($this->value) )
1845
        {
1846
            $message = $message ?: $this->overrideError;
1847
            $message = sprintf(
1848
                $message ?: 'File or directory "%s" was expected to exist.',
1849
                $this->stringify($this->value)
1850
            );
1851
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_FILE_OR_DIR, $propertyPath);
1852
        }
1853
        return $this;
1854
    }
1855
1856
    /**
1857
     * Assert that a directory exists
1858
     *
1859
     * @param string|null $message
1860
     * @param string|null $propertyPath
1861
     * @return Assert
1862
     * @throws AssertionFailedException
1863
     */
1864 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...
1865
    {
1866
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1867
        {
1868
            return $this;
1869
        }
1870
        $this->string($message, $propertyPath);
1871
        if ( !is_dir($this->value) )
1872
        {
1873
            $message = $message ?: $this->overrideError;
1874
            $message = sprintf(
1875
                $message ?: 'Path "%s" was expected to be a directory.',
1876
                $this->stringify($this->value)
1877
            );
1878
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_DIRECTORY, $propertyPath);
1879
        }
1880
        return $this;
1881
    }
1882
1883
    /**
1884
     * Assert that the value is something readable
1885
     *
1886
     * @param string|null $message
1887
     * @param string|null $propertyPath
1888
     * @return Assert
1889
     * @throws AssertionFailedException
1890
     */
1891 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...
1892
    {
1893
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1894
        {
1895
            return $this;
1896
        }
1897
        $this->string($message, $propertyPath);
1898
        if ( !is_readable($this->value) )
1899
        {
1900
            $message = $message ?: $this->overrideError;
1901
            $message = sprintf(
1902
                $message ?: 'Path "%s" was expected to be readable.',
1903
                $this->stringify($this->value)
1904
            );
1905
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_READABLE, $propertyPath);
1906
        }
1907
        return $this;
1908
    }
1909
1910
    /**
1911
     * Assert that the value is something writeable
1912
     *
1913
     * @param string|null $message
1914
     * @param string|null $propertyPath
1915
     * @return Assert
1916
     * @throws AssertionFailedException
1917
     */
1918 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...
1919
    {
1920
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1921
        {
1922
            return $this;
1923
        }
1924
        $this->string($message, $propertyPath);
1925
        if ( !is_writeable($this->value) )
1926
        {
1927
            $message = $message ?: $this->overrideError;
1928
            $message = sprintf(
1929
                $message ?: 'Path "%s" was expected to be writeable.',
1930
                $this->stringify($this->value)
1931
            );
1932
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_WRITEABLE, $propertyPath);
1933
        }
1934
        return $this;
1935
    }
1936
1937
    /**
1938
     * Assert that value is an email adress (using
1939
     * input_filter/FILTER_VALIDATE_EMAIL).
1940
     *
1941
     * @param string|null $message
1942
     * @param string|null $propertyPath
1943
     * @return Assert
1944
     * @throws AssertionFailedException
1945
     */
1946
    public function email($message = null, $propertyPath = null)
1947
    {
1948
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1949
        {
1950
            return $this;
1951
        }
1952
        $this->string($message, $propertyPath);
1953
        if ( ! filter_var($this->value, FILTER_VALIDATE_EMAIL) )
1954
        {
1955
            $message = $message ?: $this->overrideError;
1956
            $message = sprintf(
1957
                $message ?: 'Value "%s" was expected to be a valid e-mail address.',
1958
                $this->stringify($this->value)
1959
            );
1960
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_EMAIL, $propertyPath);
1961
        }
1962
        else
1963
        {
1964
            $host = substr($this->value, strpos($this->value, '@') + 1);
1965
            // Likely not a FQDN, bug in PHP FILTER_VALIDATE_EMAIL prior to PHP 5.3.3
1966
            if ( version_compare(PHP_VERSION, '5.3.3', '<') && strpos($host, '.') === false )
1967
            {
1968
                $message = $message ?: $this->overrideError;
1969
                $message = sprintf(
1970
                    $message ?: 'Value "%s" was expected to be a valid e-mail address.',
1971
                    $this->stringify($this->value)
1972
                );
1973
                throw $this->createException($message, $this->overrideCode ?: self::INVALID_EMAIL, $propertyPath);
1974
            }
1975
        }
1976
        return $this;
1977
    }
1978
1979
    /**
1980
     * @param null $message
1981
     * @param null $propertyPath
1982
     * @return Assert
1983
     * @throws AssertionFailedException
1984
     */
1985
    public function emailPrefix($message = null, $propertyPath = null)
1986
    {
1987
        $this->value($this->value . '@example.com');
1988
        return $this->email($message, $propertyPath);
1989
    }
1990
1991
    /**
1992
     * Assert that value is an URL.
1993
     *
1994
     * This code snipped was taken from the Symfony project and modified to the special demands of this method.
1995
     *
1996
     * @param string|null $message
1997
     * @param string|null $propertyPath
1998
     * @return Assert
1999
     * @throws AssertionFailedException
2000
     *
2001
     *
2002
     * @link https://github.com/symfony/Validator/blob/master/Constraints/UrlValidator.php
2003
     * @link https://github.com/symfony/Validator/blob/master/Constraints/Url.php
2004
     */
2005
    public function url($message = null, $propertyPath = null)
2006
    {
2007
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2008
        {
2009
            return $this;
2010
        }
2011
        $this->string($message, $propertyPath);
2012
        $protocols = ['http', 'https'];
2013
        $pattern   = '~^
2014
            (%s)://                                 # protocol
2015
            (
2016
                ([\pL\pN\pS-]+\.)+[\pL]+                   # a domain name
2017
                    |                                     #  or
2018
                \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}      # a IP address
2019
                    |                                     #  or
2020
                \[
2021
                    (?:(?:(?:(?:(?:(?:(?:[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})))?::))))
2022
                \]  # a IPv6 address
2023
            )
2024
            (:[0-9]+)?                              # a port (optional)
2025
            (/?|/\S+)                               # a /, nothing or a / with something
2026
        $~ixu';
2027
        $pattern   = sprintf($pattern, implode('|', $protocols));
2028
        if ( !preg_match($pattern, $this->value) )
2029
        {
2030
            $message = $message ?: $this->overrideError;
2031
            $message = sprintf(
2032
                $message ?: 'Value "%s" was expected to be a valid URL starting with http or https',
2033
                $this->stringify($this->value)
2034
            );
2035
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_URL, $propertyPath);
2036
        }
2037
        return $this;
2038
    }
2039
2040
    /**
2041
     * Assert that value is domain name.
2042
     *
2043
     * This code snipped was taken from the Symfony project and modified to the special demands of this method.
2044
     *
2045
     * @param string|null $message
2046
     * @param string|null $propertyPath
2047
     * @return Assert
2048
     * @throws AssertionFailedException
2049
     *
2050
     */
2051
    public function domainName($message = null, $propertyPath = null)
2052
    {
2053
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2054
        {
2055
            return $this;
2056
        }
2057
        $this->string($message, $propertyPath);
2058
        $pattern   = '/^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6}$/';
2059
        if ( ! preg_match($pattern, $this->value) )
2060
        {
2061
            $message = $message ?: $this->overrideError;
2062
            $message = sprintf(
2063
                $message ?: 'Value "%s" was expected to be a valid domain name',
2064
                $this->stringify($this->value)
2065
            );
2066
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_DOMAIN_NAME, $propertyPath);
2067
        }
2068
        return $this;
2069
    }
2070
2071
    /**
2072
     * Assert that value is alphanumeric.
2073
     *
2074
     * @param string|null $message
2075
     * @param string|null $propertyPath
2076
     * @return Assert
2077
     * @throws AssertionFailedException
2078
     */
2079 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...
2080
    {
2081
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2082
        {
2083
            return $this;
2084
        }
2085
        try
2086
        {
2087
            $this->regex('(^([a-zA-Z]{1}[a-zA-Z0-9]*)$)', $message, $propertyPath);
2088
        }
2089
        catch (AssertionFailedException $e)
2090
        {
2091
            $message = $message ?: $this->overrideError;
2092
            $message = sprintf(
2093
                $message
2094
                    ?: 'Value "%s" is not alphanumeric, starting with letters and containing only letters and numbers.',
2095
                $this->stringify($this->value)
2096
            );
2097
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_ALNUM, $propertyPath);
2098
        }
2099
        return $this;
2100
    }
2101
2102
    /**
2103
     * Assert that the value is boolean True.
2104
     *
2105
     * @param string|null $message
2106
     * @param string|null $propertyPath
2107
     * @return Assert
2108
     * @throws AssertionFailedException
2109
     */
2110
    public function true($message = null, $propertyPath = null)
2111
    {
2112
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2113
        {
2114
            return $this;
2115
        }
2116
        if ( $this->value !== true )
2117
        {
2118
            $message = $message ?: $this->overrideError;
2119
            $message = sprintf(
2120
                $message ?: 'Value "%s" is not TRUE.',
2121
                $this->stringify($this->value)
2122
            );
2123
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_TRUE, $propertyPath);
2124
        }
2125
        return $this;
2126
    }
2127
2128
    /**
2129
     * Assert that the value is boolean True.
2130
     *
2131
     * @param string|null $message
2132
     * @param string|null $propertyPath
2133
     * @return Assert
2134
     * @throws AssertionFailedException
2135
     */
2136
    public function truthy($message = null, $propertyPath = null)
2137
    {
2138
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2139
        {
2140
            return $this;
2141
        }
2142
        if ( ! $this->value )
2143
        {
2144
            $message = $message ?: $this->overrideError;
2145
            $message = sprintf(
2146
                $message ?: 'Value "%s" is not truthy.',
2147
                $this->stringify($this->value)
2148
            );
2149
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_TRUE, $propertyPath);
2150
        }
2151
        return $this;
2152
    }
2153
2154
    /**
2155
     * Assert that the value is boolean False.
2156
     *
2157
     * @param string|null $message
2158
     * @param string|null $propertyPath
2159
     * @return Assert
2160
     * @throws AssertionFailedException
2161
     */
2162
    public function false($message = null, $propertyPath = null)
2163
    {
2164
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2165
        {
2166
            return $this;
2167
        }
2168
        if ( $this->value !== false )
2169
        {
2170
            $message = $message ?: $this->overrideError;
2171
            $message = sprintf(
2172
                $message ?: 'Value "%s" is not FALSE.',
2173
                $this->stringify($this->value)
2174
            );
2175
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_FALSE, $propertyPath);
2176
        }
2177
        return $this;
2178
    }
2179
2180
    /**
2181
     * Assert that the value is not boolean False.
2182
     *
2183
     * @param string|null $message
2184
     * @param string|null $propertyPath
2185
     * @return Assert
2186
     * @throws AssertionFailedException
2187
     */
2188
    public function notFalse($message = null, $propertyPath = null)
2189
    {
2190
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2191
        {
2192
            return $this;
2193
        }
2194
        if ( $this->value === false )
2195
        {
2196
            $message = $message ?: $this->overrideError;
2197
            $message = sprintf(
2198
                $message ?: 'Value "%s" is not FALSE.',
2199
                $this->stringify($this->value)
2200
            );
2201
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NOT_FALSE, $propertyPath);
2202
        }
2203
        return $this;
2204
    }
2205
2206
    /**
2207
     * Assert that the class exists.
2208
     *
2209
     * @param string|null $message
2210
     * @param string|null $propertyPath
2211
     * @return Assert
2212
     * @throws AssertionFailedException
2213
     */
2214
    public function classExists($message = null, $propertyPath = null)
2215
    {
2216
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2217
        {
2218
            return $this;
2219
        }
2220
        if ( !class_exists($this->value) )
2221
        {
2222
            $message = $message ?: $this->overrideError;
2223
            $message = sprintf(
2224
                $message ?: 'Class "%s" does not exist.',
2225
                $this->stringify($this->value)
2226
            );
2227
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_CLASS, $propertyPath);
2228
        }
2229
        return $this;
2230
    }
2231
2232
    /**
2233
     * Assert that the class implements the interface
2234
     *
2235
     * @param string      $interfaceName
2236
     * @param string|null $message
2237
     * @param string|null $propertyPath
2238
     * @return Assert
2239
     * @throws AssertionFailedException
2240
     */
2241
    public function implementsInterface($interfaceName, $message = null, $propertyPath = null)
2242
    {
2243
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2244
        {
2245
            return $this;
2246
        }
2247
        $reflection = new \ReflectionClass($this->value);
2248
        if ( !$reflection->implementsInterface($interfaceName) )
2249
        {
2250
            $message = $message ?: $this->overrideError;
2251
            $message = sprintf(
2252
                $message ?: 'Class "%s" does not implement interface "%s".',
2253
                $this->stringify($this->value),
2254
                $this->stringify($interfaceName)
2255
            );
2256
            throw $this->createException($message, self::INTERFACE_NOT_IMPLEMENTED, $propertyPath, ['interface' => $interfaceName]);
2257
        }
2258
        return $this;
2259
    }
2260
2261
    /**
2262
     * Assert that the given string is a valid json string.
2263
     *
2264
     * NOTICE:
2265
     * Since this does a json_decode to determine its validity
2266
     * you probably should consider, when using the variable
2267
     * content afterwards, just to decode and check for yourself instead
2268
     * of using this assertion.
2269
     *
2270
     * @param string|null $message
2271
     * @param string|null $propertyPath
2272
     * @return Assert
2273
     * @throws AssertionFailedException
2274
     */
2275
    public function isJsonString($message = null, $propertyPath = null)
2276
    {
2277
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2278
        {
2279
            return $this;
2280
        }
2281
        if ( null === json_decode($this->value) && JSON_ERROR_NONE !== json_last_error() )
2282
        {
2283
            $message = $message ?: $this->overrideError;
2284
            $message = sprintf(
2285
                $message ?: 'Value "%s" is not a valid JSON string.',
2286
                $this->stringify($this->value)
2287
            );
2288
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_JSON_STRING, $propertyPath);
2289
        }
2290
        return $this;
2291
    }
2292
2293
    /**
2294
     * Assert that the given string is a valid UUID
2295
     *
2296
     * Uses code from {@link https://github.com/ramsey/uuid} that is MIT licensed.
2297
     *
2298
     * @param string|null $message
2299
     * @param string|null $propertyPath
2300
     * @return Assert
2301
     * @throws AssertionFailedException
2302
     */
2303
    public function uuid($message = null, $propertyPath = null)
2304
    {
2305
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2306
        {
2307
            return $this;
2308
        }
2309
        $this->value = str_replace(['urn:', 'uuid:', '{', '}'], '', $this->value);
2310
        if ( $this->value === '00000000-0000-0000-0000-000000000000' )
2311
        {
2312
            return $this;
2313
        }
2314
        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) )
2315
        {
2316
            $message = $message ?: $this->overrideError;
2317
            $message = sprintf(
2318
                $message ?: 'Value "%s" is not a valid UUID.',
2319
                $this->stringify($this->value)
2320
            );
2321
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_UUID, $propertyPath);
2322
        }
2323
        return $this;
2324
    }
2325
2326
    /**
2327
     * Assert that the count of countable is equal to count.
2328
     *
2329
     * @param int    $count
2330
     * @param string $message
2331
     * @param string $propertyPath
2332
     * @return Assert
2333
     * @throws AssertionFailedException
2334
     */
2335
    public function count($count, $message = null, $propertyPath = null)
2336
    {
2337
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2338
        {
2339
            return $this;
2340
        }
2341 View Code Duplication
        if ( $count !== count($this->value) )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
2342
        {
2343
            $message = $message ?: $this->overrideError;
2344
            $message = sprintf(
2345
                $message ?: 'List does not contain exactly "%d" elements.',
2346
                $this->stringify($this->value),
2347
                $this->stringify($count)
2348
            );
2349
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_COUNT, $propertyPath, ['count' => $count]);
2350
        }
2351
        return $this;
2352
    }
2353
2354
    /**
2355
     * @param $func
2356
     * @param $args
2357
     * @return bool
2358
     * @throws AssertionFailedException
2359
     */
2360
    protected function doAllOrNullOr($func, $args)
2361
    {
2362
        if ( $this->nullOr && is_null($this->value) )
2363
        {
2364
            return true;
2365
        }
2366
        if ( $this->emptyOr && empty($this->value) )
2367
        {
2368
            return true;
2369
        }
2370
        if ( $this->all && (new Assert($this->value))->setExceptionClass($this->exceptionClass)->isTraversable() )
2371
        {
2372
            foreach ( $this->value as $idx => $value )
2373
            {
2374
                $object = (new Assert($value))->setExceptionClass($this->exceptionClass);
2375
                call_user_func_array([$object, $func], $args);
2376
            }
2377
            return true;
2378
        }
2379
        return ( $this->nullOr && is_null($this->value) ) || ( $this->emptyOr && empty($this->value) ) ? true : false;
2380
    }
2381
2382
    /**
2383
     * Determines if the values array has every choice as key and that this choice has content.
2384
     *
2385
     * @param array $choices
2386
     * @param string|null $message
2387
     * @param string|null $propertyPath
2388
     * @return $this
2389
     */
2390
    public function choicesNotEmpty(array $choices, $message = null, $propertyPath = null)
2391
    {
2392
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2393
        {
2394
            return $this;
2395
        }
2396
        $this->notEmpty($message, $propertyPath);
2397
        foreach ( $choices as $choice )
2398
        {
2399
            $this->notEmptyKey($choice, $message, $propertyPath);
2400
        }
2401
        return $this;
2402
    }
2403
2404
    /**
2405
     * Determines that the named method is defined in the provided object.
2406
     *
2407
     * @param mixed $object
2408
     * @param string|null $message
2409
     * @param string|null $propertyPath
2410
     * @returns Assert
2411
     * @throws
2412
     */
2413
    public function methodExists($object, $message = null, $propertyPath = null)
2414
    {
2415
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2416
        {
2417
            return $this;
2418
        }
2419
        (new Assert($object))->setExceptionClass($this->exceptionClass)->isObject($message, $propertyPath);
2420
        if ( !method_exists($object, $this->value) )
2421
        {
2422
            $message = $message ?: $this->overrideError;
2423
            $message = sprintf(
2424
                $message ?: 'Expected "%s" does not a exist in provided object.',
2425
                $this->stringify($this->value)
2426
            );
2427
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_METHOD, $propertyPath);
2428
        }
2429
        return $this;
2430
    }
2431
2432
    /**
2433
     * Determines that the provided value is an object.
2434
     *
2435
     * @param string|null $message
2436
     * @param string|null $propertyPath
2437
     * @return $this
2438
     * @throws AssertionFailedException
2439
     */
2440
    public function isObject($message = null, $propertyPath = null)
2441
    {
2442
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2443
        {
2444
            return $this;
2445
        }
2446
        if ( !is_object($this->value) )
2447
        {
2448
            $message = $message ?: $this->overrideError;
2449
            $message = sprintf(
2450
                $message ?: 'Provided "%s" is not a valid object.',
2451
                $this->stringify($this->value)
2452
            );
2453
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_OBJECT, $propertyPath);
2454
        }
2455
        return $this;
2456
    }
2457
2458
    /**
2459
     * Make a string version of a value.
2460
     *
2461
     * @param $value
2462
     * @return string
2463
     */
2464
    private function stringify($value)
2465
    {
2466
        if ( is_bool($value) )
2467
        {
2468
            return $value ? '<TRUE>' : '<FALSE>';
2469
        }
2470
        if ( is_scalar($value) )
2471
        {
2472
            $val = (string)$value;
2473
            if ( strlen($val) > 100 )
2474
            {
2475
                $val = substr($val, 0, 97) . '...';
2476
            }
2477
            return $val;
2478
        }
2479
        if ( is_array($value) )
2480
        {
2481
            return '<ARRAY>';
2482
        }
2483
        if ( is_object($value) )
2484
        {
2485
            return get_class($value);
2486
        }
2487
        if ( is_resource($value) )
2488
        {
2489
            return '<RESOURCE>';
2490
        }
2491
        if ( $value === null )
2492
        {
2493
            return '<NULL>';
2494
        }
2495
        return 'unknown';
2496
    }
2497
}
2498
2499