diff --git a/src/Rules/Doctrine/NoDocumentMockingRule.php b/src/Rules/Doctrine/NoDocumentMockingRule.php index 7b9de018..48e6b6b4 100644 --- a/src/Rules/Doctrine/NoDocumentMockingRule.php +++ b/src/Rules/Doctrine/NoDocumentMockingRule.php @@ -7,18 +7,26 @@ use PhpParser\Node; use PhpParser\Node\Expr\MethodCall; use PHPStan\Analyser\Scope; +use PHPStan\Reflection\ReflectionProvider; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; +use PHPStan\Type\Constant\ConstantStringType; use Symplify\PHPStanRules\Enum\RuleIdentifier\PHPUnitRuleIdentifier; use Symplify\PHPStanRules\Helper\NamingHelper; /** * @implements Rule + * @see \Symplify\PHPStanRules\Tests\Rules\Doctrine\NoDocumentMockingRule\NoDocumentMockingRuleTest */ -final class NoDocumentMockingRule implements Rule +final readonly class NoDocumentMockingRule implements Rule { public const string ERROR_MESSAGE = 'Instead of document mocking, create object directly to get better type support'; + public function __construct( + private ReflectionProvider $reflectionProvider + ) { + } + public function getNodeType(): string { return MethodCall::class; @@ -40,7 +48,11 @@ public function processNode(Node $node, Scope $scope): array $firstArg = $node->getArgs()[0]; $mockedClassType = $scope->getType($firstArg->value); foreach ($mockedClassType->getConstantStrings() as $constantStringType) { - if (! str_contains($constantStringType->getValue(), '\\Document\\')) { + if (! str_contains($constantStringType->getValue(), '\\Document\\') && ! str_contains($constantStringType->getValue(), '\\Entity\\')) { + continue; + } + + if ($this->shouldSkipDocumentClass($constantStringType)) { continue; } @@ -53,4 +65,20 @@ public function processNode(Node $node, Scope $scope): array return []; } + + private function shouldSkipDocumentClass(ConstantStringType $constantStringType): bool + { + if ($this->reflectionProvider->hasClass($constantStringType->getValue())) { + $classReflection = $this->reflectionProvider->getClass($constantStringType->getValue()); + if ($classReflection->isAbstract()) { + return true; + } + + if ($classReflection->isInterface()) { + return true; + } + } + + return false; + } } diff --git a/tests/Rules/Doctrine/NoDocumentMockingRule/Fixture/SomeAbstractEntityMocking.php b/tests/Rules/Doctrine/NoDocumentMockingRule/Fixture/SomeAbstractEntityMocking.php new file mode 100644 index 00000000..2f881bc6 --- /dev/null +++ b/tests/Rules/Doctrine/NoDocumentMockingRule/Fixture/SomeAbstractEntityMocking.php @@ -0,0 +1,17 @@ +createMock(AbstractSomeEntity::class); + } +} diff --git a/tests/Rules/Doctrine/NoDocumentMockingRule/Fixture/SomeEntityMocking.php b/tests/Rules/Doctrine/NoDocumentMockingRule/Fixture/SomeEntityMocking.php new file mode 100644 index 00000000..1b833253 --- /dev/null +++ b/tests/Rules/Doctrine/NoDocumentMockingRule/Fixture/SomeEntityMocking.php @@ -0,0 +1,16 @@ +createMock(SomeEntity::class); + } +} diff --git a/tests/Rules/Doctrine/NoDocumentMockingRule/NoDocumentMockingRuleTest.php b/tests/Rules/Doctrine/NoDocumentMockingRule/NoDocumentMockingRuleTest.php new file mode 100644 index 00000000..3056d503 --- /dev/null +++ b/tests/Rules/Doctrine/NoDocumentMockingRule/NoDocumentMockingRuleTest.php @@ -0,0 +1,51 @@ +> $expectedErrorMessagesWithLines + */ + #[DataProvider('provideData')] + public function testRule(string $filePath, array $expectedErrorMessagesWithLines): void + { + $this->analyse([$filePath], $expectedErrorMessagesWithLines); + } + + /** + * @return Iterator, mixed>> + */ + public static function provideData(): Iterator + { + yield [__DIR__ . '/Fixture/SomeEntityMocking.php', [[ + NoDocumentMockingRule::ERROR_MESSAGE, + 14, + ]]]; + + yield [__DIR__ . '/Fixture/SomeAbstractEntityMocking.php', []]; + } + + /** + * @return string[] + */ + #[Override] + public static function getAdditionalConfigFiles(): array + { + return [__DIR__ . '/config/configured_rule.neon']; + } + + protected function getRule(): Rule + { + return self::getContainer()->getByType(NoDocumentMockingRule::class); + } +} diff --git a/tests/Rules/Doctrine/NoDocumentMockingRule/Source/Entity/AbstractSomeEntity.php b/tests/Rules/Doctrine/NoDocumentMockingRule/Source/Entity/AbstractSomeEntity.php new file mode 100644 index 00000000..e919be35 --- /dev/null +++ b/tests/Rules/Doctrine/NoDocumentMockingRule/Source/Entity/AbstractSomeEntity.php @@ -0,0 +1,12 @@ +