Completed
Push — master ( c7cca1...33976c )
by Terry
01:39
created

Assert::name()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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