Completed
Push — master ( f0c1f9...4d24a6 )
by Terry
01:55
created

Assert::length()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 23
Code Lines 14

Duplication

Lines 23
Ratio 100 %

Importance

Changes 0
Metric Value
cc 6
eloc 14
nc 4
nop 4
dl 23
loc 23
rs 8.5906
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
    public static function that($value, string $fieldName='', int $code=0, string $error='', string $level=Assert::WARNING) : Assert
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
        $this->notEmpty($message, $fieldName);
835
        if ( strtotime($this->value) === false )
836
        {
837
            $message = $message ?: $this->overrideError;
838
            $message = sprintf(
839
                $message ?: 'Value "%s" is not a date.',
840
                $this->stringify($this->value)
841
            );
842
843
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_DATE, $fieldName);
844
        }
845
846
        return $this;
847
    }
848
849
    /**
850
     * @param        $afterDate
851
     * @param string $message
852
     * @param string $fieldName
853
     * @return $this
854
     * @throws AssertionFailedException
855
     */
856
    public function after($afterDate, string $message='', string $fieldName='')
857
    {
858
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
859
        {
860
            return $this;
861
        }
862
        $this->notEmpty($message, $fieldName);
863
        if ( strtotime($this->value) === false && strtotime($afterDate) === false && strtotime($this->value) < strtotime($afterDate) )
864
        {
865
            $message = $message ?: $this->overrideError;
866
            $message = sprintf(
867
                $message ?: 'Value "%s" is not a date, comparison date is not a date or value is not before comparison date.',
868
                $this->stringify($this->value)
869
            );
870
871
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_DATE, $fieldName);
872
        }
873
874
        return $this;
875
    }
876
877
    /**
878
     * Assert that value is a PHP integer'ish.
879
     *
880
     * @param string $message
881
     * @param string $fieldName
882
     * @return Assert
883
     * @throws AssertionFailedException
884
     */
885
    public function integerish(string $message='', string $fieldName='') : Assert
886
    {
887
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
888
        {
889
            return $this;
890
        }
891
        if ( is_object($this->value) || strval(intval($this->value)) != $this->value || is_bool($this->value) || is_null($this->value) )
892
        {
893
            $message = $message ?: $this->overrideError;
894
            $message = sprintf(
895
                $message ?: 'Value "%s" is not an integer or a number castable to integer.',
896
                $this->stringify($this->value)
897
            );
898
899
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_INTEGERISH, $fieldName);
900
        }
901
902
        return $this;
903
    }
904
905
    /**
906
     * Assert that value is a valid PHP boolean.
907
     *
908
     * @param string $message
909
     * @param string $fieldName
910
     * @return Assert
911
     * @throws AssertionFailedException
912
     */
913
    public function boolean(string $message='', string $fieldName='') : Assert
914
    {
915
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
916
        {
917
            return $this;
918
        }
919
        if ( ! is_bool($this->value) )
920
        {
921
            $message = $message ?: $this->overrideError;
922
            $message = sprintf(
923
                $message ?: 'Value "%s" is not a boolean.',
924
                $this->stringify($this->value)
925
            );
926
927
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_BOOLEAN, $fieldName);
928
        }
929
930
        return $this;
931
    }
932
933
    /**
934
     * Assert that value is a valid PHP scalar.
935
     *
936
     * @param string $message
937
     * @param string $fieldName
938
     * @return Assert
939
     * @throws AssertionFailedException
940
     */
941
    public function scalar(string $message='', string $fieldName='') : Assert
942
    {
943
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
944
        {
945
            return $this;
946
        }
947
        if ( ! is_scalar($this->value) )
948
        {
949
            $message = $message ?: $this->overrideError;
950
            $message = sprintf(
951
                $message ?: 'Value "%s" is not a scalar.',
952
                $this->stringify($this->value)
953
            );
954
955
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_SCALAR, $fieldName);
956
        }
957
958
        return $this;
959
    }
960
961
    /**
962
     * Assert that value is not empty.
963
     *
964
     * @param string $message
965
     * @param string $fieldName
966
     * @return Assert
967
     * @throws AssertionFailedException
968
     */
969 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...
970
    {
971
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
972
        {
973
            return $this;
974
        }
975
        if ( ( is_object($this->value) && empty((array)$this->value) ) || empty($this->value) )
976
        {
977
            $message = $message ?: $this->overrideError;
978
            $message = sprintf(
979
                $message ?: 'Value "%s" is empty, but non empty value was expected.',
980
                $this->stringify($this->value)
981
            );
982
983
            throw $this->createException($message, $this->overrideCode ?: self::VALUE_EMPTY, $fieldName);
984
        }
985
986
        return $this;
987
    }
988
989
    /**
990
     * Assert that value is empty.
991
     *
992
     * @param string $message
993
     * @param string $fieldName
994
     * @return Assert
995
     * @throws AssertionFailedException
996
     */
997
    public function noContent(string $message='', string $fieldName='') : Assert
998
    {
999
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1000
        {
1001
            return $this;
1002
        }
1003
        if ( !empty( $this->value ) )
1004
        {
1005
            $message = $message ?: $this->overrideError;
1006
            $message = sprintf(
1007
                $message ?: 'Value "%s" is not empty, but empty value was expected.',
1008
                $this->stringify($this->value)
1009
            );
1010
1011
            throw $this->createException($message, $this->overrideCode ?: self::VALUE_NOT_EMPTY, $fieldName);
1012
        }
1013
1014
        return $this;
1015
    }
1016
1017
    /**
1018
     * Assert that value is not null.
1019
     *
1020
     * @param string $message
1021
     * @param string $fieldName
1022
     * @return Assert
1023
     * @throws AssertionFailedException
1024
     */
1025
    public function notNull(string $message='', string $fieldName='') : Assert
1026
    {
1027
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1028
        {
1029
            return $this;
1030
        }
1031
        if ( $this->value === null )
1032
        {
1033
            $message = $message ?: $this->overrideError;
1034
            $message = sprintf(
1035
                $message ?: 'Value "%s" is null, but non null value was expected.',
1036
                $this->stringify($this->value)
1037
            );
1038
1039
            throw $this->createException($message, $this->overrideCode ?: self::VALUE_NULL, $fieldName);
1040
        }
1041
1042
        return $this;
1043
    }
1044
1045
    /**
1046
     * Assert that value is a string
1047
     *
1048
     * @param string $message
1049
     * @param string $fieldName
1050
     * @return Assert
1051
     * @throws AssertionFailedException
1052
     */
1053
    public function string(string $message='', string $fieldName='') : Assert
1054
    {
1055
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1056
        {
1057
            return $this;
1058
        }
1059
        if ( !is_string($this->value) )
1060
        {
1061
            $message = $message ?: $this->overrideError;
1062
            $message = sprintf(
1063
                $message ?: 'Value "%s" expected to be string, type %s given.',
1064
                $this->stringify($this->value),
1065
                gettype($this->value)
1066
            );
1067
1068
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_STRING, $fieldName);
1069
        }
1070
1071
        return $this;
1072
    }
1073
1074
    /**
1075
     * Assert that value matches a provided Regex.
1076
     *
1077
     * @param string $pattern
1078
     * @param string $message
1079
     * @param string $fieldName
1080
     * @return Assert
1081
     * @throws AssertionFailedException
1082
     */
1083
    public function regex(string $pattern, string $message='', string $fieldName='') : Assert
1084
    {
1085
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1086
        {
1087
            return $this;
1088
        }
1089
        $this->string($message, $fieldName);
1090
        if ( ! preg_match($pattern, $this->value) )
1091
        {
1092
            $message = $message ?: $this->overrideError;
1093
            $message = sprintf(
1094
                $message ?: 'Value "%s" does not match expression.',
1095
                $this->stringify($this->value)
1096
            );
1097
1098
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_REGEX, $fieldName, ['pattern' => $pattern]);
1099
        }
1100
1101
        return $this;
1102
    }
1103
1104
    /**
1105
     * Assert that value is a valid IP address.
1106
     *
1107
     * @param string $message
1108
     * @param string $fieldName
1109
     * @return Assert
1110
     * @throws AssertionFailedException
1111
     */
