Skip to content

Commit 9c7e936

Browse files
authored
Merge pull request #44 from enumag/feature/messenger
Add EnvelopeReturnTypeExtension for symfony/messenger
2 parents 649c258 + eb878cf commit 9c7e936

7 files changed

+110
-14
lines changed

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
"phpstan/phpstan-phpunit": "^0.11",
3434
"symfony/framework-bundle": "^3.0 || ^4.0",
3535
"squizlabs/php_codesniffer": "^3.3.2",
36-
"symfony/serializer": "^3|^4"
36+
"symfony/serializer": "^3|^4",
37+
"symfony/messenger": "^4.2"
3738
},
3839
"conflict": {
3940
"symfony/framework-bundle": "<3.0"

extension.neon

+15-10
Original file line numberDiff line numberDiff line change
@@ -12,41 +12,46 @@ services:
1212
class: PHPStan\Symfony\ServiceMapFactory
1313
factory: PHPStan\Symfony\XmlServiceMapFactory(%symfony.container_xml_path%)
1414
-
15-
class: @symfony.serviceMapFactory::create()
15+
factory: @symfony.serviceMapFactory::create()
1616

1717
# ControllerTrait::get()/has() return type
1818
-
19-
class: PHPStan\Type\Symfony\ServiceDynamicReturnTypeExtension(Symfony\Component\DependencyInjection\ContainerInterface, %symfony.constant_hassers%)
19+
factory: PHPStan\Type\Symfony\ServiceDynamicReturnTypeExtension(Symfony\Component\DependencyInjection\ContainerInterface, %symfony.constant_hassers%)
2020
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
2121
-
22-
class: PHPStan\Type\Symfony\ServiceDynamicReturnTypeExtension(Symfony\Bundle\FrameworkBundle\Controller\Controller, %symfony.constant_hassers%)
22+
factory: PHPStan\Type\Symfony\ServiceDynamicReturnTypeExtension(Symfony\Bundle\FrameworkBundle\Controller\Controller, %symfony.constant_hassers%)
2323
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
2424
-
25-
class: PHPStan\Type\Symfony\ServiceDynamicReturnTypeExtension(Symfony\Bundle\FrameworkBundle\Controller\AbstractController, %symfony.constant_hassers%)
25+
factory: PHPStan\Type\Symfony\ServiceDynamicReturnTypeExtension(Symfony\Bundle\FrameworkBundle\Controller\AbstractController, %symfony.constant_hassers%)
2626
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
2727

2828
# ControllerTrait::has() type specification
2929
-
30-
class: PHPStan\Type\Symfony\ServiceTypeSpecifyingExtension(Symfony\Component\DependencyInjection\ContainerInterface)
30+
factory: PHPStan\Type\Symfony\ServiceTypeSpecifyingExtension(Symfony\Component\DependencyInjection\ContainerInterface)
3131
tags: [phpstan.typeSpecifier.methodTypeSpecifyingExtension]
3232
-
33-
class: PHPStan\Type\Symfony\ServiceTypeSpecifyingExtension(Symfony\Bundle\FrameworkBundle\Controller\Controller)
33+
factory: PHPStan\Type\Symfony\ServiceTypeSpecifyingExtension(Symfony\Bundle\FrameworkBundle\Controller\Controller)
3434
tags: [phpstan.typeSpecifier.methodTypeSpecifyingExtension]
3535
-
36-
class: PHPStan\Type\Symfony\ServiceTypeSpecifyingExtension(Symfony\Bundle\FrameworkBundle\Controller\AbstractController)
36+
factory: PHPStan\Type\Symfony\ServiceTypeSpecifyingExtension(Symfony\Bundle\FrameworkBundle\Controller\AbstractController)
3737
tags: [phpstan.typeSpecifier.methodTypeSpecifyingExtension]
3838

3939
# Request::getContent() return type
4040
-
41-
class: PHPStan\Type\Symfony\RequestDynamicReturnTypeExtension
41+
factory: PHPStan\Type\Symfony\RequestDynamicReturnTypeExtension
4242
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
4343

4444
# HeaderBag::get() return type
4545
-
46-
class: PHPStan\Type\Symfony\HeaderBagDynamicReturnTypeExtension
46+
factory: PHPStan\Type\Symfony\HeaderBagDynamicReturnTypeExtension
4747
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
4848

4949
# SerializerInterface::deserialize() return type
5050
-
51-
class: PHPStan\Type\Symfony\SerializerInterfaceDynamicReturnTypeExtension
51+
factory: PHPStan\Type\Symfony\SerializerInterfaceDynamicReturnTypeExtension
52+
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
53+
54+
# Envelope::all() return type
55+
-
56+
factory: PHPStan\Type\Symfony\EnvelopeReturnTypeExtension
5257
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Symfony;
4+
5+
use PhpParser\Node\Expr\MethodCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Reflection\MethodReflection;
8+
use PHPStan\Type\ArrayType;
9+
use PHPStan\Type\Constant\ConstantStringType;
10+
use PHPStan\Type\DynamicMethodReturnTypeExtension;
11+
use PHPStan\Type\MixedType;
12+
use PHPStan\Type\ObjectType;
13+
use PHPStan\Type\Type;
14+
15+
final class EnvelopeReturnTypeExtension implements DynamicMethodReturnTypeExtension
16+
{
17+
18+
public function getClass(): string
19+
{
20+
return 'Symfony\Component\Messenger\Envelope';
21+
}
22+
23+
public function isMethodSupported(MethodReflection $methodReflection): bool
24+
{
25+
return $methodReflection->getName() === 'all';
26+
}
27+
28+
public function getTypeFromMethodCall(
29+
MethodReflection $methodReflection,
30+
MethodCall $methodCall,
31+
Scope $scope
32+
): Type
33+
{
34+
if (count($methodCall->args) === 0) {
35+
return new ArrayType(new MixedType(), new ArrayType(new MixedType(), new ObjectType('Symfony\Component\Messenger\Stamp\StampInterface')));
36+
}
37+
38+
$argType = $scope->getType($methodCall->args[0]->value);
39+
if (!$argType instanceof ConstantStringType) {
40+
return new ArrayType(new MixedType(), new ObjectType('Symfony\Component\Messenger\Stamp\StampInterface'));
41+
}
42+
43+
return new ArrayType(new MixedType(), new ObjectType($argType->getValue()));
44+
}
45+
46+
}

tests/Symfony/NeonTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public function testExtensionNeon(): void
4040
], $container->getParameters());
4141

