Skip to content

Commit df8c48a

Browse files
Make attributes of Request Api configurable (#51)
Co-authored-by: Sascha Egerer <[email protected]>
1 parent 0997304 commit df8c48a

File tree

3 files changed

+96
-1
lines changed

3 files changed

+96
-1
lines changed

README.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ includes:
2727

2828
### Custom Context API Aspects
2929

30-
If you use custom aspects for the TYPO3 Context API you can now add a mapping so PHPStan knows
30+
If you use custom aspects for the TYPO3 Context API you can add a mapping so PHPStan knows
3131
what type of aspect class is returned by the context API
3232

3333
```
@@ -36,3 +36,25 @@ parameters:
3636
contextApiGetAspectMapping:
3737
myCustomAspect: FlowdGmbh\MyProject\Context\MyCustomAspect
3838
```
39+
40+
```
41+
// PHPStan will now know that $myCustomAspect is of type FlowdGmbh\MyProject\Context\MyCustomAspect
42+
$myCustomAspect = GeneralUtility::makeInstance(Context::class)->getAspect('myCustomAspect');
43+
```
44+
45+
### Custom Request Attribute
46+
47+
If you use custom PSR-7 request attribute you can add a mapping so PHPStan knows
48+
what type of class is returned by Request::getAttribute()
49+
50+
```
51+
parameters:
52+
typo3:
53+
requestApiGetAttributeMapping:
54+
myAttribute: FlowdGmbh\MyProject\Http\MyAttribute
55+
```
56+
57+
```
58+
// PHPStan will now know that $myAttribute is of type FlowdGmbh\MyProject\Http\MyAttribute
59+
$myAttribute = $request->getAttribute('myAttribute');
60+
```

extension.neon

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ services:
4747
class: SaschaEgerer\PhpstanTypo3\Type\RepositoryFindAllDynamicReturnTypeExtension
4848
tags:
4949
- phpstan.broker.dynamicMethodReturnTypeExtension
50+
-
51+
class: SaschaEgerer\PhpstanTypo3\Type\RequestDynamicReturnTypeExtension
52+
arguments:
53+
requestApiGetAttributeMapping: %typo3.requestApiGetAttributeMapping%
54+
tags:
55+
- phpstan.broker.dynamicMethodReturnTypeExtension
5056
parameters:
5157
bootstrapFiles:
5258
- phpstan.bootstrap.php
@@ -59,6 +65,14 @@ parameters:
5965
workspace: TYPO3\CMS\Core\Context\WorkspaceAspect
6066
language: TYPO3\CMS\Core\Context\LanguageAspect
6167
typoscript: TYPO3\CMS\Core\Context\TypoScriptAspect
68+
requestApiGetAttributeMapping:
69+
backend.user: TYPO3\CMS\Backend\FrontendBackendUserAuthentication
70+
frontend.user: TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication
71+
language: TYPO3\CMS\Core\Site\Entity\SiteLanguage
72+
module: TYPO3\CMS\Backend\Module\ModuleInterface
73+
moduleData: TYPO3\CMS\Backend\Module\ModuleData
74+
normalizedParams: TYPO3\CMS\Core\Http\NormalizedParams
75+
site: TYPO3\CMS\Core\Site\Entity\Site
6276
stubFiles:
6377
- stubs/DomainObjectInterface.stub
6478
- stubs/GeneralUtility.stub
@@ -112,4 +126,5 @@ parameters:
112126
parametersSchema:
113127
typo3: structure([
114128
contextApiGetAspectMapping: arrayOf(string())
129+
requestApiGetAttributeMapping: arrayOf(string())
115130
])
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace SaschaEgerer\PhpstanTypo3\Type;
4+
5+
use PhpParser\Node\Expr\MethodCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Reflection\MethodReflection;
8+
use PHPStan\Reflection\ParametersAcceptorSelector;
9+
use PHPStan\Type\DynamicMethodReturnTypeExtension;
10+
use PHPStan\Type\ObjectType;
11+
use PHPStan\Type\Type;
12+
13+
class RequestDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
14+
{
15+
16+
/** @var array<string, string> */
17+
private $requestApiGetAttributeMapping;
18+
19+
/**
20+
* @param array<string, string> $requestApiGetAttributeMapping
21+
*/
22+
public function __construct(array $requestApiGetAttributeMapping)
23+
{
24+
$this->requestApiGetAttributeMapping = $requestApiGetAttributeMapping;
25+
}
26+
27+
public function getClass(): string
28+
{
29+
return \Psr\Http\Message\ServerRequestInterface::class;
30+
}
31+
32+
public function getTypeFromMethodCall(
33+
MethodReflection $methodReflection,
34+
MethodCall $methodCall,
35+
Scope $scope
36+
): Type
37+
{
38+
$argument = $methodCall->getArgs()[0] ?? null;
39+
40+
if ($argument === null || !($argument->value instanceof \PhpParser\Node\Scalar\String_)) {
41+
return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
42+
}
43+
44+
if (isset($this->requestApiGetAttributeMapping[$argument->value->value])) {
45+
return new ObjectType($this->requestApiGetAttributeMapping[$argument->value->value]);
46+
}
47+
48+
return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
49+
}
50+
51+
public function isMethodSupported(
52+
MethodReflection $methodReflection
53+
): bool
54+
{
55+
return $methodReflection->getName() === 'getAttribute';
56+
}
57+
58+
}

0 commit comments

Comments
 (0)