├── LICENSE ├── composer.json └── lib └── Assert ├── Assert.php ├── Assertion.php ├── AssertionChain.php ├── AssertionFailedException.php ├── InvalidArgumentException.php ├── LazyAssertion.php ├── LazyAssertionException.php └── functions.php /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2013, Benjamin Eberlei 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | - Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "beberlei/assert", 3 | "description": "Thin assertion library for input validation in business models.", 4 | "authors": [ 5 | { 6 | "name": "Benjamin Eberlei", 7 | "email": "kontakt@beberlei.de", 8 | "role": "Lead Developer" 9 | }, 10 | { 11 | "name": "Richard Quadling", 12 | "email": "rquadling@gmail.com", 13 | "role": "Collaborator" 14 | } 15 | ], 16 | "license": "BSD-2-Clause", 17 | "keywords": [ 18 | "assert", 19 | "assertion", 20 | "validation" 21 | ], 22 | "config": { 23 | "sort-packages": true 24 | }, 25 | "require": { 26 | "php": "^7.1 || ^8.0", 27 | "ext-simplexml": "*", 28 | "ext-mbstring": "*", 29 | "ext-ctype": "*", 30 | "ext-json": "*" 31 | }, 32 | "require-dev": { 33 | "friendsofphp/php-cs-fixer": "*", 34 | "phpstan/phpstan": "*", 35 | "phpunit/phpunit": ">=6.0.0", 36 | "yoast/phpunit-polyfills": "^0.1.0" 37 | }, 38 | "autoload": { 39 | "psr-4": { 40 | "Assert\\": "lib/Assert" 41 | }, 42 | "files": [ 43 | "lib/Assert/functions.php" 44 | ] 45 | }, 46 | "autoload-dev": { 47 | "psr-4": { 48 | "Assert\\Tests\\": "tests/Assert/Tests" 49 | }, 50 | "files": [ 51 | "tests/Assert/Tests/Fixtures/functions.php" 52 | ] 53 | }, 54 | "scripts": { 55 | "assert:generate-docs": "php bin/generate_method_docs.php", 56 | "assert:cs-lint": "php-cs-fixer fix --diff -vvv --dry-run", 57 | "assert:cs-fix": "php-cs-fixer fix . -vvv || true", 58 | "assert:sa-code": "vendor/bin/phpstan analyse --configuration=phpstan-code.neon --no-progress --ansi -l 7 bin lib", 59 | "assert:sa-tests": "vendor/bin/phpstan analyse --configuration=phpstan-tests.neon --no-progress --ansi -l 7 tests" 60 | }, 61 | "suggest": { 62 | "ext-intl": "Needed to allow Assertion::count(), Assertion::isCountable(), Assertion::minCount(), and Assertion::maxCount() to operate on ResourceBundles" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/Assert/Assert.php: -------------------------------------------------------------------------------- 1 | notEmpty()->integer(); 40 | * Assert::that($value)->nullOr()->string()->startsWith("Foo"); 41 | * 42 | * The assertion chain can be stateful, that means be careful when you reuse 43 | * it. You should never pass around the chain. 44 | */ 45 | public static function that($value, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain 46 | { 47 | $assertionChain = new AssertionChain($value, $defaultMessage, $defaultPropertyPath); 48 | 49 | return $assertionChain->setAssertionClassName(static::$assertionClass); 50 | } 51 | 52 | /** 53 | * Start validation on a set of values, returns {@link AssertionChain}. 54 | * 55 | * @param mixed $values 56 | * @param string|callable|null $defaultMessage 57 | */ 58 | public static function thatAll($values, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain 59 | { 60 | return static::that($values, $defaultMessage, $defaultPropertyPath)->all(); 61 | } 62 | 63 | /** 64 | * Start validation and allow NULL, returns {@link AssertionChain}. 65 | * 66 | * @param mixed $value 67 | * @param string|callable|null $defaultMessage 68 | */ 69 | public static function thatNullOr($value, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain 70 | { 71 | return static::that($value, $defaultMessage, $defaultPropertyPath)->nullOr(); 72 | } 73 | 74 | /** 75 | * Create a lazy assertion object. 76 | */ 77 | public static function lazy(): LazyAssertion 78 | { 79 | $lazyAssertion = new LazyAssertion(); 80 | 81 | return $lazyAssertion 82 | ->setAssertClass(\get_called_class()) 83 | ->setExceptionClass(static::$lazyAssertionExceptionClass); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /lib/Assert/Assertion.php: -------------------------------------------------------------------------------- 1 | 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 $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 $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 ? '' : ''; 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 = ''; 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 = ''; 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 | -------------------------------------------------------------------------------- /lib/Assert/AssertionChain.php: -------------------------------------------------------------------------------- 1 | 23 | * 24 | * @method AssertionChain alnum(string|callable $message = null, string $propertyPath = null) Assert that value is alphanumeric. 25 | * @method AssertionChain base64(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined. 26 | * @method AssertionChain between(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. 27 | * @method AssertionChain betweenExclusive(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. 28 | * @method AssertionChain betweenLength(int $minLength, int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string length is between min and max lengths. 29 | * @method AssertionChain boolean(string|callable $message = null, string $propertyPath = null) Assert that value is php boolean. 30 | * @method AssertionChain choice(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. 31 | * @method AssertionChain choicesNotEmpty(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. 32 | * @method AssertionChain classExists(string|callable $message = null, string $propertyPath = null) Assert that the class exists. 33 | * @method AssertionChain contains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string contains a sequence of chars. 34 | * @method AssertionChain count(int $count, string|callable $message = null, string $propertyPath = null) Assert that the count of countable is equal to count. 35 | * @method AssertionChain date(string $format, string|callable $message = null, string $propertyPath = null) Assert that date is valid and corresponds to the given format. 36 | * @method AssertionChain defined(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined. 37 | * @method AssertionChain digit(string|callable $message = null, string $propertyPath = null) Validates if an integer or integerish is a digit. 38 | * @method AssertionChain directory(string|callable $message = null, string $propertyPath = null) Assert that a directory exists. 39 | * @method AssertionChain e164(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid E164 Phone Number. 40 | * @method AssertionChain email(string|callable $message = null, string $propertyPath = null) Assert that value is an email address (using input_filter/FILTER_VALIDATE_EMAIL). 41 | * @method AssertionChain endsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string ends with a sequence of chars. 42 | * @method AssertionChain eq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are equal (using ==). 43 | * @method AssertionChain eqArraySubset(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that the array contains the subset. 44 | * @method AssertionChain extensionLoaded(string|callable $message = null, string $propertyPath = null) Assert that extension is loaded. 45 | * @method AssertionChain extensionVersion(string $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded and a specific version is installed. 46 | * @method AssertionChain false(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean False. 47 | * @method AssertionChain file(string|callable $message = null, string $propertyPath = null) Assert that a file exists. 48 | * @method AssertionChain float(string|callable $message = null, string $propertyPath = null) Assert that value is a php float. 49 | * @method AssertionChain greaterOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater or equal than given limit. 50 | * @method AssertionChain greaterThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater than given limit. 51 | * @method AssertionChain implementsInterface(string $interfaceName, string|callable $message = null, string $propertyPath = null) Assert that the class implements the interface. 52 | * @method AssertionChain inArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. This is an alias of Assertion::choice(). 53 | * @method AssertionChain integer(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer. 54 | * @method AssertionChain integerish(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer'ish. 55 | * @method AssertionChain interfaceExists(string|callable $message = null, string $propertyPath = null) Assert that the interface exists. 56 | * @method AssertionChain ip(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 or IPv6 address. 57 | * @method AssertionChain ipv4(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 address. 58 | * @method AssertionChain ipv6(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv6 address. 59 | * @method AssertionChain isArray(string|callable $message = null, string $propertyPath = null) Assert that value is an array. 60 | * @method AssertionChain isArrayAccessible(string|callable $message = null, string $propertyPath = null) Assert that value is an array or an array-accessible object. 61 | * @method AssertionChain isCallable(string|callable $message = null, string $propertyPath = null) Determines that the provided value is callable. 62 | * @method AssertionChain isCountable(string|callable $message = null, string $propertyPath = null) Assert that value is countable. 63 | * @method AssertionChain isInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is instance of given class-name. 64 | * @method AssertionChain isJsonString(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid json string. 65 | * @method AssertionChain isObject(string|callable $message = null, string $propertyPath = null) Determines that the provided value is an object. 66 | * @method AssertionChain isResource(string|callable $message = null, string $propertyPath = null) Assert that value is a resource. 67 | * @method AssertionChain isTraversable(string|callable $message = null, string $propertyPath = null) Assert that value is an array or a traversable object. 68 | * @method AssertionChain keyExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array. 69 | * @method AssertionChain keyIsset(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object using isset(). 70 | * @method AssertionChain keyNotExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key does not exist in an array. 71 | * @method AssertionChain length(int $length, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string has a given length. 72 | * @method AssertionChain lessOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less or equal than given limit. 73 | * @method AssertionChain lessThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less than given limit. 74 | * @method AssertionChain max(mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that a number is smaller as a given limit. 75 | * @method AssertionChain maxCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at most $count elements. 76 | * @method AssertionChain maxLength(int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string value is not longer than $maxLength chars. 77 | * @method AssertionChain methodExists(mixed $object, string|callable $message = null, string $propertyPath = null) Determines that the named method is defined in the provided object. 78 | * @method AssertionChain min(mixed $minValue, string|callable $message = null, string $propertyPath = null) Assert that a value is at least as big as a given limit. 79 | * @method AssertionChain minCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at least $count elements. 80 | * @method AssertionChain minLength(int $minLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that a string is at least $minLength chars long. 81 | * @method AssertionChain noContent(string|callable $message = null, string $propertyPath = null) Assert that value is empty. 82 | * @method AssertionChain notBlank(string|callable $message = null, string $propertyPath = null) Assert that value is not blank. 83 | * @method AssertionChain notContains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string does not contains a sequence of chars. 84 | * @method AssertionChain notEmpty(string|callable $message = null, string $propertyPath = null) Assert that value is not empty. 85 | * @method AssertionChain notEmptyKey(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. 86 | * @method AssertionChain notEq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not equal (using ==). 87 | * @method AssertionChain notInArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is not in array of choices. 88 | * @method AssertionChain notIsInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is not instance of given class-name. 89 | * @method AssertionChain notNull(string|callable $message = null, string $propertyPath = null) Assert that value is not null. 90 | * @method AssertionChain notRegex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value does not match a regex. 91 | * @method AssertionChain notSame(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not the same (using ===). 92 | * @method AssertionChain null(string|callable $message = null, string $propertyPath = null) Assert that value is null. 93 | * @method AssertionChain numeric(string|callable $message = null, string $propertyPath = null) Assert that value is numeric. 94 | * @method AssertionChain objectOrClass(string|callable $message = null, string $propertyPath = null) Assert that the value is an object, or a class that exists. 95 | * @method AssertionChain phpVersion(mixed $version, string|callable $message = null, string $propertyPath = null) Assert on PHP version. 96 | * @method AssertionChain propertiesExist(array $properties, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the properties all exist. 97 | * @method AssertionChain propertyExists(string $property, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the property exists. 98 | * @method AssertionChain range(mixed $minValue, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that value is in range of numbers. 99 | * @method AssertionChain readable(string|callable $message = null, string $propertyPath = null) Assert that the value is something readable. 100 | * @method AssertionChain regex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value matches a regex. 101 | * @method AssertionChain same(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are the same (using ===). 102 | * @method AssertionChain satisfy(callable $callback, string|callable $message = null, string $propertyPath = null) Assert that the provided value is valid according to a callback. 103 | * @method AssertionChain scalar(string|callable $message = null, string $propertyPath = null) Assert that value is a PHP scalar. 104 | * @method AssertionChain startsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string starts with a sequence of chars. 105 | * @method AssertionChain string(string|callable $message = null, string $propertyPath = null) Assert that value is a string. 106 | * @method AssertionChain subclassOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is subclass of given class-name. 107 | * @method AssertionChain true(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean True. 108 | * @method AssertionChain uniqueValues(string|callable $message = null, string $propertyPath = null) Assert that values in array are unique (using strict equality). 109 | * @method AssertionChain url(string|callable $message = null, string $propertyPath = null) Assert that value is an URL. 110 | * @method AssertionChain uuid(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid UUID. 111 | * @method AssertionChain version(string $operator, string $version2, string|callable $message = null, string $propertyPath = null) Assert comparison of two versions. 112 | * @method AssertionChain writeable(string|callable $message = null, string $propertyPath = null) Assert that the value is something writeable. 113 | */ 114 | class AssertionChain 115 | { 116 | /** 117 | * @var mixed 118 | */ 119 | private $value; 120 | 121 | /** 122 | * @var string|callable|null 123 | */ 124 | private $defaultMessage; 125 | 126 | /** 127 | * @var string|null 128 | */ 129 | private $defaultPropertyPath; 130 | 131 | /** 132 | * Return each assertion as always valid. 133 | * 134 | * @var bool 135 | */ 136 | private $alwaysValid = false; 137 | 138 | /** 139 | * Perform assertion on every element of array or traversable. 140 | * 141 | * @var bool 142 | */ 143 | private $all = false; 144 | 145 | /** @var string|Assertion Class to use for assertion calls */ 146 | private $assertionClassName = 'Assert\Assertion'; 147 | 148 | /** 149 | * AssertionChain constructor. 150 | * 151 | * @param mixed $value 152 | * @param string|callable|null $defaultMessage 153 | */ 154 | public function __construct($value, $defaultMessage = null, ?string $defaultPropertyPath = null) 155 | { 156 | $this->value = $value; 157 | $this->defaultMessage = $defaultMessage; 158 | $this->defaultPropertyPath = $defaultPropertyPath; 159 | } 160 | 161 | /** 162 | * Call assertion on the current value in the chain. 163 | * 164 | * @param string $methodName 165 | * @param array $args 166 | */ 167 | public function __call($methodName, $args): AssertionChain 168 | { 169 | if (true === $this->alwaysValid) { 170 | return $this; 171 | } 172 | 173 | try { 174 | $method = new \ReflectionMethod($this->assertionClassName, $methodName); 175 | } catch (\ReflectionException $exception) { 176 | throw new \RuntimeException("Assertion '".$methodName."' does not exist."); 177 | } 178 | 179 | \array_unshift($args, $this->value); 180 | $params = $method->getParameters(); 181 | 182 | foreach ($params as $idx => $param) { 183 | if (isset($args[$idx])) { 184 | continue; 185 | } 186 | 187 | switch ($param->getName()) { 188 | case 'message': 189 | $args[$idx] = $this->defaultMessage; 190 | break; 191 | case 'propertyPath': 192 | $args[$idx] = $this->defaultPropertyPath; 193 | break; 194 | } 195 | } 196 | 197 | if ($this->all) { 198 | $methodName = 'all'.$methodName; 199 | } 200 | 201 | \call_user_func_array([$this->assertionClassName, $methodName], $args); 202 | 203 | return $this; 204 | } 205 | 206 | /** 207 | * Switch chain into validation mode for an array of values. 208 | */ 209 | public function all(): AssertionChain 210 | { 211 | $this->all = true; 212 | 213 | return $this; 214 | } 215 | 216 | /** 217 | * Switch chain into mode allowing nulls, ignoring further assertions. 218 | */ 219 | public function nullOr(): AssertionChain 220 | { 221 | if (null === $this->value) { 222 | $this->alwaysValid = true; 223 | } 224 | 225 | return $this; 226 | } 227 | 228 | /** 229 | * @param string $className 230 | * 231 | * @return $this 232 | */ 233 | public function setAssertionClassName($className): AssertionChain 234 | { 235 | if (!\is_string($className)) { 236 | throw new LogicException('Exception class name must be passed as a string'); 237 | } 238 | 239 | if (Assertion::class !== $className && !\is_subclass_of($className, Assertion::class)) { 240 | throw new LogicException($className.' is not (a subclass of) '.Assertion::class); 241 | } 242 | 243 | $this->assertionClassName = $className; 244 | 245 | return $this; 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /lib/Assert/AssertionFailedException.php: -------------------------------------------------------------------------------- 1 | propertyPath = $propertyPath; 39 | $this->value = $value; 40 | $this->constraints = $constraints; 41 | } 42 | 43 | /** 44 | * User controlled way to define a sub-property causing 45 | * the failure of a currently asserted objects. 46 | * 47 | * Useful to transport information about the nature of the error 48 | * back to higher layers. 49 | * 50 | * @return string|null 51 | */ 52 | public function getPropertyPath() 53 | { 54 | return $this->propertyPath; 55 | } 56 | 57 | /** 58 | * Get the value that caused the assertion to fail. 59 | * 60 | * @return mixed 61 | */ 62 | public function getValue() 63 | { 64 | return $this->value; 65 | } 66 | 67 | /** 68 | * Get the constraints that applied to the failed assertion. 69 | */ 70 | public function getConstraints(): array 71 | { 72 | return $this->constraints; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /lib/Assert/LazyAssertion.php: -------------------------------------------------------------------------------- 1 | 23 | * 24 | * @method LazyAssertion alnum(string|callable $message = null, string $propertyPath = null) Assert that value is alphanumeric. 25 | * @method LazyAssertion base64(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined. 26 | * @method LazyAssertion between(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. 27 | * @method LazyAssertion betweenExclusive(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. 28 | * @method LazyAssertion betweenLength(int $minLength, int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string length is between min and max lengths. 29 | * @method LazyAssertion boolean(string|callable $message = null, string $propertyPath = null) Assert that value is php boolean. 30 | * @method LazyAssertion choice(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. 31 | * @method LazyAssertion choicesNotEmpty(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. 32 | * @method LazyAssertion classExists(string|callable $message = null, string $propertyPath = null) Assert that the class exists. 33 | * @method LazyAssertion contains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string contains a sequence of chars. 34 | * @method LazyAssertion count(int $count, string|callable $message = null, string $propertyPath = null) Assert that the count of countable is equal to count. 35 | * @method LazyAssertion date(string $format, string|callable $message = null, string $propertyPath = null) Assert that date is valid and corresponds to the given format. 36 | * @method LazyAssertion defined(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined. 37 | * @method LazyAssertion digit(string|callable $message = null, string $propertyPath = null) Validates if an integer or integerish is a digit. 38 | * @method LazyAssertion directory(string|callable $message = null, string $propertyPath = null) Assert that a directory exists. 39 | * @method LazyAssertion e164(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid E164 Phone Number. 40 | * @method LazyAssertion email(string|callable $message = null, string $propertyPath = null) Assert that value is an email address (using input_filter/FILTER_VALIDATE_EMAIL). 41 | * @method LazyAssertion endsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string ends with a sequence of chars. 42 | * @method LazyAssertion eq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are equal (using ==). 43 | * @method LazyAssertion eqArraySubset(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that the array contains the subset. 44 | * @method LazyAssertion extensionLoaded(string|callable $message = null, string $propertyPath = null) Assert that extension is loaded. 45 | * @method LazyAssertion extensionVersion(string $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded and a specific version is installed. 46 | * @method LazyAssertion false(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean False. 47 | * @method LazyAssertion file(string|callable $message = null, string $propertyPath = null) Assert that a file exists. 48 | * @method LazyAssertion float(string|callable $message = null, string $propertyPath = null) Assert that value is a php float. 49 | * @method LazyAssertion greaterOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater or equal than given limit. 50 | * @method LazyAssertion greaterThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater than given limit. 51 | * @method LazyAssertion implementsInterface(string $interfaceName, string|callable $message = null, string $propertyPath = null) Assert that the class implements the interface. 52 | * @method LazyAssertion inArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. This is an alias of Assertion::choice(). 53 | * @method LazyAssertion integer(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer. 54 | * @method LazyAssertion integerish(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer'ish. 55 | * @method LazyAssertion interfaceExists(string|callable $message = null, string $propertyPath = null) Assert that the interface exists. 56 | * @method LazyAssertion ip(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 or IPv6 address. 57 | * @method LazyAssertion ipv4(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 address. 58 | * @method LazyAssertion ipv6(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv6 address. 59 | * @method LazyAssertion isArray(string|callable $message = null, string $propertyPath = null) Assert that value is an array. 60 | * @method LazyAssertion isArrayAccessible(string|callable $message = null, string $propertyPath = null) Assert that value is an array or an array-accessible object. 61 | * @method LazyAssertion isCallable(string|callable $message = null, string $propertyPath = null) Determines that the provided value is callable. 62 | * @method LazyAssertion isCountable(string|callable $message = null, string $propertyPath = null) Assert that value is countable. 63 | * @method LazyAssertion isInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is instance of given class-name. 64 | * @method LazyAssertion isJsonString(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid json string. 65 | * @method LazyAssertion isObject(string|callable $message = null, string $propertyPath = null) Determines that the provided value is an object. 66 | * @method LazyAssertion isResource(string|callable $message = null, string $propertyPath = null) Assert that value is a resource. 67 | * @method LazyAssertion isTraversable(string|callable $message = null, string $propertyPath = null) Assert that value is an array or a traversable object. 68 | * @method LazyAssertion keyExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array. 69 | * @method LazyAssertion keyIsset(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object using isset(). 70 | * @method LazyAssertion keyNotExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key does not exist in an array. 71 | * @method LazyAssertion length(int $length, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string has a given length. 72 | * @method LazyAssertion lessOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less or equal than given limit. 73 | * @method LazyAssertion lessThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less than given limit. 74 | * @method LazyAssertion max(mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that a number is smaller as a given limit. 75 | * @method LazyAssertion maxCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at most $count elements. 76 | * @method LazyAssertion maxLength(int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string value is not longer than $maxLength chars. 77 | * @method LazyAssertion methodExists(mixed $object, string|callable $message = null, string $propertyPath = null) Determines that the named method is defined in the provided object. 78 | * @method LazyAssertion min(mixed $minValue, string|callable $message = null, string $propertyPath = null) Assert that a value is at least as big as a given limit. 79 | * @method LazyAssertion minCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at least $count elements. 80 | * @method LazyAssertion minLength(int $minLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that a string is at least $minLength chars long. 81 | * @method LazyAssertion noContent(string|callable $message = null, string $propertyPath = null) Assert that value is empty. 82 | * @method LazyAssertion notBlank(string|callable $message = null, string $propertyPath = null) Assert that value is not blank. 83 | * @method LazyAssertion notContains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string does not contains a sequence of chars. 84 | * @method LazyAssertion notEmpty(string|callable $message = null, string $propertyPath = null) Assert that value is not empty. 85 | * @method LazyAssertion notEmptyKey(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. 86 | * @method LazyAssertion notEq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not equal (using ==). 87 | * @method LazyAssertion notInArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is not in array of choices. 88 | * @method LazyAssertion notIsInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is not instance of given class-name. 89 | * @method LazyAssertion notNull(string|callable $message = null, string $propertyPath = null) Assert that value is not null. 90 | * @method LazyAssertion notRegex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value does not match a regex. 91 | * @method LazyAssertion notSame(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not the same (using ===). 92 | * @method LazyAssertion null(string|callable $message = null, string $propertyPath = null) Assert that value is null. 93 | * @method LazyAssertion numeric(string|callable $message = null, string $propertyPath = null) Assert that value is numeric. 94 | * @method LazyAssertion objectOrClass(string|callable $message = null, string $propertyPath = null) Assert that the value is an object, or a class that exists. 95 | * @method LazyAssertion phpVersion(mixed $version, string|callable $message = null, string $propertyPath = null) Assert on PHP version. 96 | * @method LazyAssertion propertiesExist(array $properties, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the properties all exist. 97 | * @method LazyAssertion propertyExists(string $property, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the property exists. 98 | * @method LazyAssertion range(mixed $minValue, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that value is in range of numbers. 99 | * @method LazyAssertion readable(string|callable $message = null, string $propertyPath = null) Assert that the value is something readable. 100 | * @method LazyAssertion regex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value matches a regex. 101 | * @method LazyAssertion same(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are the same (using ===). 102 | * @method LazyAssertion satisfy(callable $callback, string|callable $message = null, string $propertyPath = null) Assert that the provided value is valid according to a callback. 103 | * @method LazyAssertion scalar(string|callable $message = null, string $propertyPath = null) Assert that value is a PHP scalar. 104 | * @method LazyAssertion startsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string starts with a sequence of chars. 105 | * @method LazyAssertion string(string|callable $message = null, string $propertyPath = null) Assert that value is a string. 106 | * @method LazyAssertion subclassOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is subclass of given class-name. 107 | * @method LazyAssertion true(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean True. 108 | * @method LazyAssertion uniqueValues(string|callable $message = null, string $propertyPath = null) Assert that values in array are unique (using strict equality). 109 | * @method LazyAssertion url(string|callable $message = null, string $propertyPath = null) Assert that value is an URL. 110 | * @method LazyAssertion uuid(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid UUID. 111 | * @method LazyAssertion version(string $operator, string $version2, string|callable $message = null, string $propertyPath = null) Assert comparison of two versions. 112 | * @method LazyAssertion writeable(string|callable $message = null, string $propertyPath = null) Assert that the value is something writeable. 113 | * @method LazyAssertion all() Switch chain into validation mode for an array of values. 114 | * @method LazyAssertion nullOr() Switch chain into mode allowing nulls, ignoring further assertions. 115 | */ 116 | class LazyAssertion 117 | { 118 | private $currentChainFailed = false; 119 | private $alwaysTryAll = false; 120 | private $thisChainTryAll = false; 121 | private $currentChain; 122 | private $errors = []; 123 | 124 | /** @var string The class to use as AssertionChain factory */ 125 | private $assertClass = Assert::class; 126 | 127 | /** @var string|LazyAssertionException The class to use for exceptions */ 128 | private $exceptionClass = LazyAssertionException::class; 129 | 130 | /** 131 | * @param mixed $value 132 | * @param string|callable|null $defaultMessage 133 | * 134 | * @return static 135 | */ 136 | public function that($value, ?string $propertyPath = null, $defaultMessage = null) 137 | { 138 | $this->currentChainFailed = false; 139 | $this->thisChainTryAll = false; 140 | $assertClass = $this->assertClass; 141 | $this->currentChain = $assertClass::that($value, $defaultMessage, $propertyPath); 142 | 143 | return $this; 144 | } 145 | 146 | /** 147 | * @return static 148 | */ 149 | public function tryAll() 150 | { 151 | if (!$this->currentChain) { 152 | $this->alwaysTryAll = true; 153 | } 154 | 155 | $this->thisChainTryAll = true; 156 | 157 | return $this; 158 | } 159 | 160 | /** 161 | * @param string $method 162 | * @param array $args 163 | * 164 | * @return static 165 | */ 166 | public function __call($method, $args) 167 | { 168 | if (false === $this->alwaysTryAll 169 | && false === $this->thisChainTryAll 170 | && true === $this->currentChainFailed 171 | ) { 172 | return $this; 173 | } 174 | 175 | try { 176 | \call_user_func_array([$this->currentChain, $method], $args); 177 | } catch (AssertionFailedException $e) { 178 | $this->errors[] = $e; 179 | $this->currentChainFailed = true; 180 | } 181 | 182 | return $this; 183 | } 184 | 185 | /** 186 | * @throws LazyAssertionException 187 | */ 188 | public function verifyNow(): bool 189 | { 190 | if ($this->errors) { 191 | throw \call_user_func([$this->exceptionClass, 'fromErrors'], $this->errors); 192 | } 193 | 194 | return true; 195 | } 196 | 197 | /** 198 | * @param string $className 199 | * 200 | * @return static 201 | */ 202 | public function setAssertClass(string $className): LazyAssertion 203 | { 204 | if (Assert::class !== $className && !\is_subclass_of($className, Assert::class)) { 205 | throw new LogicException($className.' is not (a subclass of) '.Assert::class); 206 | } 207 | 208 | $this->assertClass = $className; 209 | 210 | return $this; 211 | } 212 | 213 | /** 214 | * @param string $className 215 | * 216 | * @return static 217 | */ 218 | public function setExceptionClass(string $className): LazyAssertion 219 | { 220 | if (LazyAssertionException::class !== $className && !\is_subclass_of($className, LazyAssertionException::class)) { 221 | throw new LogicException($className.' is not (a subclass of) '.LazyAssertionException::class); 222 | } 223 | 224 | $this->exceptionClass = $className; 225 | 226 | return $this; 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /lib/Assert/LazyAssertionException.php: -------------------------------------------------------------------------------- 1 | getPropertyPath(), $error->getMessage()); 34 | } 35 | 36 | return new static($message, $errors); 37 | } 38 | 39 | public function __construct($message, array $errors) 40 | { 41 | parent::__construct($message, 0, null, null); 42 | 43 | $this->errors = $errors; 44 | } 45 | 46 | /** 47 | * @return InvalidArgumentException[] 48 | */ 49 | public function getErrorExceptions(): array 50 | { 51 | return $this->errors; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/Assert/functions.php: -------------------------------------------------------------------------------- 1 | notEmpty()->integer(); 30 | * \Assert\that($value)->nullOr()->string()->startsWith("Foo"); 31 | * 32 | * The assertion chain can be stateful, that means be careful when you reuse 33 | * it. You should never pass around the chain. 34 | */ 35 | function that($value, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain 36 | { 37 | return Assert::that($value, $defaultMessage, $defaultPropertyPath); 38 | } 39 | 40 | /** 41 | * Start validation on a set of values, returns {@link AssertionChain}. 42 | * 43 | * @param mixed $values 44 | * @param string|callable|null $defaultMessage 45 | * @param string $defaultPropertyPath 46 | */ 47 | function thatAll($values, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain 48 | { 49 | return Assert::thatAll($values, $defaultMessage, $defaultPropertyPath); 50 | } 51 | 52 | /** 53 | * Start validation and allow NULL, returns {@link AssertionChain}. 54 | * 55 | * @param mixed $value 56 | * @param string|callable|null $defaultMessage 57 | * @param string $defaultPropertyPath 58 | * 59 | * @deprecated In favour of Assert::thatNullOr($value, $defaultMessage = null, $defaultPropertyPath = null) 60 | */ 61 | function thatNullOr($value, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain 62 | { 63 | return Assert::thatNullOr($value, $defaultMessage, $defaultPropertyPath); 64 | } 65 | 66 | /** 67 | * Create a lazy assertion object. 68 | */ 69 | function lazy(): LazyAssertion 70 | { 71 | return Assert::lazy(); 72 | } 73 | --------------------------------------------------------------------------------