1112
    public function ipAddress(string $message='', string $fieldName='') : Assert
1113
    {
1114
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1115
        {
1116
            return $this;
1117
        }
1118
        $this->string($message, $fieldName);
1119
        $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])$/';
1120
        if ( ! preg_match($pattern, $this->value) )
1121
        {
1122
            $message = $message ?: $this->overrideError;
1123
            $message = sprintf(
1124
                $message ?: 'Value "%s" was expected to be a valid IP Address',
1125
                $this->stringify($this->value)
1126
            );
1127
1128
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_IP_ADDRESS, $fieldName);
1129
        }
1130
1131
        return $this;
1132
    }
1133
1134
    /**
1135
     * Assert that value does not match a provided Regex.
1136
     *
1137
     * @param string $pattern
1138
     * @param string $message
1139
     * @param string $fieldName
1140
     * @return Assert
1141
     * @throws AssertionFailedException
1142
     */
1143
    public function notRegex(string $pattern, string $message='', string $fieldName='') : Assert
1144
    {
1145
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1146
        {
1147
            return $this;
1148
        }
1149
        $this->string($message, $fieldName);
1150
        if ( preg_match($pattern, $this->value) )
1151
        {
1152
            $message = $message ?: $this->overrideError;
1153
            $message = sprintf(
1154
                $message ?: 'Value "%s" does not match expression.',
1155
                $this->stringify($this->value)
1156
            );
1157
1158
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_REGEX, $fieldName, ['pattern' => $pattern]);
1159
        }
1160
1161
        return $this;
1162
    }
1163
1164
    /**
1165
     * Assert that value is a string and has a character count which is equal to a given length.
1166
     *
1167
     * @param int    $length
1168
     * @param string $message
1169
     * @param string $fieldName
1170
     * @param string $encoding
1171
     * @return Assert
1172
     * @throws AssertionFailedException
1173
     */
1174 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...
1175
    {
1176
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1177
        {
1178
            return $this;
1179
        }
1180
        $this->string($message, $fieldName);
1181
        if ( mb_strlen($this->value, $encoding) !== $length )
1182
        {
1183
            $message    = $message ?: $this->overrideError;
1184
            $message    = sprintf(
1185
                $message ?: 'Value "%s" has to be %d exactly characters long, but length is %d.',
1186
                $this->stringify($this->value),
1187
                $length,
1188
                mb_strlen($this->value, $encoding)
1189
            );
1190
            $constraints = ['length' => $length, 'encoding' => $encoding];
1191
1192
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_LENGTH, $fieldName, $constraints);
1193
        }
1194
1195
        return $this;
1196
    }
1197
1198
    /**
1199
     * Assert that value is a string and has a character count which is
1200
     * greater than or equal to a given lower limit ($minLength chars).
1201
     *
1202
     * @param int    $minLength
1203
     * @param string $message
1204
     * @param string $fieldName
1205
     * @param string $encoding
1206
     * @return Assert
1207
     * @throws AssertionFailedException
1208
     */
1209 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...
1210
    {
1211
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1212
        {
1213
            return $this;
1214
        }
1215
        $this->string($message, $fieldName);
1216
        if ( mb_strlen($this->value, $encoding) < $minLength )
1217
        {
1218
            $message = $message ?: $this->overrideError;
1219
            $message     = sprintf(
1220
                $message
1221
                    ?: 'Value "%s" is too short, it should have more than %d characters, but only has %d characters.',
1222
                $this->stringify($this->value),
1223
                $minLength,
1224
                mb_strlen($this->value, $encoding)
1225
            );
1226
            $constraints = ['min_length' => $minLength, 'encoding' => $encoding];
1227
1228
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MIN_LENGTH, $fieldName, $constraints);
1229
        }
1230
1231
        return $this;
1232
    }
1233
1234
    /**
1235
     * Assert that value is a string and has a character count which is
1236
     * less than or equal to given upper limit ($maxLength chars).
1237
     *
1238
     * @param int    $maxLength
1239
     * @param string $message
1240
     * @param string $fieldName
1241
     * @param string $encoding
1242
     * @return Assert
1243
     * @throws AssertionFailedException
1244
     */
1245 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...
1246
    {
1247
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1248
        {
1249
            return $this;
1250
        }
1251
        $this->string($message, $fieldName);
1252
        if ( mb_strlen($this->value, $encoding) > $maxLength )
1253
        {
1254
            $message = $message ?: $this->overrideError;
1255
            $message     = sprintf(
1256
                $message ?: 'Value "%s" is too long, it should have no more than %d characters, but has %d characters.',
1257
                $this->stringify($this->value),
1258
                $maxLength,
1259
                mb_strlen($this->value, $encoding)
1260
            );
1261
            $constraints = ['max_length' => $maxLength, 'encoding' => $encoding];
1262
1263
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MAX_LENGTH, $fieldName, $constraints);
1264
        }
1265
1266
        return $this;
1267
    }
1268
1269
    /**
1270
     * Assert that value has a length between min,max lengths (inclusive).
1271
     *
1272
     * @param int    $minLength
1273
     * @param int    $maxLength
1274
     * @param string $message
1275
     * @param string $fieldName
1276
     * @param string      $encoding
1277
     * @return Assert
1278
     * @throws AssertionFailedException
1279
     */
1280
    public function betweenLength(int $minLength, int $maxLength, string $message='', string $fieldName='', string $encoding='utf8') : Assert
1281
    {
1282
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1283
        {
1284
            return $this;
1285
        }
1286
        $this->string($message, $fieldName);
1287
        if ( mb_strlen($this->value, $encoding) < $minLength )
1288
        {
1289
            $message = $message ?: $this->overrideError;
1290
            $message     = sprintf(
1291
                $message
1292
                    ?: 'Value "%s" is too short, it should have more than %d characters, but only has %d characters.',
1293
                $this->stringify($this->value),
1294
                $minLength,
1295
                mb_strlen($this->value, $encoding)
1296
            );
1297
            $constraints = ['min_length' => $minLength, 'encoding' => $encoding];
1298
1299
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MIN_LENGTH, $fieldName, $constraints);
1300
        }
1301
        if ( mb_strlen($this->value, $encoding) > $maxLength )
1302
        {
1303
            $message = $message ?: $this->overrideError;
1304
            $message     = sprintf(
1305
                $message ?: 'Value "%s" is too long, it should have no more than %d characters, but has %d characters.',
1306
                $this->stringify($this->value),
1307
                $maxLength,
1308
                mb_strlen($this->value, $encoding)
1309
            );
1310
            $constraints = ['max_length' => $maxLength, 'encoding' => $encoding];
1311
1312
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MAX_LENGTH, $fieldName, $constraints);
1313
        }
1314
1315
        return $this;
1316
    }
1317
1318
    /**
1319
     * Assert that value starts with a sequence of chars.
1320
     *
1321
     * @param string $needle
1322
     * @param string $message
1323
     * @param string $fieldName
1324
     * @param string $encoding
1325
     * @return Assert
1326
     * @throws AssertionFailedException
1327
     */
1328 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...
1329
    {
1330
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1331
        {
1332
            return $this;
1333
        }
1334
        $this->string($message, $fieldName);
1335
        if ( mb_strpos($this->value, $needle, 0, $encoding) !== 0 )
1336
        {
1337
            $message = $message ?: $this->overrideError;
1338
            $message     = sprintf(
1339
                $message ?: 'Value "%s" does not start with "%s".',
1340
                $this->stringify($this->value),
1341
                $this->stringify($needle)
1342
            );
1343
            $constraints = ['needle' => $needle, 'encoding' => $encoding];
1344
1345
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_STRING_START, $fieldName, $constraints);
1346
        }
1347
1348
        return $this;
1349
    }
1350
1351
    /**
1352
     * Assert that value ends with a sequence of chars.
1353
     *
1354
     * @param string $needle
1355
     * @param string $message
1356
     * @param string $fieldName
1357
     * @param string $encoding
1358
     * @return Assert
1359
     * @throws AssertionFailedException
1360
     */
1361
    public function endsWith(string $needle, string $message='', string $fieldName='', string $encoding='utf8') : Assert
1362
    {
1363
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1364
        {
1365
            return $this;
1366
        }
1367
        $this->string($message, $fieldName);
1368
        $stringPosition = mb_strlen($this->value, $encoding) - mb_strlen($needle, $encoding);
1369
        if ( mb_strripos($this->value, $needle, 0 , $encoding) !== $stringPosition )
1370
        {
1371
            $message = $message ?: $this->overrideError;
1372
            $message     = sprintf(
1373
                $message ?: 'Value "%s" does not end with "%s".',
1374
                $this->stringify($this->value),
1375
                $this->stringify($needle)
1376
            );
1377
            $constraints = ['needle' => $needle, 'encoding' => $encoding];
1378
1379
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_STRING_END, $fieldName, $constraints);
1380
        }
1381
1382
        return $this;
1383
    }
1384
1385
    /**
1386
     * Assert that value contains a sequence of chars.
1387
     *
1388
     * @param string $needle
1389
     * @param string $message
1390
     * @param string $fieldName
1391
     * @param string $encoding
1392
     * @return Assert
1393
     * @throws AssertionFailedException
1394
     */
1395 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...
1396
    {
1397
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1398
        {
1399
            return $this;
1400
        }
1401
        $this->string($message, $fieldName);
1402
        if ( mb_strpos($this->value, $needle, 0, $encoding) === false )
1403
        {
1404
            $message = $message ?: $this->overrideError;
1405
            $message     = sprintf(
1406
                $message ?: 'Value "%s" does not contain "%s".',
1407
                $this->stringify($this->value),
1408
                $this->stringify($needle)
1409
            );
1410
            $constraints = ['needle' => $needle, 'encoding' => $encoding];
1411
1412
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_STRING_CONTAINS, $fieldName, $constraints);
1413
        }
1414
1415
        return $this;
1416
    }
1417
1418
    /**
1419
     * Assert that value is in an array of choices.
1420
     *
1421
     * @param array  $choices
1422
     * @param string $message
1423
     * @param string $fieldName
1424
     * @return Assert
1425
     * @throws AssertionFailedException
1426
     */
1427
    public function choice(array $choices, string $message='', string $fieldName='') : Assert
1428
    {
1429
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1430
        {
1431
            return $this;
1432
        }
1433
        if ( !in_array($this->value, $choices, true) )
1434
        {
1435
            $message = $message ?: $this->overrideError;
1436
            $message = sprintf(
1437
                $message ?: 'Value "%s" is not an element of the valid values: %s',
1438
                $this->stringify($this->value),
1439
                implode(", ", array_map('Terah\Assert\Assert::stringify', $choices))
1440
            );
1441
1442
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_CHOICE, $fieldName, ['choices' => $choices]);
1443
        }
1444
1445
        return $this;
1446
    }
1447
1448
    /**
1449
     * Alias of {@see choice()}
1450
     *
1451
     * @param array  $choices
1452
     * @param string $message
1453
     * @param string $fieldName
1454
     * @return Assert
1455
     * @throws AssertionFailedException
1456
     */
1457
    public function inArray(array $choices, string $message='', string $fieldName='') : Assert
1458
    {
1459
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1460
        {
1461
            return $this;
1462
        }
1463
        $this->choice($choices, $message, $fieldName);
1464
1465
        return $this;
1466
    }
1467
1468
    /**
1469
     * Assert that value is numeric.
1470
     *
1471
     * @param string $message
1472
     * @param string $fieldName
1473
     * @return Assert
1474
     * @throws AssertionFailedException
1475
     */
1476
    public function numeric(string $message='', string $fieldName='') : Assert
1477
    {
1478
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1479
        {
1480
            return $this;
1481
        }
1482
        if ( ! is_numeric($this->value) )
1483
        {
1484
            $message = $message ?: $this->overrideError;
1485
            $message = sprintf(
1486
                $message ?: 'Value "%s" is not numeric.',
1487
                $this->stringify($this->value)
1488
            );
1489
1490
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NUMERIC, $fieldName);
1491
        }
1492
1493
        return $this;
1494
    }
1495
1496
    /**
1497
     * Assert that value is a non-empty array.
1498
     *
1499
     * @param string $message
1500
     * @param string $fieldName
1501
     * @return Assert
1502
     * @throws AssertionFailedException
1503
     */
1504
    public function nonEmptyArray(string $message='', string $fieldName='') : Assert
1505
    {
1506
        $message = $message ?: 'Value "%s" is not a non-empty array.';
1507
1508
        return $this->isArray($message, $fieldName)->notEmpty($message, $fieldName);
1509
    }
1510
1511
    /**
1512
     * Assert that value is a non-empty int.
1513
     *
1514
     * @param string $message
1515
     * @param string $fieldName
1516
     * @return Assert
1517
     * @throws AssertionFailedException
1518
     */
1519
    public function nonEmptyInt(string $message='', string $fieldName='') : Assert
1520
    {
1521
        $message = $message ?: 'Value "%s" is not a non-empty integer.';
1522
1523
        return $this->integer($message, $fieldName)->notEmpty($message, $fieldName);
1524
    }
1525
1526
    /**
1527
     * Assert that value is a non-empty string.
1528
     *
1529
     * @param string $message
1530
     * @param string $fieldName
1531
     * @return Assert
1532
     * @throws AssertionFailedException
1533
     */
1534
    public function nonEmptyString(string $message='', string $fieldName='') : Assert
1535
    {
1536
        $message = $message ?: 'Value "%s" is not a non-empty string.';
1537
1538
        return $this->string($message, $fieldName)->notEmpty($message, $fieldName);
1539
    }
1540
1541
    /**
1542
     * Assert that value is an array.
1543
     *
1544
     * @param string $message
1545
     * @param string $fieldName
1546
     * @return Assert
1547
     * @throws AssertionFailedException
1548
     */
1549
    public function isArray(string $message='', string $fieldName='') : Assert
1550
    {
1551
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1552
        {
1553
            return $this;
1554
        }
1555
        if ( !is_array($this->value) )
1556
        {
1557
            $message = $message ?: $this->overrideError;
1558
            $message = sprintf(
1559
                $message ?: 'Value "%s" is not an array.',
1560
                $this->stringify($this->value)
1561
            );
1562
1563
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_ARRAY, $fieldName);
1564
        }
1565
1566
        return $this;
1567
    }
1568
1569
    /**
1570
     * Assert that value is an array or a traversable object.
1571
     *
1572
     * @param string $message
1573
     * @param string $fieldName
1574
     * @return Assert
1575
     * @throws AssertionFailedException
1576
     */
1577
    public function isTraversable(string $message='', string $fieldName='') : Assert
1578
    {
1579
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1580
        {
1581
            return $this;
1582
        }
1583
        if ( !is_array($this->value) && !$this->value instanceof \Traversable )
1584
        {
1585
            $message = $message ?: $this->overrideError;
1586
            $message = sprintf(
1587
                $message ?: 'Value "%s" is not an array and does not implement Traversable.',
1588
                $this->stringify($this->value)
1589
            );
1590
1591
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_TRAVERSABLE, $fieldName);
1592
        }
1593
1594
        return $this;
1595
    }
1596
1597
    /**
1598
     * Assert that value is an array or an array-accessible object.
1599
     *
1600
     * @param string $message
1601
     * @param string $fieldName
1602
     * @return Assert
1603
     * @throws AssertionFailedException
1604
     */
1605
    public function isArrayAccessible(string $message='', string $fieldName='') : Assert
1606
    {
1607
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1608
        {
1609
            return $this;
1610
        }
1611
        if ( !is_array($this->value) && !$this->value instanceof \ArrayAccess )
1612
        {
1613
            $message = $message ?: $this->overrideError;
1614
            $message = sprintf(
1615
                $message ?: 'Value "%s" is not an array and does not implement ArrayAccess.',
1616
                $this->stringify($this->value)
1617
            );
1618
1619
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_ARRAY_ACCESSIBLE, $fieldName);
1620
        }
