Skip to content

Commit

Permalink
Add NoValueObjectInServiceConstructorRule (#152)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba authored Dec 17, 2024
1 parent 7beae59 commit 3cb4dda
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/Enum/RuleIdentifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,9 @@ final class RuleIdentifier
* @var string
*/
public const SYMFONY_REQUIRE_INVOKABLE_CONTROLLER = 'symfony.requireInvokableController';

/**
* @var string
*/
public const NO_VALUE_OBJECT_IN_SERVICE_CONSTRUCTOR = 'symplify.noValueObjectInServiceConstructor';
}
72 changes: 72 additions & 0 deletions src/Rules/NoValueObjectInServiceConstructorRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

declare(strict_types=1);

namespace Symplify\PHPStanRules\Rules;

use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use Symplify\PHPStanRules\Enum\RuleIdentifier;

/**
* @implements Rule<ClassMethod>
*/
final class NoValueObjectInServiceConstructorRule implements Rule
{
public function getNodeType(): string
{
return ClassMethod::class;
}

/**
* @param ClassMethod $node
*/
public function processNode(Node $node, Scope $scope): array
{
if ($node->name->toString() !== '__construct') {
return [];
}

if (! $scope->isInClass()) {
return [];
}

$classReflection = $scope->getClassReflection();

// value objects can accept value objects
if ($this->isValueObject($classReflection->getName())) {
return [];
}

$ruleErrors = [];

foreach ($node->params as $param) {
if (! $param->type instanceof Name) {
continue;
}

$paramType = $param->type->toString();
if (! $this->isValueObject($paramType)) {
continue;
}

$ruleErrors[] = RuleErrorBuilder::message(sprintf(
'Value object "%s" cannot be passed to constructor of a service. Pass it as a method argument instead',
$paramType
))
->identifier(RuleIdentifier::NO_VALUE_OBJECT_IN_SERVICE_CONSTRUCTOR)
->build();
}

return $ruleErrors;
}

private function isValueObject(string $className): bool
{
return preg_match('#(ValueObject|DataObject|Models)#', $className) === 1;
}
}

0 comments on commit 3cb4dda

Please sign in to comment.