From e3790e0f2fc98ef689b7f52945654a36eb58a4aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Nowak?= Date: Wed, 14 Aug 2024 07:52:15 +0200 Subject: [PATCH] phpstan fix --- src/Symfony/Message.php | 5 +- src/Symfony/MessageMap.php | 7 --- src/Symfony/MessageMapFactory.php | 53 +++++++------------ src/Symfony/Service.php | 3 +- src/Symfony/ServiceDefinition.php | 1 + src/Symfony/ServiceTag.php | 3 +- src/Symfony/ServiceTagDefinition.php | 1 + ...rHandleTraitDynamicReturnTypeExtension.php | 23 ++++---- 8 files changed, 39 insertions(+), 57 deletions(-) diff --git a/src/Symfony/Message.php b/src/Symfony/Message.php index dac5b23c..8a633a59 100644 --- a/src/Symfony/Message.php +++ b/src/Symfony/Message.php @@ -2,6 +2,7 @@ namespace PHPStan\Symfony; +use PHPStan\Type\Type; use function count; final class Message @@ -10,9 +11,10 @@ final class Message /** @var string */ private $class; - /** @var array */ + /** @var Type[] */ private $returnTypes; + /** @param Type[] $returnTypes */ public function __construct(string $class, array $returnTypes) { $this->class = $class; @@ -24,6 +26,7 @@ public function getClass(): string return $this->class; } + /** @return Type[] */ public function getReturnTypes(): array { return $this->returnTypes; diff --git a/src/Symfony/MessageMap.php b/src/Symfony/MessageMap.php index a96f3521..3ef6fcef 100644 --- a/src/Symfony/MessageMap.php +++ b/src/Symfony/MessageMap.php @@ -2,8 +2,6 @@ namespace PHPStan\Symfony; -use function array_key_exists; - final class MessageMap { @@ -25,9 +23,4 @@ public function getMessageForClass(string $class): ?Message return $this->messages[$class] ?? null; } - public function hasMessageForClass(string $class): bool - { - return array_key_exists($class, $this->messages); - } - } diff --git a/src/Symfony/MessageMapFactory.php b/src/Symfony/MessageMapFactory.php index 896f4674..ce4e23bb 100644 --- a/src/Symfony/MessageMapFactory.php +++ b/src/Symfony/MessageMapFactory.php @@ -5,8 +5,6 @@ use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Reflection\ReflectionProvider; -use PHPStan\Type\ObjectType; -use PHPStan\Type\UnionType; use RuntimeException; use Symfony\Component\Messenger\Handler\MessageSubscriberInterface; use function count; @@ -18,6 +16,8 @@ final class MessageMapFactory { + private const DEFAULT_HANDLER_METHOD = '__invoke'; + /** @var ReflectionProvider */ private $reflectionProvider; @@ -53,19 +53,13 @@ public function create(): MessageMap $reflectionClass = $this->reflectionProvider->getClass($serviceClass); if (isset($tagAttributes['handles'])) { - $handles = isset($tag['method']) ? [$tag['handles'] => $tag['method']] : [$tag['handles']]; + // todo cover by test case + $handles = [$tagAttributes['handles'] => ['method' => $tagAttributes['method'] ?? self::DEFAULT_HANDLER_METHOD]]; } else { $handles = $this->guessHandledMessages($reflectionClass); } foreach ($handles as $messageClassName => $options) { - if (is_int($messageClassName) && is_string($options)) { - $messageClassName = $options; - $options = []; - } - - $options['method'] = $options['method'] ?? '__invoke'; - $methodReflection = $reflectionClass->getNativeMethod($options['method']); $variant = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants()); @@ -82,15 +76,24 @@ public function create(): MessageMap return new MessageMap($messages); } + /** @return array> */ private function guessHandledMessages(ClassReflection $reflectionClass): iterable { if ($reflectionClass->implementsInterface(MessageSubscriberInterface::class)) { // todo handle different return formats - return $reflectionClass->getName()::getHandledMessages(); + foreach ($reflectionClass->getName()::getHandledMessages() as $index => $value) { + if (is_int($index) && is_string($value)) { + yield $value => ['method' => self::DEFAULT_HANDLER_METHOD]; + } else { + yield $index => $value; + } + } + + return; } // todo handle if doesn't exists - $methodReflection = $reflectionClass->getNativeMethod('__invoke'); + $methodReflection = $reflectionClass->getNativeMethod(self::DEFAULT_HANDLER_METHOD); $variant = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants()); $parameters = $variant->getParameters(); @@ -102,30 +105,10 @@ private function guessHandledMessages(ClassReflection $reflectionClass): iterabl $type = $parameters[0]->getType(); - if ($type instanceof UnionType) { - $types = []; - foreach ($type->getTypes() as $type) { - if (!$type instanceof ObjectType) { - // todo handle error - throw new RuntimeException('invalid handler'); - } - - $types[] = $type->getClassName(); - } - - if ($types) { - return $types; - } - - // todo handle error - throw new RuntimeException('invalid handler'); + // todo many class names? + foreach ($type->getObjectClassNames() as $className) { + yield $className => ['method' => self::DEFAULT_HANDLER_METHOD]; } - - if (!$type instanceof ObjectType) { - throw new RuntimeException('invalid handler'); - } - - return [$type->getClassName()]; } } diff --git a/src/Symfony/Service.php b/src/Symfony/Service.php index 09152d58..1cc465ac 100644 --- a/src/Symfony/Service.php +++ b/src/Symfony/Service.php @@ -20,9 +20,10 @@ final class Service implements ServiceDefinition /** @var string|null */ private $alias; - /** @var array */ + /** @var ServiceTag[] */ private $tags; + /** @param ServiceTag[] $tags */ public function __construct( string $id, ?string $class, diff --git a/src/Symfony/ServiceDefinition.php b/src/Symfony/ServiceDefinition.php index c943e2a8..b3785d7f 100644 --- a/src/Symfony/ServiceDefinition.php +++ b/src/Symfony/ServiceDefinition.php @@ -15,6 +15,7 @@ public function isSynthetic(): bool; public function getAlias(): ?string; + /** @return ServiceTag[] */ public function getTags(): array; } diff --git a/src/Symfony/ServiceTag.php b/src/Symfony/ServiceTag.php index c02be7c5..a8437fd1 100644 --- a/src/Symfony/ServiceTag.php +++ b/src/Symfony/ServiceTag.php @@ -8,9 +8,10 @@ final class ServiceTag implements ServiceTagDefinition /** @var string */ private $name; - /** @var array */ + /** @var array */ private $attributes; + /** @param array $attributes */ public function __construct(string $name, array $attributes = []) { $this->name = $name; diff --git a/src/Symfony/ServiceTagDefinition.php b/src/Symfony/ServiceTagDefinition.php index 19bd84a3..b0f66d9c 100644 --- a/src/Symfony/ServiceTagDefinition.php +++ b/src/Symfony/ServiceTagDefinition.php @@ -7,6 +7,7 @@ interface ServiceTagDefinition public function getName(): string; + /** @return array */ public function getAttributes(): array; } diff --git a/src/Type/Symfony/MessengerHandleTraitDynamicReturnTypeExtension.php b/src/Type/Symfony/MessengerHandleTraitDynamicReturnTypeExtension.php index a0f06a5a..43be1295 100644 --- a/src/Type/Symfony/MessengerHandleTraitDynamicReturnTypeExtension.php +++ b/src/Type/Symfony/MessengerHandleTraitDynamicReturnTypeExtension.php @@ -9,8 +9,9 @@ use PHPStan\Symfony\MessageMap; use PHPStan\Symfony\MessageMapFactory; use PHPStan\Type\DynamicMethodReturnTypeExtension; -use PHPStan\Type\ObjectType; use PHPStan\Type\Type; +use function count; +use function is_null; final class MessengerHandleTraitDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension { @@ -18,7 +19,7 @@ final class MessengerHandleTraitDynamicReturnTypeExtension implements DynamicMet /** @var MessageMapFactory */ private $messageMapFactory; - /** @var MessageMap */ + /** @var MessageMap|null */ private $messageMap; public function __construct(MessageMapFactory $symfonyMessageMapFactory) @@ -34,8 +35,7 @@ public function getClass(): string // todo or make it configurable with passing concrete classes names to extension config // todo or use reflection somehow to get all classes that use HandleTrait and configure it dynamically - // todo temporarily hardcoded test class here - return HandleTraitClass::class; + return HandleTraitClass::class; // @phpstan-ignore-line todo temporarily hardcoded test class here } public function isMethodSupported(MethodReflection $methodReflection): bool @@ -56,16 +56,15 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method // - [] read SF doc to determine any other cases to covers $arg = $methodCall->getArgs()[0]->value; - $argType = $scope->getType($arg); + $argClassNames = $scope->getType($arg)->getObjectClassNames(); - if ($argType instanceof ObjectType) { + // todo filter out not handled cases on map creation? + if (count($argClassNames) === 1) { $messageMap = $this->getMessageMap(); - if ($messageMap->hasMessageForClass($argType->getClassName())) { - $message = $messageMap->getMessageForClass($argType->getClassName()); + $message = $messageMap->getMessageForClass($argClassNames[0]); - if ($message->countReturnTypes() === 1) { - return $message->getReturnTypes()[0]; - } + if (!is_null($message) && $message->countReturnTypes() === 1) { + return $message->getReturnTypes()[0]; } } @@ -74,7 +73,7 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method private function getMessageMap(): MessageMap { - if (!$this->messageMap) { + if (is_null($this->messageMap)) { $this->messageMap = $this->messageMapFactory->create(); }