1621
1622
        return $this;
1623
    }
1624
1625
    /**
1626
     * Assert that key exists in the values array.
1627
     *
1628
     * @param string|integer $key
1629
     * @param string         $message
1630
     * @param string         $fieldName
1631
     * @return Assert
1632
     * @throws AssertionFailedException
1633
     */
1634
    public function keyExists($key, string $message='', string $fieldName='') : Assert
1635
    {
1636
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1637
        {
1638
            return $this;
1639
        }
1640
        $this->isArray($message, $fieldName);
1641
        if ( !array_key_exists($key, $this->value) )
1642
        {
1643
            $message = $message ?: $this->overrideError;
1644
            $message = sprintf(
1645
                $message ?: 'Array does not contain an element with key "%s"',
1646
                $this->stringify($key)
1647
            );
1648
1649
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_KEY_EXISTS, $fieldName, ['key' => $key]);
1650
        }
1651
1652
        return $this;
1653
    }
1654
1655
    /**
1656
     * Assert that keys exist in the values array.
1657
     *
1658
     * @param array  $keys
1659
     * @param string $message
1660
     * @param string $fieldName
1661
     * @return Assert
1662
     * @throws AssertionFailedException
1663
     */
1664
    public function keysExist(array $keys, string $message='', string $fieldName='') : Assert
1665
    {
1666
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1667
        {
1668
            return $this;
1669
        }
1670
        $this->isArray($message, $fieldName);
1671
        foreach ( $keys as $key )
1672
        {
1673
            if ( !array_key_exists($key, $this->value) )
1674
            {
1675
                $message = $message
1676
                    ?: sprintf(
1677
                        'Array does not contain an element with key "%s"',
1678
                        $this->stringify($key)
1679
                    );
1680
                throw $this->createException($message, $this->overrideCode ?: self::INVALID_KEYS_EXIST, $fieldName, ['key' => $key]);
1681
            }
1682
        }
1683
1684
        return $this;
1685
    }
1686
1687
    /**
1688
     * Assert that a property (key) exists in the values array.
1689
     *
1690
     * @param string|integer $key
1691
     * @param string|null    $message
1692
     * @param string|null    $fieldName
1693
     * @return Assert
1694
     * @throws AssertionFailedException
1695
     */
1696
    public function propertyExists($key, string $message='', string $fieldName='') : Assert
1697
    {
1698
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1699
        {
1700
            return $this;
1701
        }
1702
        $this->isObject($message, $fieldName);
1703
        if ( !property_exists($this->value, $key) && !isset( $this->value->{$key} ) )
1704
        {
1705
            $message = $message
1706
                ?: sprintf(
1707
                    'Object does not contain a property with key "%s"',
1708
                    $this->stringify($key)
1709
                );
1710
1711
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_PROPERTY_EXISTS, $fieldName, ['key' => $key]);
1712
        }
1713
1714
        return $this;
1715
    }
1716
1717
    /**
1718
     * Assert that properties (keys) exist in the values array.
1719
     *
1720
     * @param array  $keys
1721
     * @param string $message
1722
     * @param string $fieldName
1723
     * @return Assert
1724
     * @throws AssertionFailedException
1725
     */
1726
    public function propertiesExist(array $keys, string $message='', string $fieldName='') : Assert
1727
    {
1728
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1729
        {
1730
            return $this;
1731
        }
1732
        $this->isObject($message, $fieldName);
1733
        foreach ( $keys as $key )
1734
        {
1735
            // Using isset to allow resolution of magically defined properties
1736
            if ( !property_exists($this->value, $key) && !isset( $this->value->{$key} ) )
1737
            {
1738
                $message = $message
1739
                    ?: sprintf(
1740
                        'Object does not contain a property with key "%s"',
1741
                        $this->stringify($key)
1742
                    );
1743
                throw $this->createException($message, $this->overrideCode ?: self::INVALID_PROPERTIES_EXIST, $fieldName, ['key' => $key]);
1744
            }
1745
        }
1746
1747
        return $this;
1748
    }
1749
1750
    /**
1751
     * Assert that value is valid utf8.
1752
     *
1753
     * @param string $message
1754
     * @param string $fieldName
1755
     * @return Assert
1756
     * @throws AssertionFailedException
1757
     */
1758 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...
1759
    {
1760
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1761
        {
1762
            return $this;
1763
        }
1764
        $this->string($message, $fieldName);
1765
        if ( mb_detect_encoding($this->value, 'UTF-8', true) !== 'UTF-8' )
1766
        {
1767
            $message = $message
1768
                ?: sprintf(
1769
                    'Value "%s" was expected to be a valid UTF8 string',
1770
                    $this->stringify($this->value)
1771
                );
1772
1773
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_UTF8, $fieldName);
1774
        }
1775
1776
        return $this;
1777
    }
1778
1779
1780
    /**
1781
     * Assert that value is valid ascii.
1782
     *
1783
     * @param string $message
1784
     * @param string $fieldName
1785
     * @return Assert
1786
     * @throws AssertionFailedException
1787
     */
1788 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...
1789
    {
1790
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1791
        {
1792
            return $this;
1793
        }
1794
        $this->string($message, $fieldName);
1795
        if ( ! preg_match('/^[ -~]+$/', $this->value) )
1796
        {
1797
            $message = $message
1798
                ?: sprintf(
1799
                    'Value "%s" was expected to be a valid ASCII string',
1800
                    $this->stringify($this->value)
1801
                );
1802
1803
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_ASCII, $fieldName);
1804
        }
1805
1806
        return $this;
1807
    }
1808
1809
    /**
1810
     * Assert that key exists in an array/array-accessible object
1811
     * (using isset()).
1812
     *
1813
     * @param string|integer $key
1814
     * @param string|null    $message
1815
     * @param string|null    $fieldName
1816
     * @return Assert
1817
     * @throws AssertionFailedException
1818
     */
1819
    public function keyIsset($key, string $message='', string $fieldName='') : Assert
1820
    {
1821
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1822
        {
1823
            return $this;
1824
        }
1825
        $this->isArrayAccessible($message, $fieldName);
1826
        if ( !isset( $this->value[$key] ) )
1827
        {
1828
            $message = $message ?: $this->overrideError;
1829
            $message = sprintf(
1830
                $message ?: 'The element with key "%s" was not found',
1831
                $this->stringify($key)
1832
            );
1833
1834
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_KEY_ISSET, $fieldName, ['key' => $key]);
1835
        }
1836
1837
        return $this;
1838
    }
1839
1840
    /**
1841
     * Assert that key exists in an array/array-accessible object
1842
     * and its value is not empty.
1843
     *
1844
     * @param string|integer $key
1845
     * @param string|null    $message
1846
     * @param string|null    $fieldName
1847
     * @return Assert
1848
     * @throws AssertionFailedException
1849
     */
1850
    public function notEmptyKey($key, string $message='', string $fieldName='') : Assert
1851
    {
1852
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1853
        {
1854
            return $this;
1855
        }
1856
        $this->keyIsset($key, $message, $fieldName);
1857
        (new Assert($this->value[$key]))->setExceptionClass($this->exceptionClass)->notEmpty($message, $fieldName);
1858
1859
        return $this;
1860
    }
1861
1862
    /**
1863
     * Assert that value is not blank.
1864
     *
1865
     * @param string $message
1866
     * @param string $fieldName
1867
     * @return Assert
1868
     * @throws AssertionFailedException
1869
     */
1870 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...
1871
    {
1872
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1873
        {
1874
            return $this;
1875
        }
1876
        if ( false === $this->value || ( empty( $this->value ) && '0' != $this->value ) )
1877
        {
1878
            $message = $message ?: $this->overrideError;
1879
            $message = sprintf(
1880
                $message ?: 'Value "%s" is blank, but was expected to contain a value.',
1881
                $this->stringify($this->value)
1882
            );
1883
1884
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NOT_BLANK, $fieldName);
1885
        }
1886
1887
        return $this;
