PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.7.2
Defender Security – Malware Scanner, Login Security & Firewall v5.7.2
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / vendor / beberlei / assert / lib / Assert / Assertion.php

Assertion.php in Defender Security – Malware Scanner, Login Security & Firewall 5.7.2, at vendor/beberlei/assert/lib/Assert/Assertion.php

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