diff --git a/README.md b/README.md index 766099c..85a9885 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,7 @@ Method | Description `ipv6($value, $message = '')` | Check that a string is a valid IPv6 `email($value, $message = '')` | Check that a string is a valid e-mail address `notWhitespaceOnly($value, $message = '')` | Check that a string contains at least one non-whitespace character +`validRegexPattern($value, $message = '')` | Check that a string is a valid regular expression pattern ### File Assertions diff --git a/src/Assert.php b/src/Assert.php index b962e3e..05c1349 100644 --- a/src/Assert.php +++ b/src/Assert.php @@ -1227,6 +1227,26 @@ public static function notRegex($value, $pattern, $message = '') } } + /** + * @psalm-pure + * + * @param string $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function validRegexPattern($value, $message = 'The value %s must be a valid regex pattern.') + { + static::string($value); + + if (@\preg_match($value, '') === false) { + static::reportInvalidArgument(\sprintf( + $message, + $value + )); + } + } + /** * @psalm-pure * diff --git a/src/Mixin.php b/src/Mixin.php index fad0d47..9f1edd4 100644 --- a/src/Mixin.php +++ b/src/Mixin.php @@ -3200,6 +3200,59 @@ public static function allNullOrNotRegex($value, $pattern, $message = '') } } + /** + * @psalm-pure + * + * @param string|null $value + * @param string $message + * + * @return void + * + * @throws InvalidArgumentException + */ + public static function nullOrValidRegexPattern($value, $message = 'The value %s must be a valid regex pattern.') + { + null === $value || static::validRegexPattern($value, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @return void + * + * @throws InvalidArgumentException + */ + public static function allValidRegexPattern($value, $message = 'The value %s must be a valid regex pattern.') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::validRegexPattern($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @return void + * + * @throws InvalidArgumentException + */ + public static function allNullOrValidRegexPattern($value, $message = 'The value %s must be a valid regex pattern.') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::validRegexPattern($entry, $message); + } + } + /** * @psalm-pure * diff --git a/tests/AssertTest.php b/tests/AssertTest.php index ef9b6be..d5734e8 100644 --- a/tests/AssertTest.php +++ b/tests/AssertTest.php @@ -595,6 +595,11 @@ public function getTests() array('uniqueValues', array(array('qwerty', 'qwerty')), false), array('uniqueValues', array(array('asdfg', 'qwerty')), true), array('uniqueValues', array(array(123, '123')), false), + array('validRegexPattern', array('/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/'), true), + array('validRegexPattern', array('/^\(\d{3}\) \d{3}-\d{4}$/'), true), + array('validRegexPattern', array('/^https?:\/\/[^\s\/$.?#].[^\s]*$/i'), true), + array('validRegexPattern', array('/^(abc/'), false), // Unclosed parenthesis + array('validRegexPattern', array('/(?:abc)\1/'), false), // Backreference to non-capturing group ); }