1888
    }
1889
1890
    /**
1891
     * Assert that value is an instance of a given class-name.
1892
     *
1893
     * @param string $className
1894
     * @param string $message
1895
     * @param string $fieldName
1896
     * @return Assert
1897
     * @throws AssertionFailedException
1898
     */
1899
    public function isInstanceOf(string $className, string $message='', string $fieldName='') : Assert
1900
    {
1901
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1902
        {
1903
            return $this;
1904
        }
1905
        if ( !( $this->value instanceof $className ) )
1906
        {
1907
            $message = $message ?: $this->overrideError;
1908
            $message = sprintf(
1909
                $message ?: 'Class "%s" was expected to be instanceof of "%s" but is not.',
1910
                $this->stringify($this->value),
1911
                $className
1912
            );
1913
1914
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_INSTANCE_OF, $fieldName, ['class' => $className]);
1915
        }
1916
1917
        return $this;
1918
    }
1919
1920
    /**
1921
     * Assert that value is not an instance of given class-name.
1922
     *
1923
     * @param string $className
1924
     * @param string $message
1925
     * @param string $fieldName
1926
     * @return Assert
1927
     * @throws AssertionFailedException
1928
     */
1929
    public function notIsInstanceOf(string $className, string $message='', string $fieldName='') : Assert
1930
    {
1931
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1932
        {
1933
            return $this;
1934
        }
1935
        if ( $this->value instanceof $className )
1936
        {
1937
            $message = $message ?: $this->overrideError;
1938
            $message = sprintf(
1939
                $message ?: 'Class "%s" was not expected to be instanceof of "%s".',
1940
                $this->stringify($this->value),
1941
                $className
1942
            );
1943
1944
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NOT_INSTANCE_OF, $fieldName, ['class' => $className]);
1945
        }
1946
1947
        return $this;
1948
    }
1949
1950
    /**
1951
     * Assert that value is a subclass of given class-name.
1952
     *
1953
     * @param string $className
1954
     * @param string $message
1955
     * @param string $fieldName
1956
     * @return Assert
1957
     * @throws AssertionFailedException
1958
     */
1959
    public function subclassOf(string $className, string $message='', string $fieldName='') : Assert
1960
    {
1961
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1962
        {
1963
            return $this;
1964
        }
1965
        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...
1966
        {
1967
            $message = $message ?: $this->overrideError;
1968
            $message = sprintf(
1969
                $message ?: 'Class "%s" was expected to be subclass of "%s".',
1970
                $this->stringify($this->value),
1971
                $className
1972
            );
1973
1974
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_SUBCLASS_OF, $fieldName, ['class' => $className]);
1975
        }
1976
1977
        return $this;
1978
    }
1979
1980
    /**
1981
     * Assert that value is within a range of numbers (inclusive).
1982
     *
1983
     * @param float    $minValue
1984
     * @param float    $maxValue
1985
     * @param string $message
1986
     * @param string $fieldName
1987
     * @return Assert
1988
     * @throws AssertionFailedException
1989
     */
1990
    public function range(float $minValue, float $maxValue, string $message='', string $fieldName='') : Assert
1991
    {
1992
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
1993
        {
1994
            return $this;
1995
        }
1996
        $this->numeric($message, $fieldName);
1997
        if ( $this->value < $minValue || $this->value > $maxValue )
1998
        {
1999
            $message = $message ?: $this->overrideError;
2000
            $message = sprintf(
2001
                $message ?: 'Number "%s" was expected to be at least "%d" and at most "%d".',
2002
                $this->stringify($this->value),
2003
                $this->stringify($minValue),
2004
                $this->stringify($maxValue)
2005
            );
2006
2007
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_RANGE, $fieldName, [
2008
                'min' => $minValue,
2009
                'max' => $maxValue
2010
            ]);
2011
        }
2012
2013
        return $this;
2014
    }
2015
2016
    /**
2017
     * Assert that value is larger or equal to a given lower limit.
2018
     *
2019
     * @param int    $minValue
2020
     * @param string $message
2021
     * @param string $fieldName
2022
     * @return Assert
2023
     * @throws AssertionFailedException
2024
     */
2025
    public function min(int $minValue, string $message='', string $fieldName='') : Assert
2026
    {
2027
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2028
        {
2029
            return $this;
2030
        }
2031
        $this->numeric($message, $fieldName);
2032
        if ( $this->value < $minValue )
2033
        {
2034
            $message = $message ?: $this->overrideError;
2035
            $message = sprintf(
2036
                $message ?: 'Number "%s" was expected to be at least "%d".',
2037
                $this->stringify($this->value),
2038
                $this->stringify($minValue)
2039
            );
2040
2041
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MIN, $fieldName, ['min' => $minValue]);
2042
        }
2043
2044
        return $this;
2045
    }
2046
2047
    /**
2048
     * Assert that value is smaller than or equal to a given upper limit.
2049
     *
2050
     * @param int    $maxValue
2051
     * @param string $message
2052
     * @param string $fieldName
2053
     * @return Assert
2054
     * @throws AssertionFailedException
2055
     */
2056
    public function max(int $maxValue, string $message='', string $fieldName='') : Assert
2057
    {
2058
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2059
        {
2060
            return $this;
2061
        }
2062
        $this->numeric($message, $fieldName);
2063
        if ( $this->value > $maxValue )
2064
        {
2065
            $message = $message ?: $this->overrideError;
2066
            $message = sprintf(
2067
                $message ?: 'Number "%s" was expected to be at most "%d".',
2068
                $this->stringify($this->value),
2069
                $this->stringify($maxValue)
2070
            );
2071
2072
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_MAX, $fieldName, ['max' => $maxValue]);
2073
        }
2074
2075
        return $this;
2076
    }
2077
2078
    /**
2079
     * Assert that value is a file that exists.
2080
     *
2081
     * @param string $message
2082
     * @param string $fieldName
2083
     * @return Assert
2084
     * @throws AssertionFailedException
2085
     */
2086
    public function file(string $message='', string $fieldName='') : Assert
2087
    {
2088
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2089
        {
2090
            return $this;
2091
        }
2092
        $this->string($message, $fieldName);
2093
        $this->notEmpty($message, $fieldName);
2094
        if ( !is_file($this->value) )
2095
        {
2096
            $message = $message ?: $this->overrideError;
2097
            $message = sprintf(
2098
                $message ?: 'File "%s" was expected to exist.',
2099
                $this->stringify($this->value)
2100
            );
2101
2102
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_FILE, $fieldName);
2103
        }
2104
2105
        return $this;
2106
    }
2107
2108
    /**
2109
     * Assert that value is a file or directory that exists.
2110
     *
2111
     * @param string $message
2112
     * @param string $fieldName
2113
     * @return Assert
2114
     * @throws AssertionFailedException
2115
     */
2116
    public function fileOrDirectoryExists(string $message='', string $fieldName='') : Assert
2117
    {
2118
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2119
        {
2120
            return $this;
2121
        }
2122
        $this->string($message, $fieldName);
2123
        $this->notEmpty($message, $fieldName);
2124
        if ( ! file_exists($this->value) )
2125
        {
2126
            $message = $message ?: $this->overrideError;
2127
            $message = sprintf(
2128
                $message ?: 'File or directory "%s" was expected to exist.',
2129
                $this->stringify($this->value)
2130
            );
2131
2132
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_FILE_OR_DIR, $fieldName);
2133
        }
2134
2135
        return $this;
2136
    }
2137
2138
    /**
2139
     * Assert that value is a directory that exists.
2140
     *
2141
     * @param string $message
2142
     * @param string $fieldName
2143
     * @return Assert
2144
     * @throws AssertionFailedException
2145
     */
2146 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...
2147
    {
2148
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2149
        {
2150
            return $this;
2151
        }
2152
        $this->string($message, $fieldName);
2153
        if ( !is_dir($this->value) )
2154
        {
2155
            $message = $message ?: $this->overrideError;
2156
            $message = sprintf(
2157
                $message ?: 'Path "%s" was expected to be a directory.',
2158
                $this->stringify($this->value)
2159
            );
2160
2161
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_DIRECTORY, $fieldName);
2162
        }
