mirror of https://github.com/flightphp/core
- FilteredCallable wraps a callable and helps static analyzers to check if after filters are using the callable return type as output type. - FilteredCallable handles after filters with two parameters (deprecated) and one parameter (new required signature)dispatcher-rework
parent
bb6932e92e
commit
2682e3298f
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace flight\core;
|
||||
|
||||
use Closure;
|
||||
use ReflectionFunction;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @template CallableWithoutFilters of Closure
|
||||
* @template Output of mixed
|
||||
*/
|
||||
final class FilteredCallable
|
||||
{
|
||||
/**
|
||||
* @readonly
|
||||
* @var CallableWithoutFilters
|
||||
*/
|
||||
private $closure;
|
||||
|
||||
/** @var (callable(mixed[] &$input): (void|never|false))[] */
|
||||
private array $beforeFilters = [];
|
||||
|
||||
/** @var (callable(mixed &$output): (void|never|false))[] */
|
||||
private array $afterFilters = [];
|
||||
|
||||
/** @param CallableWithoutFilters|callable(): Output $callable */
|
||||
public function __construct(callable $callable)
|
||||
{
|
||||
$this->closure = Closure::fromCallable($callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed ...$input
|
||||
* @return Output
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function __invoke(...$input)
|
||||
{
|
||||
foreach ($this->beforeFilters as $filter) {
|
||||
$filterReturnValue = $filter($input);
|
||||
|
||||
if ($filterReturnValue === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$closure = $this->closure;
|
||||
|
||||
$output = $closure(...$input);
|
||||
|
||||
foreach ($this->afterFilters as $filter) {
|
||||
$filterReturnValue = $filter($output);
|
||||
|
||||
if ($filterReturnValue === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/** @param callable(mixed[] &$input): (void|never|false) $filter */
|
||||
public function pushBeforeFilter(callable $filter): void
|
||||
{
|
||||
if (!in_array($filter, $this->beforeFilters)) {
|
||||
$this->beforeFilters[] = $filter;
|
||||
}
|
||||
}
|
||||
|
||||
/** @param callable(Output &$output): (void|never|false) $filter */
|
||||
public function pushAfterFilter(callable $filter): void
|
||||
{
|
||||
if (!in_array($filter, $this->afterFilters)) {
|
||||
$filterReflectionFunction = new ReflectionFunction($filter);
|
||||
|
||||
if ($filterReflectionFunction->getNumberOfParameters() === 2) {
|
||||
$filter = static function (&$output) use ($filter) {
|
||||
static $input = [];
|
||||
|
||||
return $filter($input, $output);
|
||||
};
|
||||
}
|
||||
|
||||
$this->afterFilters[] = $filter;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue