Skip to content

Commit f574bb0

Browse files
committed
Added validation rule for site attribute
1 parent edebf53 commit f574bb0

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

extension.neon

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ services:
4545
requestGetAttributeMapping: %typo3.requestGetAttributeMapping%
4646
tags:
4747
- phpstan.rules.rule
48+
-
49+
class: SaschaEgerer\PhpstanTypo3\Rule\SiteAttributeValidationRule
50+
arguments:
51+
siteGetAttributeMapping: %typo3.siteGetAttributeMapping%
52+
tags:
53+
- phpstan.rules.rule
4854
-
4955
class: SaschaEgerer\PhpstanTypo3\Type\RepositoryQueryDynamicReturnTypeExtension
5056
tags:
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace SaschaEgerer\PhpstanTypo3\Rule;
4+
5+
use PhpParser\Node;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Rules\RuleErrorBuilder;
8+
use TYPO3\CMS\Core\Site\Entity\Site;
9+
10+
/**
11+
* @implements \PHPStan\Rules\Rule<\PhpParser\Node\Expr\MethodCall>
12+
*/
13+
class SiteAttributeValidationRule implements \PHPStan\Rules\Rule
14+
{
15+
16+
/** @var array<string, string> */
17+
private $siteGetAttributeMapping;
18+
19+
/**
20+
* @param array<string, string> $siteGetAttributeMapping
21+
*/
22+
public function __construct(array $siteGetAttributeMapping)
23+
{
24+
$this->siteGetAttributeMapping = $siteGetAttributeMapping;
25+
}
26+
27+
public function getNodeType(): string
28+
{
29+
return Node\Expr\MethodCall::class;
30+
}
31+
32+
public function processNode(Node $node, Scope $scope): array
33+
{
34+
if (!$node->name instanceof Node\Identifier) {
35+
return [];
36+
}
37+
38+
$methodReflection = $scope->getMethodReflection($scope->getType($node->var), $node->name->toString());
39+
if ($methodReflection === null || $methodReflection->getName() !== 'getAttribute') {
40+
return [];
41+
}
42+
43+
$declaringClass = $methodReflection->getDeclaringClass();
44+
45+
if (!$declaringClass->implementsInterface(Site::class) && $declaringClass->getName() !== Site::class) {
46+
return [];
47+
}
48+
49+
$argument = $node->getArgs()[0] ?? null;
50+
51+
if (!($argument instanceof Node\Arg) || !($argument->value instanceof Node\Scalar\String_)) {
52+
return [];
53+
}
54+
55+
if (isset($this->siteGetAttributeMapping[$argument->value->value])) {
56+
return [];
57+
}
58+
59+
$ruleError = RuleErrorBuilder::message(sprintf(
60+
'There is no site attribute "%s" configured so we can\'t figure out the exact type to return when calling %s::%s',
61+
$argument->value->value,
62+
$declaringClass->getDisplayName(),
63+
$methodReflection->getName()
64+
))->tip('You should add custom site attribute to the typo3.siteGetAttributeMapping setting.')->build();
65+
66+
return [$ruleError];
67+
}
68+
69+
}

0 commit comments

Comments
 (0)