2163
2164
        return $this;
2165
    }
2166
2167
    /**
2168
     * Assert that value is something readable.
2169
     *
2170
     * @param string $message
2171
     * @param string $fieldName
2172
     * @return Assert
2173
     * @throws AssertionFailedException
2174
     */
2175 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...
2176
    {
2177
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2178
        {
2179
            return $this;
2180
        }
2181
        $this->string($message, $fieldName);
2182
        if ( !is_readable($this->value) )
2183
        {
2184
            $message = $message ?: $this->overrideError;
2185
            $message = sprintf(
2186
                $message ?: 'Path "%s" was expected to be readable.',
2187
                $this->stringify($this->value)
2188
            );
2189
2190
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_READABLE, $fieldName);
2191
        }
2192
2193
        return $this;
2194
    }
2195
2196
    /**
2197
     * Assert that value is something writeable.
2198
     *
2199
     * @param string $message
2200
     * @param string $fieldName
2201
     * @return Assert
2202
     * @throws AssertionFailedException
2203
     */
2204 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...
2205
    {
2206
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2207
        {
2208
            return $this;
2209
        }
2210
        $this->string($message, $fieldName);
2211
        if ( !is_writeable($this->value) )
2212
        {
2213
            $message = $message ?: $this->overrideError;
2214
            $message = sprintf(
2215
                $message ?: 'Path "%s" was expected to be writeable.',
2216
                $this->stringify($this->value)
2217
            );
2218
2219
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_WRITEABLE, $fieldName);
2220
        }
2221
2222
        return $this;
2223
    }
2224
2225
    /**
2226
     * Assert that value is a valid email address (using input_filter/FILTER_VALIDATE_EMAIL).
2227
     *
2228
     * @param string $message
2229
     * @param string $fieldName
2230
     * @return Assert
2231
     * @throws AssertionFailedException
2232
     */
2233
    public function email(string $message='', string $fieldName='') : Assert
2234
    {
2235
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2236
        {
2237
            return $this;
2238
        }
2239
        $this->string($message, $fieldName);
2240
        if ( ! filter_var($this->value, FILTER_VALIDATE_EMAIL) )
2241
        {
2242
            $message = $message ?: $this->overrideError;
2243
            $message = sprintf(
2244
                $message ?: 'Value "%s" was expected to be a valid e-mail address.',
2245
                $this->stringify($this->value)
2246
            );
2247
2248
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_EMAIL, $fieldName);
2249
        }
2250
        else
2251
        {
2252
            $host = substr($this->value, strpos($this->value, '@') + 1);
2253
            // Likely not a FQDN, bug in PHP FILTER_VALIDATE_EMAIL prior to PHP 5.3.3
2254
            if ( version_compare(PHP_VERSION, '5.3.3', '<') && strpos($host, '.') === false )
2255
            {
2256
                $message = $message ?: $this->overrideError;
2257
                $message = sprintf(
2258
                    $message ?: 'Value "%s" was expected to be a valid e-mail address.',
2259
                    $this->stringify($this->value)
2260
                );
2261
                throw $this->createException($message, $this->overrideCode ?: self::INVALID_EMAIL, $fieldName);
2262
            }
2263
        }
2264
2265
        return $this;
2266
    }
2267
2268
    /**
2269
     * Assert that value is a valid email prefix.
2270
     *
2271
     * @param string $message
2272
     * @param string $fieldName
2273
     * @return Assert
2274
     * @throws AssertionFailedException
2275
     */
2276
    public function emailPrefix(string $message='', string $fieldName='') : Assert
2277
    {
2278
        $this->value($this->value . '@example.com');
2279
2280
        return $this->email($message, $fieldName);
2281
    }
2282
2283
    /**
2284
     * Assert that value is a valid URL.
2285
     *
2286
     * This code snipped was taken from the Symfony project and modified to the special demands of this method.
2287
     *
2288
     * @param string $message
2289
     * @param string $fieldName
2290
     * @return Assert
2291
     * @throws AssertionFailedException
2292
     *
2293
     *
2294
     * @link https://github.com/symfony/Validator/blob/master/Constraints/UrlValidator.php
2295
     * @link https://github.com/symfony/Validator/blob/master/Constraints/Url.php
2296
     */
2297
    public function url(string $message='', string $fieldName='') : Assert
2298
    {
2299
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2300
        {
2301
            return $this;
2302
        }
2303
        $this->string($message, $fieldName);
2304
        $protocols = ['http', 'https'];
2305
        $pattern   = '~^
2306
            (%s)://                                 # protocol
2307
            (
2308
                ([\pL\pN\pS-]+\.)+[\pL]+                   # a domain name
2309
                    |                                     #  or
2310
                \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}      # a IP address
2311
                    |                                     #  or
2312
                \[
2313
                    (?:(?:(?:(?:(?:(?:(?:[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})))?::))))
2314
                \]  # a IPv6 address
2315
            )
2316
            (:[0-9]+)?                              # a port (optional)
2317
            (/?|/\S+)                               # a /, nothing or a / with something
2318
        $~ixu';
2319
        $pattern   = sprintf($pattern, implode('|', $protocols));
2320
        if ( !preg_match($pattern, $this->value) )
2321
        {
2322
            $message = $message ?: $this->overrideError;
2323
            $message = sprintf(
2324
                $message ?: 'Value "%s" was expected to be a valid URL starting with http or https',
2325
                $this->stringify($this->value)
2326
            );
2327
2328
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_URL, $fieldName);
2329
        }
2330
2331
        return $this;
2332
    }
2333
2334
    /**
2335
     * Assert that value is domain name.
2336
     *
2337
     * This code snipped was taken from the Symfony project and modified to the special demands of this method.
2338
     *
2339
     * @param string $message
2340
     * @param string $fieldName
2341
     * @return Assert
2342
     * @throws AssertionFailedException
2343
     *
2344
     */
2345
    public function domainName(string $message='', string $fieldName='') : Assert
2346
    {
2347
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2348
        {
2349
            return $this;
2350
        }
2351
        $this->string($message, $fieldName);
2352
        $pattern   = '/^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6}$/';
2353
        if ( ! preg_match($pattern, $this->value) )
2354
        {
2355
            $message = $message ?: $this->overrideError;
2356
            $message = sprintf(
2357
                $message ?: 'Value "%s" was expected to be a valid domain name',
2358
                $this->stringify($this->value)
2359
            );
2360
2361
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_DOMAIN_NAME, $fieldName);
2362
        }
2363
2364
        return $this;
2365
    }
2366
2367
    /**
2368
     * Assert that value is alphanumeric.
2369
     *
2370
     * @param string $message
2371
     * @param string $fieldName
2372
     * @return Assert
2373
     * @throws AssertionFailedException
2374
     */
2375 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...
2376
    {
2377
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2378
        {
2379
            return $this;
2380
        }
2381
        try
2382
        {
2383
            $this->regex('/^04[0-9]{8})$/', $message, $fieldName);
2384
        }
2385
        catch ( AssertionFailedException $e )
2386
        {
2387
            $message = $message ?: $this->overrideError;
2388
            $message = sprintf(
2389
                $message
2390
                    ?: 'Value "%s" is not an australian mobile number.',
2391
                $this->stringify($this->value)
2392
            );
2393
2394
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_AUS_MOBILE, $fieldName);
2395
        }
2396
2397
        return $this;
2398
    }
2399
2400
    /**
2401
     * Assert that value is alphanumeric.
2402
     *
2403
     * @param string $message
2404
     * @param string $fieldName
2405
     * @return Assert
2406
     * @throws AssertionFailedException
2407
     */
2408 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...
2409
    {
2410
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2411
        {
2412
            return $this;
2413
        }
2414
        try
2415
        {
2416
            $this->regex('(^([a-zA-Z]{1}[a-zA-Z0-9]*)$)', $message, $fieldName);
2417
        }
2418
        catch (AssertionFailedException $e)
2419
        {
2420
            $message = $message ?: $this->overrideError;
2421
            $message = sprintf(
2422
                $message
2423
                    ?: 'Value "%s" is not alphanumeric, starting with letters and containing only letters and numbers.',
2424
                $this->stringify($this->value)
2425
            );
2426
2427
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_ALNUM, $fieldName);
2428
        }
