Skip to content

Commit 4bb2c58

Browse files
Merge pull request #130 from alexanderschnitzler/feature/add-useraspect-get-dynamic-return-type-extension
[FEATURE] Add dynamic return type extension for UserAspect::get()
2 parents 3f3a64b + d0e5079 commit 4bb2c58

File tree

4 files changed

+132
-0
lines changed

4 files changed

+132
-0
lines changed

extension.neon

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ services:
9797
class: SaschaEgerer\PhpstanTypo3\Stubs\StubFilesExtensionLoader
9898
tags:
9999
- phpstan.stubFilesExtension
100+
-
101+
class: SaschaEgerer\PhpstanTypo3\Type\UserAspectGetDynamicReturnTypeExtension
102+
tags:
103+
- phpstan.broker.dynamicMethodReturnTypeExtension
100104
parameters:
101105
bootstrapFiles:
102106
- phpstan.bootstrap.php
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace SaschaEgerer\PhpstanTypo3\Type;
4+
5+
use PhpParser\Node\Arg;
6+
use PhpParser\Node\Expr\MethodCall;
7+
use PHPStan\Analyser\Scope;
8+
use PHPStan\Reflection\MethodReflection;
9+
use PHPStan\Type\ArrayType;
10+
use PHPStan\Type\BooleanType;
11+
use PHPStan\Type\Constant\ConstantStringType;
12+
use PHPStan\Type\DynamicMethodReturnTypeExtension;
13+
use PHPStan\Type\IntegerRangeType;
14+
use PHPStan\Type\IntegerType;
15+
use PHPStan\Type\StringType;
16+
use TYPO3\CMS\Core\Context\UserAspect;
17+
18+
class UserAspectGetDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
19+
{
20+
21+
public function getClass(): string
22+
{
23+
return UserAspect::class;
24+
}
25+
26+
public function isMethodSupported(MethodReflection $methodReflection): bool
27+
{
28+
return $methodReflection->getName() === 'get';
29+
}
30+
31+
public function getTypeFromMethodCall(
32+
MethodReflection $methodReflection,
33+
MethodCall $methodCall,
34+
Scope $scope
35+
): ?\PHPStan\Type\Type
36+
{
37+
$firstArgument = $methodCall->args[0];
38+
39+
if (!$firstArgument instanceof Arg) {
40+
return null;
41+
}
42+
43+
$argumentType = $scope->getType($firstArgument->value);
44+
45+
if ($argumentType instanceof ConstantStringType) {
46+
switch ($argumentType->getValue()) {
47+
case 'id':
48+
return IntegerRangeType::createAllGreaterThanOrEqualTo(0);
49+
case 'username':
50+
return new StringType();
51+
case 'isLoggedIn':
52+
case 'isAdmin':
53+
return new BooleanType();
54+
case 'groupIds':
55+
return new ArrayType(new IntegerType(), IntegerRangeType::fromInterval(-2, null));
56+
case 'groupNames':
57+
return new ArrayType(new IntegerType(), new StringType());
58+
}
59+
}
60+
61+
return null;
62+
}
63+
64+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace SaschaEgerer\PhpstanTypo3\Tests\Unit\Type\UserAspectGetDynamicReturnTypeExtension;
4+
5+
use PHPStan\Testing\TypeInferenceTestCase;
6+
7+
final class UserAspectGetDynamicReturnTypeExtensionTest extends TypeInferenceTestCase
8+
{
9+
10+
/**
11+
*
12+
* @return iterable<mixed>
13+
*/
14+
public function dataFileAsserts(): iterable
15+
{
16+
yield from $this->gatherAssertTypes(__DIR__ . '/data/user-aspect-get-return-types.php');
17+
}
18+
19+
/**
20+
* @dataProvider dataFileAsserts
21+
* @param string $assertType
22+
* @param string $file
23+
* @param mixed ...$args
24+
*/
25+
public function testFileAsserts(
26+
string $assertType,
27+
string $file,
28+
...$args
29+
): void
30+
{
31+
$this->assertFileAsserts($assertType, $file, ...$args);
32+
}
33+
34+
public static function getAdditionalConfigFiles(): array
35+
{
36+
return [
37+
__DIR__ . '/../../../../extension.neon',
38+
];
39+
}
40+
41+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace SaschaEgerer\PhpstanTypo3\Tests\Unit\Type\UserAspectGetDynamicReturnTypeExtension\data;
4+
5+
use TYPO3\CMS\Core\Context\UserAspect;
6+
7+
use function PHPStan\Testing\assertType;
8+
9+
// phpcs:ignore Squiz.Classes.ClassFileName.NoMatch
10+
class MyContext
11+
{
12+
13+
public function getTests(UserAspect $context): void
14+
{
15+
assertType('int<0, max>', $context->get('id'));
16+
assertType('string', $context->get('username'));
17+
assertType('bool', $context->get('isLoggedIn'));
18+
assertType('bool', $context->get('isAdmin'));
19+
assertType('array<int, int<-2, max>>', $context->get('groupIds'));
20+
assertType('array<int, string>', $context->get('groupNames'));
21+
}
22+
23+
}

0 commit comments

Comments
 (0)