Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 31
Introduce handler resolver#327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base:master
Are you sure you want to change the base?
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| <?php | ||
| declare(strict_types=1); | ||
| namespace Yiisoft\Queue\Message\Handler; | ||
| use Yiisoft\Queue\Message\MessageInterface; | ||
| /** | ||
| * Handles a message by invoking the given callable. | ||
| * | ||
| * @internal | ||
| */ | ||
| final class CallableHandler implements HandlerInterface | ||
| { | ||
| /** | ||
| * @param callable $handler Callable invoked to handle a message. | ||
| * | ||
| * @psalm-param callable(MessageInterface): void $handler | ||
| */ | ||
| public function __construct( | ||
| private readonly mixed $handler, | ||
| ) {} | ||
| public function handle(MessageInterface $message): void | ||
| { | ||
| ($this->handler)($message); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| <?php | ||
| declare(strict_types=1); | ||
| namespace Yiisoft\Queue\Message\Handler; | ||
| use Yiisoft\Queue\Message\MessageInterface; | ||
| /** | ||
| * Handles a message. | ||
| */ | ||
| interface HandlerInterface | ||
| { | ||
| /** | ||
| * Handle the given message. | ||
| */ | ||
| public function handle(MessageInterface $message): void; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| <?php | ||
| declare(strict_types=1); | ||
| namespace Yiisoft\Queue\Message\Handler; | ||
| use LogicException; | ||
| use Throwable; | ||
| use function sprintf; | ||
| /** | ||
| * Thrown when a handler for the given message type is not found. | ||
| */ | ||
| final class HandlerNotFoundException extends LogicException | ||
| { | ||
| public function __construct(string $messageType, int $code = 0, ?Throwable $previous = null) | ||
| { | ||
| parent::__construct( | ||
| sprintf('Queue handler for message type "%s" does not exist.', $messageType), | ||
| $code, | ||
| $previous, | ||
| ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| <?php | ||
| declare(strict_types=1); | ||
| namespace Yiisoft\Queue\Message\Handler; | ||
| use LogicException; | ||
| use Psr\Container\ContainerExceptionInterface; | ||
| use Psr\Container\ContainerInterface; | ||
| use Yiisoft\Injector\Injector; | ||
| use Yiisoft\Queue\Message\MessageInterface; | ||
| use Yiisoft\Queue\Middleware\CallableFactory; | ||
| use Yiisoft\Queue\Middleware\InvalidCallableConfigurationException; | ||
| use function array_key_exists; | ||
| use function is_callable; | ||
| use function is_string; | ||
| use function sprintf; | ||
| /** | ||
| * Resolves message handlers from configuration, a DI container, or a callable factory. | ||
| */ | ||
| final class HandlerResolver | ||
| { | ||
| /** | ||
| * @var HandlerInterface[] Cache of resolved handlers. | ||
| * @psalm-var array<non-empty-string, HandlerInterface> | ||
| */ | ||
| private array $cache = []; | ||
| private readonly Injector $injector; | ||
| private readonly CallableFactory $callableFactory; | ||
| /** | ||
| * @param (array|callable|HandlerInterface|string)[] $handlers Handler definitions indexed by message type. | ||
| * @param ContainerInterface $container Container used to resolve handlers. | ||
| * @param ContainerInterface|null $callableDependencyContainer Container used to resolve callable handler | ||
| * dependencies. If not set, the main container is used. | ||
| * | ||
| * @psalm-param array<non-empty-string, array|callable|HandlerInterface|string> $handlers | ||
| */ | ||
| public function __construct( | ||
| private readonly array $handlers, | ||
| private readonly ContainerInterface $container, | ||
| ?ContainerInterface $callableDependencyContainer = null, | ||
| ) { | ||
| $this->injector = new Injector($callableDependencyContainer ?? $this->container); | ||
| $this->callableFactory = new CallableFactory($this->container); | ||
| } | ||
| /** | ||
| * Get a handler for the given message type. | ||
| * | ||
| * @param string $messageType Message type. | ||
| * | ||
| * @throws HandlerNotFoundException If no handler exists for the message type. | ||
| * @throws InvalidHandlerConfigurationException If the handler definition is configured incorrectly. | ||
| * @throws ContainerExceptionInterface Error while retrieving the entry from container. | ||
| */ | ||
| public function resolve(string $messageType): HandlerInterface | ||
| { | ||
| if ($messageType === '') { | ||
| throw new LogicException('Message type cannot be empty.'); | ||
| } | ||
| if (array_key_exists($messageType, $this->cache)) { | ||
| return $this->cache[$messageType]; | ||
| } | ||
| $this->cache[$messageType] = $this->internalResolve($messageType); | ||
| return $this->cache[$messageType]; | ||
| } | ||
| /** | ||
| * @throws HandlerNotFoundException | ||
| * @throws InvalidHandlerConfigurationException | ||
| * @throws ContainerExceptionInterface | ||
| */ | ||
| private function internalResolve(string $messageType): HandlerInterface | ||
| { | ||
| $definition = $this->handlers[$messageType] ?? $messageType; | ||
| if ($definition instanceof HandlerInterface) { | ||
| return $definition; | ||
| } | ||
| if (is_string($definition)) { | ||
| return $this->getHandlerFromContainer($messageType, $definition); | ||
| } | ||
| return $this->createCallableHandler($messageType, $definition); | ||
| } | ||
| /** | ||
| * @throws HandlerNotFoundException | ||
| * @throws InvalidHandlerConfigurationException | ||
| * @throws ContainerExceptionInterface | ||
| */ | ||
| private function getHandlerFromContainer(string $messageType, string $id): HandlerInterface | ||
| { | ||
| if (!$this->container->has($id)) { | ||
| throw new HandlerNotFoundException($messageType); | ||
| } | ||
| $handler = $this->container->get($id); | ||
| if ($handler instanceof HandlerInterface) { | ||
| return $handler; | ||
| } | ||
| if (is_callable($handler)) { | ||
| return $this->createCallableHandler($messageType, $handler); | ||
| } | ||
| throw new InvalidHandlerConfigurationException( | ||
| $messageType, | ||
| sprintf( | ||
| 'Resolved from container handler should be an instance of "%s" or callable, got "%s".', | ||
| HandlerInterface::class, | ||
| get_debug_type($handler), | ||
| ), | ||
| ); | ||
| } | ||
| /** | ||
| * @throws InvalidHandlerConfigurationException | ||
| * @throws ContainerExceptionInterface | ||
| */ | ||
| private function createCallableHandler(string $messageType, mixed $definition): CallableHandler | ||
| { | ||
| try { | ||
| $callable = $this->callableFactory->create($definition); | ||
| } catch (InvalidCallableConfigurationException $exception) { | ||
| throw new InvalidHandlerConfigurationException($messageType, $exception->getMessage(), $exception); | ||
| } | ||
| $callable = function (MessageInterface $message) use ($callable): void { | ||
| $this->injector->invoke($callable, [$message]); | ||
| }; | ||
| return new CallableHandler($callable); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| <?php | ||
| declare(strict_types=1); | ||
| namespace Yiisoft\Queue\Message\Handler; | ||
| use LogicException; | ||
| use Throwable; | ||
| use function sprintf; | ||
| /** | ||
| * Thrown when a handler for the given message type is configured incorrectly. | ||
| */ | ||
| final class InvalidHandlerConfigurationException extends LogicException | ||
| { | ||
| public function __construct(string $messageType, ?string $additionalMessage = null, ?Throwable $previous = null) | ||
| { | ||
| $message = sprintf('Queue handler for message type "%s" is configured incorrectly.', $messageType); | ||
| if ($additionalMessage !== null) { | ||
| $message .= ' ' . $additionalMessage; | ||
| } | ||
| parent::__construct($message, 0, $previous); | ||
| } | ||
| } |
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should use injector as it was previously.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed