Skip to content

Commit

Permalink
CallbackValidator: Cache callback results by default
Browse files Browse the repository at this point in the history
Since Icinga/ipl-html#97 form elements don't cache
the validation results anymore. This isn't a problem for most validators.
Though, custom callbacks written before this change were written with the
cache in mind. This change allows to control this when creating the validator.
It caches by default for historical reasons. (To not break compatibility)
  • Loading branch information
nilmerg committed Jan 16, 2023
1 parent 63e4a32 commit e0381d0
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 2 deletions.
21 changes: 19 additions & 2 deletions src/CallbackValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
30 changes: 30 additions & 0 deletions tests/CallbackValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}
}

0 comments on commit e0381d0

Please sign in to comment.