Skip to content

Commit 224c478

Browse files
Bartłomiej Nowakbnowak
Bartłomiej Nowak
authored andcommitted
use ExpressionTypeResolverExtension instead of DynamicMethodReturnTypeExtension
1 parent 0c8cb34 commit 224c478

File tree

3 files changed

+97
-86
lines changed

3 files changed

+97
-86
lines changed

extension.neon

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,8 @@ services:
212212

213213
# Messenger HandleTrait::handle() return type
214214
-
215-
factory: PHPStan\Type\Symfony\MessengerHandleTraitDynamicReturnTypeExtension
216-
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
215+
class: PHPStan\Type\Symfony\MessengerHandleTraitReturnTypeExtension
216+
tags: [phpstan.broker.expressionTypeResolverExtension]
217217

218218
# InputInterface::getArgument() return type
219219
-

src/Type/Symfony/MessengerHandleTraitDynamicReturnTypeExtension.php

Lines changed: 0 additions & 84 deletions
This file was deleted.
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Symfony;
4+
5+
use PhpParser\Node\Expr;
6+
use PhpParser\Node\Expr\MethodCall;
7+
use PhpParser\Node\Identifier;
8+
use PHPStan\Analyser\Scope;
9+
use PHPStan\Symfony\MessageMap;
10+
use PHPStan\Symfony\MessageMapFactory;
11+
use PHPStan\Type\ExpressionTypeResolverExtension;
12+
use PHPStan\Type\Type;
13+
use ReflectionException;
14+
use function count;
15+
use function is_null;
16+
17+
final class MessengerHandleTraitReturnTypeExtension implements ExpressionTypeResolverExtension
18+
{
19+
20+
private const TRAIT_NAME = 'Symfony\Component\Messenger\HandleTrait';
21+
private const TRAIT_METHOD_NAME = 'handle';
22+
23+
/** @var MessageMapFactory */
24+
private $messageMapFactory;
25+
26+
/** @var MessageMap|null */
27+
private $messageMap;
28+
29+
public function __construct(MessageMapFactory $symfonyMessageMapFactory)
30+
{
31+
$this->messageMapFactory = $symfonyMessageMapFactory;
32+
}
33+
34+
public function getType(Expr $expr, Scope $scope): ?Type
35+
{
36+
// todo handle different cases:
37+
// - [X] regular message classes
38+
// - [ ] interfaces for message classes
39+
// - [ ] many handlers for one message? it would throw exception in HandleTrait anyway
40+
// - [x] many messages for one handler
41+
// - [partially] cover MessageSubscriberInterface
42+
// - [partially] custom method names for handlers (different than default "__invoke" magic method)
43+
// - [] read SF doc to determine any other cases to covers
44+
45+
if ($this->isSupported($expr, $scope)) {
46+
$arg = $expr->getArgs()[0]->value;
47+
$argClassNames = $scope->getType($arg)->getObjectClassNames();
48+
49+
// todo filter out not handled cases on map creation?
50+
if (count($argClassNames) === 1) {
51+
$messageMap = $this->getMessageMap();
52+
$message = $messageMap->getMessageForClass($argClassNames[0]);
53+
54+
if (!is_null($message) && $message->countReturnTypes() === 1) {
55+
return $message->getReturnTypes()[0];
56+
}
57+
}
58+
}
59+
60+
return null;
61+
}
62+
63+
private function getMessageMap(): MessageMap
64+
{
65+
if (is_null($this->messageMap)) {
66+
$this->messageMap = $this->messageMapFactory->create();
67+
}
68+
69+
return $this->messageMap;
70+
}
71+
72+
/**
73+
* @phpstan-assert-if-true MethodCall $expr
74+
*/
75+
private function isSupported(Expr $expr, Scope $scope): bool
76+
{
77+
if (!($expr instanceof MethodCall) || !($expr->name instanceof Identifier) || $expr->name->name !== self::TRAIT_METHOD_NAME) {
78+
return false;
79+
}
80+
81+
if (!$scope->isInClass()) {
82+
return false;
83+
}
84+
85+
try {
86+
$methodReflection = $scope->getClassReflection()->getNativeReflection()->getMethod(self::TRAIT_METHOD_NAME);
87+
$declaringClassReflection = $methodReflection->getBetterReflection()->getDeclaringClass();
88+
89+
return $declaringClassReflection->getName() === self::TRAIT_NAME;
90+
} catch (ReflectionException $e) {
91+
return false;
92+
}
93+
}
94+
95+
}

0 commit comments

Comments
 (0)