2429
2430
        return $this;
2431
    }
2432
2433
    /**
2434
     * Assert that value is boolean True.
2435
     *
2436
     * @param string $message
2437
     * @param string $fieldName
2438
     * @return Assert
2439
     * @throws AssertionFailedException
2440
     */
2441
    public function true(string $message='', string $fieldName='') : Assert
2442
    {
2443
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2444
        {
2445
            return $this;
2446
        }
2447
        if ( $this->value !== true )
2448
        {
2449
            $message = $message ?: $this->overrideError;
2450
            $message = sprintf(
2451
                $message ?: 'Value "%s" is not TRUE.',
2452
                $this->stringify($this->value)
2453
            );
2454
2455
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_TRUE, $fieldName);
2456
        }
2457
2458
        return $this;
2459
    }
2460
2461
    /**
2462
     * Assert that value is boolean True.
2463
     *
2464
     * @param string $message
2465
     * @param string $fieldName
2466
     * @return Assert
2467
     * @throws AssertionFailedException
2468
     */
2469
    public function truthy(string $message='', string $fieldName='') : Assert
2470
    {
2471
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2472
        {
2473
            return $this;
2474
        }
2475
        if ( ! $this->value )
2476
        {
2477
            $message = $message ?: $this->overrideError;
2478
            $message = sprintf(
2479
                $message ?: 'Value "%s" is not truthy.',
2480
                $this->stringify($this->value)
2481
            );
2482
2483
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_TRUE, $fieldName);
2484
        }
2485
2486
        return $this;
2487
    }
2488
2489
    /**
2490
     * Assert that value is boolean False.
2491
     *
2492
     * @param string $message
2493
     * @param string $fieldName
2494
     * @return Assert
2495
     * @throws AssertionFailedException
2496
     */
2497
    public function false(string $message='', string $fieldName='') : Assert
2498
    {
2499
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2500
        {
2501
            return $this;
2502
        }
2503
        if ( $this->value !== false )
2504
        {
2505
            $message = $message ?: $this->overrideError;
2506
            $message = sprintf(
2507
                $message ?: 'Value "%s" is not FALSE.',
2508
                $this->stringify($this->value)
2509
            );
2510
2511
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_FALSE, $fieldName);
2512
        }
2513
2514
        return $this;
2515
    }
2516
2517
    /**
2518
     * Assert that value is not boolean False.
2519
     *
2520
     * @param string $message
2521
     * @param string $fieldName
2522
     * @return Assert
2523
     * @throws AssertionFailedException
2524
     */
2525
    public function notFalse(string $message='', string $fieldName='') : Assert
2526
    {
2527
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2528
        {
2529
            return $this;
2530
        }
2531
        if ( $this->value === false )
2532
        {
2533
            $message = $message ?: $this->overrideError;
2534
            $message = sprintf(
2535
                $message ?: 'Value "%s" is not FALSE.',
2536
                $this->stringify($this->value)
2537
            );
2538
2539
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_NOT_FALSE, $fieldName);
2540
        }
2541
2542
        return $this;
2543
    }
2544
2545
    /**
2546
     * Assert that the class exists.
2547
     *
2548
     * @param string $message
2549
     * @param string $fieldName
2550
     * @return Assert
2551
     * @throws AssertionFailedException
2552
     */
2553
    public function classExists(string $message='', string $fieldName='') : Assert
2554
    {
2555
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2556
        {
2557
            return $this;
2558
        }
2559
        if ( !class_exists($this->value) )
2560
        {
2561
            $message = $message ?: $this->overrideError;
2562
            $message = sprintf(
2563
                $message ?: 'Class "%s" does not exist.',
2564
                $this->stringify($this->value)
2565
            );
2566
2567
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_CLASS, $fieldName);
2568
        }
2569
2570
        return $this;
2571
    }
2572
2573
    /**
2574
     * @param string $interfaceName
2575
     * @param string $message
2576
     * @param string $fieldName
2577
     * @return Assert
2578
     * @throws AssertionFailedException
2579
     * @throws \ReflectionException
2580
     */
2581
    public function implementsInterface(string $interfaceName, string $message='', string $fieldName='') : Assert
2582
    {
2583
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2584
        {
2585
            return $this;
2586
        }
2587
        $reflection = new \ReflectionClass($this->value);
2588
        if ( !$reflection->implementsInterface($interfaceName) )
2589
        {
2590
            $message = $message ?: $this->overrideError;
2591
            $message = sprintf(
2592
                $message ?: 'Class "%s" does not implement interface "%s".',
2593
                $this->stringify($this->value),
2594
                $this->stringify($interfaceName)
2595
            );
2596
2597
            throw $this->createException($message, self::INTERFACE_NOT_IMPLEMENTED, $fieldName, ['interface' => $interfaceName]);
2598
        }
2599
2600
        return $this;
2601
    }
2602
2603
    /**
2604
     * Assert that value is a valid json string.
2605
     *
2606
     * NOTICE:
2607
     * Since this does a json_decode to determine its validity
2608
     * you probably should consider, when using the variable
2609
     * content afterwards, just to decode and check for yourself instead
2610
     * of using this assertion.
2611
     *
2612
     * @param string $message
2613
     * @param string $fieldName
2614
     * @return Assert
2615
     * @throws AssertionFailedException
2616
     */
2617
    public function isJsonString(string $message='', string $fieldName='') : Assert
2618
    {
2619
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2620
        {
2621
            return $this;
2622
        }
2623
        if ( null === json_decode($this->value) && JSON_ERROR_NONE !== json_last_error() )
2624
        {
2625
            $message = $message ?: $this->overrideError;
2626
            $message = sprintf(
2627
                $message ?: 'Value "%s" is not a valid JSON string.',
2628
                $this->stringify($this->value)
2629
            );
2630
2631
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_JSON_STRING, $fieldName);
2632
        }
2633
2634
        return $this;
2635
    }
2636
2637
    /**
2638
     * Assert that value is a valid UUID.
2639
     *
2640
     * Uses code from {@link https://github.com/ramsey/uuid} that is MIT licensed.
2641
     *
2642
     * @param string $message
2643
     * @param string $fieldName
2644
     * @return Assert
2645
     * @throws AssertionFailedException
2646
     */
2647
    public function uuid(string $message='', string $fieldName='') : Assert
2648
    {
2649
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2650
        {
2651
            return $this;
2652
        }
2653
        $this->value = str_replace(['urn:', 'uuid:', '{', '}'], '', $this->value);
2654
        if ( $this->value === '00000000-0000-0000-0000-000000000000' )
2655
        {
2656
            return $this;
2657
        }
2658
        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) )
2659
        {
2660
            $message = $message ?: $this->overrideError;
2661
            $message = sprintf(
2662
                $message ?: 'Value "%s" is not a valid UUID.',
2663
                $this->stringify($this->value)
2664
            );
2665
2666
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_UUID, $fieldName);
2667
        }
2668
2669
        return $this;
2670
    }
2671
    /**
2672
     * Assert that value is a valid samAccountName (in line with Active
2673
     * directory sAMAccountName restrictions for users).
2674
     *
2675
     * From: @link https://social.technet.microsoft.com/wiki/contents/articles/11216.active-directory-requirements-for-creating-objects.aspx#Objects_with_sAMAccountName_Attribute
2676
     *      The schema allows 256 characters in sAMAccountName values. However, the system limits sAMAccountName to
2677
     *      20 characters for user objects and 16 characters for computer objects. The following characters are not
2678
     *      allowed in sAMAccountName values: " [ ] : ; | = + * ? < > / \ ,
2679
     *      You cannot logon to a domain using a sAMAccountName that includes the "@" character. If a user has a
2680
     *      sAMAccountName with this character, they must logon using their userPrincipalName (UPN).
2681
     *
2682
     * @param string $message
2683
     * @param string $fieldName
2684
     * @return Assert
2685
     * @throws AssertionFailedException
2686
     */
