Skip to content

Commit 3cb4dda

Browse files
authored
Add NoValueObjectInServiceConstructorRule (#152)
1 parent 7beae59 commit 3cb4dda

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

src/Enum/RuleIdentifier.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,9 @@ final class RuleIdentifier
160160
* @var string
161161
*/
162162
public const SYMFONY_REQUIRE_INVOKABLE_CONTROLLER = 'symfony.requireInvokableController';
163+
164+
/**
165+
* @var string
166+
*/
167+
public const NO_VALUE_OBJECT_IN_SERVICE_CONSTRUCTOR = 'symplify.noValueObjectInServiceConstructor';
163168
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Symplify\PHPStanRules\Rules;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Name;
9+
use PhpParser\Node\Stmt\ClassMethod;
10+
use PHPStan\Analyser\Scope;
11+
use PHPStan\Rules\Rule;
12+
use PHPStan\Rules\RuleErrorBuilder;
13+
use Symplify\PHPStanRules\Enum\RuleIdentifier;
14+
15+
/**
16+
* @implements Rule<ClassMethod>
17+
*/
18+
final class NoValueObjectInServiceConstructorRule implements Rule
19+
{
20+
public function getNodeType(): string
21+
{
22+
return ClassMethod::class;
23+
}
24+
25+
/**
26+
* @param ClassMethod $node
27+
*/
28+
public function processNode(Node $node, Scope $scope): array
29+
{
30+
if ($node->name->toString() !== '__construct') {
31+
return [];
32+
}
33+
34+
if (! $scope->isInClass()) {
35+
return [];
36+
}
37+
38+
$classReflection = $scope->getClassReflection();
39+
40+
// value objects can accept value objects
41+
if ($this->isValueObject($classReflection->getName())) {
42+
return [];
43+
}
44+
45+
$ruleErrors = [];
46+
47+
foreach ($node->params as $param) {
48+
if (! $param->type instanceof Name) {
49+
continue;
50+
}
51+
52+
$paramType = $param->type->toString();
53+
if (! $this->isValueObject($paramType)) {
54+
continue;
55+
}
56+
57+
$ruleErrors[] = RuleErrorBuilder::message(sprintf(
58+
'Value object "%s" cannot be passed to constructor of a service. Pass it as a method argument instead',
59+
$paramType
60+
))
61+
->identifier(RuleIdentifier::NO_VALUE_OBJECT_IN_SERVICE_CONSTRUCTOR)
62+
->build();
63+
}
64+
65+
return $ruleErrors;
66+
}
67+
68+
private function isValueObject(string $className): bool
69+
{
70+
return preg_match('#(ValueObject|DataObject|Models)#', $className) === 1;
71+
}
72+
}

0 commit comments

Comments
 (0)