diff --git a/src/CallbackValidator.php b/src/CallbackValidator.php index 611a45e..ec31f5c 100644 --- a/src/CallbackValidator.php +++ b/src/CallbackValidator.php @@ -25,21 +25,38 @@ class CallbackValidator extends BaseValidator /** @var callable Validation callback */ protected $callback; + /** @var bool Whether to cache the callback's result */ + protected $cacheResult; + + /** @var ?bool The result, if {@see self::$cacheResult} is `true` (default) */ + protected $result; + /** * Create a new callback validator * * @param callable $callback Validation callback + * @param boolean $cacheResult Whether to cache the callback's result */ - public function __construct(callable $callback) + public function __construct(callable $callback, bool $cacheResult = true) { $this->callback = $callback; + $this->cacheResult = $cacheResult; } public function isValid($value) { + if ($this->result !== null) { + return $this->result; + } + // Multiple isValid() calls must not stack validation messages $this->clearMessages(); - return call_user_func($this->callback, $value, $this); + $valid = (bool) call_user_func($this->callback, $value, $this); + if ($this->cacheResult) { + $this->result = $valid; + } + + return $valid; } } diff --git a/tests/CallbackValidatorTest.php b/tests/CallbackValidatorTest.php index 14dadac..d92c5dd 100644 --- a/tests/CallbackValidatorTest.php +++ b/tests/CallbackValidatorTest.php @@ -22,4 +22,34 @@ public function testWhetherValidationCallbackIsOnlyExecutedWhenIsValidIsCalled() $this->assertSame($messages, $validator->getMessages()); } + + public function testWhetherCallbackIsOnlyCalledAgainIfNotCached() + { + $count = 0; + + $validator = new CallbackValidator(function ($value, CallbackValidator $validator) use (&$count) { + $count++; + return true; + }); + + $validator->isValid(true); + $validator->isValid(true); + + $this->assertEquals(1, $count, 'The callback is called again even if the cache is enabled'); + } + + public function testWhetherCallbackIsCalledAgainIfCached() + { + $count = 0; + + $validator = new CallbackValidator(function ($value, CallbackValidator $validator) use (&$count) { + $count++; + return true; + }, false); + + $validator->isValid(true); + $validator->isValid(true); + + $this->assertEquals(2, $count, 'The callback is not called again even if the cache is disabled'); + } }