Skip to content

Commit 11221af

Browse files
authored
Add dynamic return type to ResponseHeaderBag::getCookies
1 parent 784e7a0 commit 11221af

File tree

4 files changed

+83
-0
lines changed

4 files changed

+83
-0
lines changed

extension.neon

+5
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,8 @@ services:
273273
-
274274
factory: PHPStan\Type\Symfony\CommandGetHelperDynamicReturnTypeExtension
275275
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
276+
277+
# ResponseHeaderBag::getCookies() return type
278+
-
279+
factory: PHPStan\Type\Symfony\ResponseHeaderBagDynamicReturnTypeExtension
280+
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Symfony;
4+
5+
use PhpParser\Node\Expr\ClassConstFetch;
6+
use PhpParser\Node\Expr\MethodCall;
7+
use PhpParser\Node\Identifier;
8+
use PhpParser\Node\Name;
9+
use PHPStan\Analyser\Scope;
10+
use PHPStan\Reflection\MethodReflection;
11+
use PHPStan\Type\ArrayType;
12+
use PHPStan\Type\DynamicMethodReturnTypeExtension;
13+
use PHPStan\Type\IntegerType;
14+
use PHPStan\Type\ObjectType;
15+
use PHPStan\Type\StringType;
16+
use PHPStan\Type\Type;
17+
use Symfony\Component\HttpFoundation\Cookie;
18+
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
19+
20+
final class ResponseHeaderBagDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
21+
{
22+
23+
public function getClass(): string
24+
{
25+
return ResponseHeaderBag::class;
26+
}
27+
28+
public function isMethodSupported(MethodReflection $methodReflection): bool
29+
{
30+
return $methodReflection->getName() === 'getCookies';
31+
}
32+
33+
public function getTypeFromMethodCall(
34+
MethodReflection $methodReflection,
35+
MethodCall $methodCall,
36+
Scope $scope
37+
): Type
38+
{
39+
if (isset($methodCall->getArgs()[0])) {
40+
$node = $methodCall->getArgs()[0]->value;
41+
42+
if (
43+
$node instanceof ClassConstFetch &&
44+
$node->class instanceof Name &&
45+
$node->name instanceof Identifier &&
46+
$node->class->toString() === ResponseHeaderBag::class &&
47+
$node->name->name === 'COOKIES_ARRAY'
48+
) {
49+
return new ArrayType(
50+
new StringType(),
51+
new ArrayType(
52+
new StringType(),
53+
new ArrayType(
54+
new StringType(),
55+
new ObjectType(Cookie::class)
56+
)
57+
)
58+
);
59+
}
60+
}
61+
62+
return new ArrayType(new IntegerType(), new ObjectType(Cookie::class));
63+
}
64+
65+
}

tests/Type/Symfony/ExtensionTest.php

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public function dataFileAsserts(): iterable
1414
{
1515
yield from $this->gatherAssertTypes(__DIR__ . '/data/envelope_all.php');
1616
yield from $this->gatherAssertTypes(__DIR__ . '/data/header_bag_get.php');
17+
yield from $this->gatherAssertTypes(__DIR__ . '/data/response_header_bag_get_cookies.php');
1718

1819
if (class_exists('Symfony\Component\HttpFoundation\InputBag')) {
1920
yield from $this->gatherAssertTypes(__DIR__ . '/data/input_bag.php');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php declare(strict_types = 1);
2+
3+
use Symfony\Component\HttpFoundation\Cookie;
4+
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
5+
use function PHPStan\Testing\assertType;
6+
7+
$headerBag = new ResponseHeaderBag();
8+
$headerBag->setCookie(Cookie::create('cookie_name'));
9+
10+
assertType('array<int, Symfony\Component\HttpFoundation\Cookie>', $headerBag->getCookies());
11+
assertType('array<int, Symfony\Component\HttpFoundation\Cookie>', $headerBag->getCookies(ResponseHeaderBag::COOKIES_FLAT));
12+
assertType('array<string, array<string, array<string, Symfony\Component\HttpFoundation\Cookie>>>', $headerBag->getCookies(ResponseHeaderBag::COOKIES_ARRAY));

0 commit comments

Comments
 (0)