Completed
Push — master ( d4ace1...f3be79 )
by Terry
03:18
created

Assert::notEq()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

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