Skip to content

Commit

Permalink
Add support for InputBag::all (Symfony 5+)
Browse files Browse the repository at this point in the history
  • Loading branch information
leongersen authored and ondrejmirtes committed Apr 14, 2021
1 parent 3a9a45c commit 8a062af
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 7 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ This extension provides following features:
* Provides correct return type for `Request::getContent()` method based on the `$asResource` parameter.
* Provides correct return type for `HeaderBag::get()` method based on the `$first` parameter.
* Provides correct return type for `Envelope::all()` method based on the `$stampFqcn` parameter.
* Provides correct return type for `InputBag::get()` method based on the `$default` parameter.
* Provides correct return type for `InputBag::all()` method based on the `$key` parameter.
* Provides correct return types for `TreeBuilder` and `NodeDefinition` objects.
* Notifies you when you try to get an unregistered service from the container.
* Notifies you when you try to get a private service from the container.
Expand Down
2 changes: 1 addition & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ parameters:
- tests/*/console_application_loader.php
- tests/*/envelope_all.php
- tests/*/header_bag_get.php
- tests/*/input_bag_get.php
- tests/*/input_bag.php
- tests/*/kernel_interface.php
- tests/*/request_get_content.php
- tests/*/request_get_session.php
Expand Down
34 changes: 33 additions & 1 deletion src/Type/Symfony/InputBagDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\ArrayType;
use PHPStan\Type\DynamicMethodReturnTypeExtension;
use PHPStan\Type\MixedType;
use PHPStan\Type\NullType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;

final class InputBagDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
{
Expand All @@ -21,14 +25,31 @@ public function getClass(): string

public function isMethodSupported(MethodReflection $methodReflection): bool
{
return $methodReflection->getName() === 'get';
return in_array($methodReflection->getName(), ['get', 'all'], true);
}

public function getTypeFromMethodCall(
MethodReflection $methodReflection,
MethodCall $methodCall,
Scope $scope
): Type
{
if ($methodReflection->getName() === 'get') {
return $this->getGetTypeFromMethodCall($methodReflection, $methodCall, $scope);
}

if ($methodReflection->getName() === 'all') {
return $this->getAllTypeFromMethodCall($methodCall);
}

throw new ShouldNotHappenException();
}

private function getGetTypeFromMethodCall(
MethodReflection $methodReflection,
MethodCall $methodCall,
Scope $scope
): Type
{
if (isset($methodCall->args[1])) {
$argType = $scope->getType($methodCall->args[1]->value);
Expand All @@ -43,4 +64,15 @@ public function getTypeFromMethodCall(
return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
}

private function getAllTypeFromMethodCall(
MethodCall $methodCall
): Type
{
if (isset($methodCall->args[0])) {
return new ArrayType(new MixedType(), new StringType());
}

return new ArrayType(new StringType(), new UnionType([new StringType(), new ArrayType(new MixedType(), new StringType())]));
}

}
10 changes: 6 additions & 4 deletions tests/Type/Symfony/InputBagDynamicReturnTypeExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ final class InputBagDynamicReturnTypeExtensionTest extends ExtensionTestCase
{

/**
* @dataProvider getProvider
* @dataProvider inputBagProvider
*/
public function testGet(string $expression, string $type): void
public function testInputBag(string $expression, string $type): void
{
if (!class_exists('Symfony\\Component\\HttpFoundation\\InputBag')) {
self::markTestSkipped('The test needs Symfony\Component\HttpFoundation\InputBag class.');
}

$this->processFile(
__DIR__ . '/input_bag_get.php',
__DIR__ . '/input_bag.php',
$expression,
$type,
[new InputBagDynamicReturnTypeExtension()]
Expand All @@ -27,12 +27,14 @@ public function testGet(string $expression, string $type): void
/**
* @return \Iterator<array{string, string}>
*/
public function getProvider(): Iterator
public function inputBagProvider(): Iterator
{
yield ['$test1', 'string|null'];
yield ['$test2', 'string|null'];
yield ['$test3', 'string'];
yield ['$test4', 'string'];
yield ['$test5', 'array<string, array<string>|string>'];
yield ['$test6', 'array<string>'];
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<?php declare(strict_types = 1);

$bag = new \Symfony\Component\HttpFoundation\InputBag(['foo' => 'bar']);
$bag = new \Symfony\Component\HttpFoundation\InputBag(['foo' => 'bar', 'bar' => ['x']]);

$test1 = $bag->get('foo');
$test2 = $bag->get('foo', null);
$test3 = $bag->get('foo', '');
$test4 = $bag->get('foo', 'baz');
$test5 = $bag->all();
$test6 = $bag->all('bar');

die;

0 comments on commit 8a062af

Please sign in to comment.