-
-
Save angelov/f5cd2eb4ea21ed65fc82caa25c55ba8d to your computer and use it in GitHub Desktop.
part 3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace App; | |
use Exception; | |
use ReflectionFunction; | |
use ReflectionParameter; | |
use Symfony\Component\Messenger\Envelope; | |
use Symfony\Component\Messenger\Handler\HandlerDescriptor; | |
use Symfony\Component\Messenger\Handler\HandlersLocatorInterface; | |
class WrappingHandlersLocator implements HandlersLocatorInterface | |
{ | |
private HandlersLocatorInterface $decorated; | |
public function __construct(HandlersLocatorInterface $decorated) | |
{ | |
$this->decorated = $decorated; | |
} | |
public function getHandlers(Envelope $envelope): iterable | |
{ | |
/** @var iterable<int, HandlerDescriptor> $handlerDescriptors */ | |
$handlerDescriptors = $this->decorated->getHandlers($envelope); | |
$message = $envelope->getMessage(); | |
foreach ($handlerDescriptors as $handlerDescriptor) { | |
if ($this->shouldWrapHandler($handlerDescriptor, $message)) { | |
yield $this->wrapHandler($handlerDescriptor, $message); | |
} else { | |
yield $handlerDescriptor; | |
} | |
} | |
} | |
private function shouldWrapHandler(HandlerDescriptor $handlerDescriptor, object $message): bool | |
{ | |
$arguments = $this->getHandlerArguments($handlerDescriptor); | |
return (count($arguments) == 0) | |
|| (count($arguments) > 1) | |
|| (!$arguments[0]->getType()->getName() == get_class($message)); | |
} | |
/** @return array<int, ReflectionParameter> */ | |
private function getHandlerArguments(HandlerDescriptor $handlerDescriptor): array | |
{ | |
$function = new ReflectionFunction($handlerDescriptor->getHandler()); | |
return $function->getParameters(); | |
} | |
private function wrapHandler(HandlerDescriptor $handlerDescriptor, object $message): HandlerDescriptor | |
{ | |
$handlerArguments = $this->getHandlerArguments($handlerDescriptor); | |
$handlerArgumentValues = $this->resolveValuesForHandlerArguments($handlerArguments, $message); | |
return new HandlerDescriptor( | |
fn() => $handlerDescriptor->getHandler()(...$handlerArgumentValues), | |
[ | |
'alias' => $this->generateHandlerAlias($handlerDescriptor) | |
] | |
); | |
} | |
private function generateHandlerAlias(HandlerDescriptor $handlerDescriptor): string | |
{ | |
$function = new ReflectionFunction($handlerDescriptor->getHandler()); | |
return sprintf( | |
"%s::%s", | |
$function->getClosureScopeClass()?->getShortName(), | |
$function->getName() | |
); | |
} | |
/** | |
* @param array<int, ReflectionParameter> $arguments | |
* @return array<int, mixed> | |
*/ | |
private function resolveValuesForHandlerArguments(array $arguments, object $message): array | |
{ | |
return array_map( | |
fn(ReflectionParameter $argument) => $this->resolveValueForHandlerArgument($argument, $message), | |
$arguments | |
); | |
} | |
private function resolveValueForHandlerArgument( | |
ReflectionParameter $argument, | |
object $message | |
): mixed { | |
$attribute = $this->getAttributeForArgument($argument); | |
$messagePropertyName = $attribute?->messageProperty ?? $argument->getName(); | |
if (property_exists($message, $messagePropertyName)) { | |
return $message->{$messagePropertyName}; | |
} | |
if ($argument->isDefaultValueAvailable()) { | |
return $argument->getDefaultValue(); | |
} | |
if ($attribute?->defaultValue) { | |
return $attribute->defaultValue; | |
} | |
throw new Exception(sprintf( | |
"Missing handler argument mapping or default value for the \"%s\" argument of \"%s::%s\".", | |
$argument->getName(), | |
$argument->getDeclaringClass()->getName(), | |
$argument->getDeclaringFunction()->getName() | |
)); | |
} | |
private function getAttributeForArgument(ReflectionParameter $argument): ?ExtractedValue | |
{ | |
$attributes = $argument->getAttributes(ExtractedValue::class); | |
if (!count($attributes)) { | |
return null; | |
} | |
return $attributes[0]->newInstance(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment