From 1bdf24f065975594f6a117f0f1f6cabf1333b156 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Tue, 10 Sep 2019 22:37:39 +0100 Subject: [PATCH] Added Validator::allowedRegexValues (#371) Co-authored-by: Chaim Paperman --- README.md | 5 +++++ src/Regex/Regex.php | 21 ++++++++++++++++--- src/Regex/Result.php | 2 +- src/Regex/Success.php | 6 +++--- src/Validator.php | 25 ++++++++++++++++++++++ tests/Dotenv/ValidatorTest.php | 38 ++++++++++++++++++++++++++++++++++ 6 files changed, 90 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1ad50618..2f8c9b2f 100644 --- a/README.md +++ b/README.md @@ -257,6 +257,11 @@ One or more environment variables failed assertions: SESSION_STORE is not an allowed value ``` +It is also possible to define a regex that your environment variable should be. +```php +$dotenv->required('FOO')->allowedRegexValues('([[:lower:]]{3})'); +``` + ### Comments You can comment your `.env` file using the `#` character. E.g. diff --git a/src/Regex/Regex.php b/src/Regex/Regex.php index 9a37da07..3f13d69b 100644 --- a/src/Regex/Regex.php +++ b/src/Regex/Regex.php @@ -6,6 +6,21 @@ class Regex { + /** + * Perform a preg match, wrapping up the result. + * + * @param string $pattern + * @param string $subject + * + * @return \Dotenv\Regex\Result + */ + public static function match($pattern, $subject) + { + return self::pregAndWrap(function ($subject) use ($pattern) { + return (int) @preg_match($pattern, $subject); + }, $subject); + } + /** * Perform a preg replace, wrapping up the result. * @@ -18,7 +33,7 @@ class Regex public static function replace($pattern, $replacement, $subject) { return self::pregAndWrap(function ($subject) use ($pattern, $replacement) { - return preg_replace($pattern, $replacement, $subject); + return (string) @preg_replace($pattern, $replacement, $subject); }, $subject); } @@ -34,7 +49,7 @@ public static function replace($pattern, $replacement, $subject) public static function replaceCallback($pattern, callable $callback, $subject) { return self::pregAndWrap(function ($subject) use ($pattern, $callback) { - return preg_replace_callback($pattern, $callback, $subject); + return (string) @preg_replace_callback($pattern, $callback, $subject); }, $subject); } @@ -48,7 +63,7 @@ public static function replaceCallback($pattern, callable $callback, $subject) */ private static function pregAndWrap(callable $operation, $subject) { - $result = (string) @$operation($subject); + $result = $operation($subject); if (($e = preg_last_error()) !== PREG_NO_ERROR) { return Error::create(self::lookupError($e)); diff --git a/src/Regex/Result.php b/src/Regex/Result.php index 04638bb3..f7074fa7 100644 --- a/src/Regex/Result.php +++ b/src/Regex/Result.php @@ -14,7 +14,7 @@ abstract public function success(); /** * Get the error value, if possible. * - * @return string + * @return string|int */ public function getSuccess() { diff --git a/src/Regex/Success.php b/src/Regex/Success.php index 47dbda0a..3f06e968 100644 --- a/src/Regex/Success.php +++ b/src/Regex/Success.php @@ -8,14 +8,14 @@ class Success extends Result { /** - * @var string + * @var string|int */ private $value; /** * Internal constructor for a success value. * - * @param string $value + * @param string|int $value * * @return void */ @@ -27,7 +27,7 @@ private function __construct($value) /** * Create a new success value. * - * @param string $value + * @param string|int $value * * @return \Dotenv\Regex\Result */ diff --git a/src/Validator.php b/src/Validator.php index 2d1441b4..d8cdef47 100644 --- a/src/Validator.php +++ b/src/Validator.php @@ -3,6 +3,7 @@ namespace Dotenv; use Dotenv\Exception\ValidationException; +use Dotenv\Regex\Regex; /** * This is the validator class. @@ -138,6 +139,30 @@ function ($value) use ($choices) { ); } + /** + * Assert that each variable matches the given regular expression. + * + * @param string $regex + * + * @throws \Dotenv\Exception\ValidationException + * + * @return \Dotenv\Validator + */ + public function allowedRegexValues($regex) + { + return $this->assertCallback( + function ($value) use ($regex) + { + if ($value === null) { + return true; + } + + return Regex::match($regex, $value)->success()->getOrElse(0) === 1; + }, + sprintf('does not match "%s"' , $regex) + ); + } + /** * Assert that the callback returns true for each variable. * diff --git a/tests/Dotenv/ValidatorTest.php b/tests/Dotenv/ValidatorTest.php index 1967d037..bf0edc01 100644 --- a/tests/Dotenv/ValidatorTest.php +++ b/tests/Dotenv/ValidatorTest.php @@ -408,4 +408,42 @@ public function testIfPresentIntegerNonExist() $dotenv->ifPresent(['VAR_DOES_NOT_EXIST_234782462764'])->isInteger(); $this->assertTrue(true); } + + public function testDotenvRegexMatchPass() + { + $dotenv = Dotenv::create($this->fixturesFolder); + $dotenv->load(); + $dotenv->required('FOO')->allowedRegexValues('([[:lower:]]{3})'); + $this->assertTrue(true); + } + + /** + * @expectedException \Dotenv\Exception\ValidationException + * @expectedExceptionMessage One or more environment variables failed assertions: FOO does not match "/^([[:lower:]]{1})$/". + */ + public function testDotenvRegexMatchFail() + { + $dotenv = Dotenv::create($this->fixturesFolder); + $dotenv->load(); + $dotenv->required('FOO')->allowedRegexValues('/^([[:lower:]]{1})$/'); + } + + /** + * @expectedException \Dotenv\Exception\ValidationException + * @expectedExceptionMessage One or more environment variables failed assertions: FOO does not match "/([[:lower:]{1{". + */ + public function testDotenvRegexMatchError() + { + $dotenv = Dotenv::create($this->fixturesFolder); + $dotenv->load(); + $dotenv->required('FOO')->allowedRegexValues('/([[:lower:]{1{'); + } + + public function testDotenvRegexMatchNotPresent() + { + $dotenv = Dotenv::create($this->fixturesFolder); + $dotenv->load(); + $dotenv->ifPresent('FOOOOOOOOOOO')->allowedRegexValues('([[:lower:]]{3})'); + $this->assertTrue(true); + } }