4242
self::assertCount(2, $container->findByTag('phpstan.rules.rule'));
43-
self::assertCount(6, $container->findByTag('phpstan.broker.dynamicMethodReturnTypeExtension'));
43+
self::assertCount(7, $container->findByTag('phpstan.broker.dynamicMethodReturnTypeExtension'));
4444
self::assertCount(3, $container->findByTag('phpstan.typeSpecifier.methodTypeSpecifyingExtension'));
4545
self::assertInstanceOf(ServiceMap::class, $container->getByType(ServiceMap::class));
4646
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Symfony;
4+
5+
use Iterator;
6+
use Symfony\Component\Messenger\Stamp\ReceivedStamp;
7+
use Symfony\Component\Messenger\Stamp\StampInterface;
8+
9+
final class EnvelopeReturnTypeExtensionTest extends ExtensionTestCase
10+
{
11+
12+
/**
13+
* @dataProvider getProvider
14+
*/
15+
public function testAll(string $expression, string $type): void
16+
{
17+
$this->processFile(
18+
__DIR__ . '/envelope_all.php',
19+
$expression,
20+
$type,
21+
new EnvelopeReturnTypeExtension()
22+
);
23+
}
24+
25+
public function getProvider(): Iterator
26+
{
27+
yield ['$test1', 'array<' . ReceivedStamp::class . '>'];
28+
yield ['$test2', 'array<' . StampInterface::class . '>'];
29+
yield ['$test3', 'array<array<' . StampInterface::class . '>>'];
30+
}
31+
32+
}

tests/Type/Symfony/ExtensionTestCase.php

+5-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use PHPStan\Broker\AnonymousClassNameHelper;
1111
use PHPStan\Cache\Cache;
1212
use PHPStan\File\FileHelper;
13-
use PHPStan\Node\InClassMethodNode;
13+
use PHPStan\Node\VirtualNode;
1414
use PHPStan\PhpDoc\PhpDocStringResolver;
1515
use PHPStan\PhpDoc\TypeNodeResolver;
1616
use PHPStan\Testing\TestCase;
@@ -61,7 +61,10 @@ protected function processFile(
6161
$parser->parseFile($file),
6262
$this->createScopeFactory($broker, $typeSpecifier)->create(ScopeContext::create($file)),
6363
function (Node $node, Scope $scope) use ($expression, $type, &$run): void {
64-
if ((new Standard())->prettyPrint([$node instanceof InClassMethodNode ? $node->getOriginalNode() : $node]) !== 'die') {
64+
if ($node instanceof VirtualNode) {
65+
return;
66+
}
67+
if ((new Standard())->prettyPrint([$node]) !== 'die') {
6568
return;
6669
}
6770
/** @var \PhpParser\Node\Stmt\Expression $expNode */

tests/Type/Symfony/envelope_all.php

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php declare(strict_types = 1);
2+
3+
$envelope = new \Symfony\Component\Messenger\Envelope(new stdClass());
4+
5+
$test1 = $envelope->all(\Symfony\Component\Messenger\Stamp\ReceivedStamp::class);
6+
$test2 = $envelope->all(random_bytes(1));
7+
$test3 = $envelope->all();
8+
9+
die;

0 commit comments

Comments
 (0)