|
|
|
@ -35,6 +35,25 @@ class Dispatcher
|
|
|
|
|
*/
|
|
|
|
|
protected array $filters = [];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This is a container for the dependency injection.
|
|
|
|
|
*
|
|
|
|
|
* @var callable|object|null
|
|
|
|
|
*/
|
|
|
|
|
protected $container_handler = null;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets the dependency injection container handler.
|
|
|
|
|
*
|
|
|
|
|
* @param callable|object $container_handler Dependency injection container
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function setContainerHandler($container_handler): void
|
|
|
|
|
{
|
|
|
|
|
$this->container_handler = $container_handler;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Dispatches an event.
|
|
|
|
|
*
|
|
|
|
@ -80,10 +99,10 @@ class Dispatcher
|
|
|
|
|
$requestedMethod = $this->get($eventName);
|
|
|
|
|
|
|
|
|
|
if ($requestedMethod === null) {
|
|
|
|
|
throw new Exception("Event '$eventName' isn't found.");
|
|
|
|
|
throw new Exception("Event '{$eventName}' isn't found.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $requestedMethod(...$params);
|
|
|
|
|
return $this->execute($requestedMethod, $params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -194,7 +213,7 @@ class Dispatcher
|
|
|
|
|
*
|
|
|
|
|
* @throws Exception If an event throws an `Exception` or if `$filters` contains an invalid filter.
|
|
|
|
|
*/
|
|
|
|
|
public static function filter(array $filters, array &$params, &$output): void
|
|
|
|
|
public function filter(array $filters, array &$params, &$output): void
|
|
|
|
|
{
|
|
|
|
|
foreach ($filters as $key => $callback) {
|
|
|
|
|
if (!is_callable($callback)) {
|
|
|
|
@ -219,22 +238,39 @@ class Dispatcher
|
|
|
|
|
* @return mixed Function results
|
|
|
|
|
* @throws Exception If `$callback` also throws an `Exception`.
|
|
|
|
|
*/
|
|
|
|
|
public static function execute($callback, array &$params = [])
|
|
|
|
|
public function execute($callback, array &$params = [])
|
|
|
|
|
{
|
|
|
|
|
$isInvalidFunctionName = (
|
|
|
|
|
is_string($callback)
|
|
|
|
|
&& !function_exists($callback)
|
|
|
|
|
);
|
|
|
|
|
if (is_string($callback) === true && (strpos($callback, '->') !== false || strpos($callback, '::') !== false)) {
|
|
|
|
|
$callback = $this->parseStringClassAndMethod($callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($isInvalidFunctionName) {
|
|
|
|
|
throw new InvalidArgumentException('Invalid callback specified.');
|
|
|
|
|
$this->handleInvalidCallbackType($callback);
|
|
|
|
|
|
|
|
|
|
if (is_array($callback) === true) {
|
|
|
|
|
return $this->invokeMethod($callback, $params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_array($callback)) {
|
|
|
|
|
return self::invokeMethod($callback, $params);
|
|
|
|
|
return $this->callFunction($callback, $params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Parses a string into a class and method.
|
|
|
|
|
*
|
|
|
|
|
* @param string $classAndMethod Class and method
|
|
|
|
|
*
|
|
|
|
|
* @return array{class-string|object, string} Class and method
|
|
|
|
|
*/
|
|
|
|
|
public function parseStringClassAndMethod(string $classAndMethod): array
|
|
|
|
|
{
|
|
|
|
|
$class_parts = explode('->', $classAndMethod);
|
|
|
|
|
if (count($class_parts) === 1) {
|
|
|
|
|
$class_parts = explode('::', $class_parts[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return self::callFunction($callback, $params);
|
|
|
|
|
$class = $class_parts[0];
|
|
|
|
|
$method = $class_parts[1];
|
|
|
|
|
|
|
|
|
|
return [ $class, $method ];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -244,10 +280,11 @@ class Dispatcher
|
|
|
|
|
* @param array<int, mixed> &$params Function parameters
|
|
|
|
|
*
|
|
|
|
|
* @return mixed Function results
|
|
|
|
|
* @deprecated 3.7.0 Use invokeCallable instead
|
|
|
|
|
*/
|
|
|
|
|
public static function callFunction(callable $func, array &$params = [])
|
|
|
|
|
public function callFunction(callable $func, array &$params = [])
|
|
|
|
|
{
|
|
|
|
|
return call_user_func_array($func, $params);
|
|
|
|
|
return $this->invokeCallable($func, $params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -257,12 +294,48 @@ class Dispatcher
|
|
|
|
|
* @param array<int, mixed> &$params Class method parameters
|
|
|
|
|
*
|
|
|
|
|
* @return mixed Function results
|
|
|
|
|
* @throws TypeError For unexistent class name.
|
|
|
|
|
* @throws TypeError For nonexistent class name.
|
|
|
|
|
* @deprecated 3.7.0 Use invokeCallable instead
|
|
|
|
|
*/
|
|
|
|
|
public function invokeMethod(array $func, array &$params = [])
|
|
|
|
|
{
|
|
|
|
|
return $this->invokeCallable($func, $params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Invokes a callable (anonymous function or Class->method).
|
|
|
|
|
*
|
|
|
|
|
* @param array{class-string|object, string}|Callable $func Class method
|
|
|
|
|
* @param array<int, mixed> &$params Class method parameters
|
|
|
|
|
*
|
|
|
|
|
* @return mixed Function results
|
|
|
|
|
* @throws TypeError For nonexistent class name.
|
|
|
|
|
* @throws InvalidArgumentException If the constructor requires parameters
|
|
|
|
|
*/
|
|
|
|
|
public static function invokeMethod(array $func, array &$params = [])
|
|
|
|
|
public function invokeCallable($func, array &$params = [])
|
|
|
|
|
{
|
|
|
|
|
// If this is a directly callable function, call it
|
|
|
|
|
if (is_array($func) === false) {
|
|
|
|
|
return call_user_func_array($func, $params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[$class, $method] = $func;
|
|
|
|
|
|
|
|
|
|
// Only execute this if it's not a Flight class
|
|
|
|
|
if (
|
|
|
|
|
$this->container_handler !== null &&
|
|
|
|
|
(
|
|
|
|
|
(
|
|
|
|
|
is_object($class) === true &&
|
|
|
|
|
strpos(get_class($class), 'flight\\') === false
|
|
|
|
|
) ||
|
|
|
|
|
is_string($class) === true
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
$container_handler = $this->container_handler;
|
|
|
|
|
$class = $this->resolveContainerClass($container_handler, $class, $params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_string($class) && class_exists($class)) {
|
|
|
|
|
$constructor = (new ReflectionClass($class))->getConstructor();
|
|
|
|
|
$constructorParamsNumber = 0;
|
|
|
|
@ -284,7 +357,56 @@ class Dispatcher
|
|
|
|
|
$class = new $class();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return call_user_func_array([$class, $method], $params);
|
|
|
|
|
return call_user_func_array([ $class, $method ], $params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handles invalid callback types.
|
|
|
|
|
*
|
|
|
|
|
* @param callable-string|(Closure(): mixed)|array{class-string|object, string} $callback
|
|
|
|
|
* Callback function
|
|
|
|
|
*
|
|
|
|
|
* @throws InvalidArgumentException If `$callback` is an invalid type
|
|
|
|
|
*/
|
|
|
|
|
protected function handleInvalidCallbackType($callback): void
|
|
|
|
|
{
|
|
|
|
|
$isInvalidFunctionName = (
|
|
|
|
|
is_string($callback)
|
|
|
|
|
&& !function_exists($callback)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if ($isInvalidFunctionName) {
|
|
|
|
|
throw new InvalidArgumentException('Invalid callback specified.');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Resolves the container class.
|
|
|
|
|
*
|
|
|
|
|
* @param callable|object $container_handler Dependency injection container
|
|
|
|
|
* @param class-string $class Class name
|
|
|
|
|
* @param array<int, mixed> &$params Class constructor parameters
|
|
|
|
|
*
|
|
|
|
|
* @return object Class object
|
|
|
|
|
*/
|
|
|
|
|
protected function resolveContainerClass($container_handler, $class, array &$params)
|
|
|
|
|
{
|
|
|
|
|
$class_object = null;
|
|
|
|
|
|
|
|
|
|
// PSR-11
|
|
|
|
|
if (
|
|
|
|
|
is_object($container_handler) === true &&
|
|
|
|
|
method_exists($container_handler, 'has') === true &&
|
|
|
|
|
$container_handler->has($class)
|
|
|
|
|
) {
|
|
|
|
|
$class_object = call_user_func([$container_handler, 'get'], $class);
|
|
|
|
|
|
|
|
|
|
// Just a callable where you configure the behavior (Dice, PHP-DI, etc.)
|
|
|
|
|
} elseif (is_callable($container_handler) === true) {
|
|
|
|
|
$class_object = call_user_func($container_handler, $class, $params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $class_object;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|