2687 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...
2688
    {
2689
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2690
        {
2691
            return $this;
2692
        }
2693
        if ( !preg_match('/^([a-z0-9]{4,20})$/', $this->value) )
2694
        {
2695
            $message = $message ?: $this->overrideError;
2696
            $message = sprintf(
2697
                $message ?: 'Value "%s" is not a valid samAccountName.',
2698
                $this->stringify($this->value)
2699
            );
2700
2701
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_SAMACCOUNTNAME, $fieldName);
2702
        }
2703
2704
        return $this;
2705
    }
2706
2707
    /**
2708
     * Assert that value is a valid userPrincipalName.
2709
     *
2710
     * @param string $message
2711
     * @param string $fieldName
2712
     * @return Assert
2713
     * @throws AssertionFailedException
2714
     */
2715 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...
2716
    {
2717
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2718
        {
2719
            return $this;
2720
        }
2721
        try
2722
        {
2723
            $this->email($message, $fieldName);
2724
        }
2725
        catch (AssertionFailedException $e)
2726
        {
2727
            $message = $message ?: $this->overrideError;
2728
            $message = sprintf(
2729
                $message
2730
                    ?: 'Value "%s" is not a valid userPrincipalName.',
2731
                $this->stringify($this->value)
2732
            );
2733
2734
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_USERPRINCIPALNAME, $fieldName);
2735
        }
2736
2737
        return $this;
2738
    }
2739
2740
    /**
2741
     * Assert that the given string is a valid UUID
2742
     *
2743
     * Uses code from {@link https://github.com/ramsey/uuid} that is MIT licensed.
2744
     *
2745
     * @param string|null $message
2746
     * @param string|null $propertyPath
0 ignored issues
show
Bug introduced by
There is no parameter named $propertyPath. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2747
     * @return Assert
2748
     * @throws AssertionFailedException
2749
     */
2750 View Code Duplication
    public function isni(string $message='', string $fieldName='')
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...
2751
    {
2752
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2753
        {
2754
            return $this;
2755
        }
2756
        if ( !preg_match('/^[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{3}[0-9X]{1}$/', $this->value) )
2757
        {
2758
            $message = $message ?: $this->overrideError;
2759
            $message = sprintf(
2760
                $message ?: 'Value "%s" is not a valid ISNI.',
2761
                $this->stringify($this->value)
2762
            );
2763
2764
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_ISNI, $fieldName);
2765
        }
2766
2767
        return $this;
2768
    }
2769
2770
    /**
2771
     * Assert that the count of countable is equal to count.
2772
     *
2773
     * @param int    $count
2774
     * @param string $message
2775
     * @param string $fieldName
2776
     * @return Assert
2777
     * @throws AssertionFailedException
2778
     */
2779
    public function count(int $count, string $message='', string $fieldName='') : Assert
2780
    {
2781
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2782
        {
2783
            return $this;
2784
        }
2785
        if ( $count !== count($this->value) )
2786
        {
2787
            $message = $message ?: $this->overrideError;
2788
            $message = sprintf(
2789
                $message ?: 'List does not contain exactly "%d" elements.',
2790
                $this->stringify($this->value),
2791
                $this->stringify($count)
2792
            );
2793
2794
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_COUNT, $fieldName, ['count' => $count]);
2795
        }
2796
2797
        return $this;
2798
    }
2799
2800
    /**
2801
     * @param $func
2802
     * @param $args
2803
     * @return bool
2804
     * @throws AssertionFailedException
2805
     */
2806
    protected function doAllOrNullOr($func, $args) : bool
2807
    {
2808
        if ( $this->nullOr && is_null($this->value) )
2809
        {
2810
            return true;
2811
        }
2812
        if ( $this->emptyOr && empty($this->value) )
2813
        {
2814
            return true;
2815
        }
2816
        if ( $this->all && (new Assert($this->value))->setExceptionClass($this->exceptionClass)->isTraversable() )
2817
        {
2818
            foreach ( $this->value as $idx => $value )
2819
            {
2820
                $object = (new Assert($value))->setExceptionClass($this->exceptionClass);
2821
                call_user_func_array([$object, $func], $args);
2822
            }
2823
            return true;
2824
        }
2825
2826
        return ( $this->nullOr && is_null($this->value) ) || ( $this->emptyOr && empty($this->value) ) ? true : false;
2827
    }
2828
2829
    /**
2830
     * Assert if values array has every choice as key and that this choice has content.
2831
     *
2832
     * @param array  $choices
2833
     * @param string $message
2834
     * @param string $fieldName
2835
     * @return Assert
2836
     * @throws AssertionFailedException
2837
     */
2838
    public function choicesNotEmpty(array $choices, string $message='', string $fieldName='') : Assert
2839
    {
2840
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2841
        {
2842
            return $this;
2843
        }
2844
        $this->notEmpty($message, $fieldName);
2845
        foreach ( $choices as $choice )
2846
        {
2847
            $this->notEmptyKey($choice, $message, $fieldName);
2848
        }
2849
2850
        return $this;
2851
    }
2852
2853
    /**
2854
     * Assert that the named method is defined in the provided object.
2855
     *
2856
     * @param mixed  $object
2857
     * @param string $message
2858
     * @param string $fieldName
2859
     * @returns Assert
2860
     * @throws AssertionFailedException
2861
     */
2862
    public function methodExists($object, string $message='', string $fieldName='') : Assert
2863
    {
2864
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2865
        {
2866
            return $this;
2867
        }
2868
        (new Assert($object))->setExceptionClass($this->exceptionClass)->isObject($message, $fieldName);
2869
        if ( !method_exists($object, $this->value) )
2870
        {
2871
            $message = $message ?: $this->overrideError;
2872
            $message = sprintf(
2873
                $message ?: 'Expected "%s" does not a exist in provided object.',
2874
                $this->stringify($this->value)
2875
            );
2876
2877
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_METHOD, $fieldName);
2878
        }
2879
2880
        return $this;
2881
    }
2882
2883
    /**
2884
     * Assert that value is an object.
2885
     *
2886
     * @param string $message
2887
     * @param string $fieldName
2888
     * @return Assert
2889
     * @throws AssertionFailedException
2890
     */
2891
    public function isObject(string $message='', string $fieldName='') : Assert
2892
    {
2893
        if ( $this->doAllOrNullOr(__FUNCTION__, func_get_args()) )
2894
        {
2895
            return $this;
2896
        }
2897
        if ( !is_object($this->value) )
2898
        {
2899
            $message = $message ?: $this->overrideError;
2900
            $message = sprintf(
2901
                $message ?: 'Provided "%s" is not a valid object.',
2902
                $this->stringify($this->value)
2903
            );
2904
2905
            throw $this->createException($message, $this->overrideCode ?: self::INVALID_OBJECT, $fieldName);
2906
        }
2907
2908
        return $this;
2909
    }
2910
2911
    /**
2912
     * Make a string version of a value.
2913
     *
2914
     * @param $value
2915
     * @return string
2916
     */
2917
    private function stringify($value) : string
2918
    {
2919
        if ( is_bool($value) )
2920
        {
2921
            return $value ? '<TRUE>' : '<FALSE>';
2922
        }
2923
        if ( is_scalar($value) )
2924
        {
2925
            $val = (string)$value;
2926
            if ( strlen($val) > 100 )
2927
            {
2928
                $val = substr($val, 0, 97) . '...';
2929
            }
2930
2931
            return $val;
2932
        }
2933
        if ( is_array($value) )
2934
        {
2935
            return '<ARRAY>';
2936
        }
2937
        if ( is_object($value) )
2938
        {
2939
            return get_class($value);
2940
        }
2941
        if ( is_resource($value) )
2942
        {
2943
            return '<RESOURCE>';
2944
        }
2945
        if ( $value === null )
2946
        {
2947
            return '<NULL>';
2948
        }
2949
2950
        return 'unknown';
2951
    }
2952
}
2953
2954