Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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