diff --git a/README.md b/README.md index bc6b1db6..7148323e 100644 --- a/README.md +++ b/README.md @@ -1065,6 +1065,28 @@ final class SomeClass
+## Doctrine-specific Rules + +### NoGetRepositoryOutsideServiceRule + +Instead of getting repository from EntityManager, use constructor injection and service pattern to keep code clean + +```yaml +rules: + - Symplify\PHPStanRules\Rules\Doctrine\NoGetRepositoryOutsideServiceRule +``` + +```php +class SomeClass +{ + public function run(EntityManagerInterface $entityManager) + { + return $entityManager->getRepository(SomeEntity::class); + } +} +``` + +
diff --git a/src/Enum/RuleIdentifier.php b/src/Enum/RuleIdentifier.php index a79d8874..1b583d09 100644 --- a/src/Enum/RuleIdentifier.php +++ b/src/Enum/RuleIdentifier.php @@ -182,4 +182,26 @@ final class RuleIdentifier public const NO_DYNAMIC_NAME = 'symplify.noDynamicName'; public const NO_REFERENCE = 'symplify.noReference'; + + public const PHPUNIT_NO_MOCK_ONLY = 'phpunit.noMockOnly'; + + public const SINGLE_ARG_EVENT_DISPATCH = 'symfony.singleArgEventDispatch'; + + public const NO_ENTITY_MOCKING = 'doctrine.noEntityMocking'; + + public const NO_STRING_IN_GET_SUBSCRIBED_EVENTS = 'symfony.noStringInGetSubscribedEvents'; + + public const NO_LISTENER_WITHOUT_CONTRACT = 'symfony.noListenerWithoutContract'; + + public const DOCTRINE_NO_PARENT_REPOSITORY = 'doctrine.noParentRepository'; + + public const DOCTRINE_NO_GET_REPOSITORY_OUTSIDE_SERVICE = 'doctrine.noGetRepositoryOutsideService'; + + public const SYMFONY_NO_REQUIRED_OUTSIDE_CLASS = 'symfony.noRequiredOutsideClass'; + + public const NO_CONSTRUCTOR_OVERRIDE = 'symplify.noConstructorOverride'; + + public const SYMFONY_NO_ABSTRACT_CONTROLLER_CONSTRUCTOR = 'symfony.noAbstractControllerConstructor'; + + public const PHPUNIT_PUBLIC_STATIC_DATA_PROVIDER = 'phpunit.publicStaticDataProvider'; } diff --git a/src/PHPStan/Rules/Doctrine/NoGetRepositoryOutsideServiceRule.php b/src/PHPStan/Rules/Doctrine/NoGetRepositoryOutsideServiceRule.php index 4b5e9e3d..7a2ea3cd 100644 --- a/src/PHPStan/Rules/Doctrine/NoGetRepositoryOutsideServiceRule.php +++ b/src/PHPStan/Rules/Doctrine/NoGetRepositoryOutsideServiceRule.php @@ -9,14 +9,11 @@ use PhpParser\Node\Identifier; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; -use PHPStan\Rules\RuleError; use PHPStan\Rules\RuleErrorBuilder; +use Symplify\PHPStanRules\Enum\RuleIdentifier; /** - * Check if abstract controller has constructor, as it should use - * #[Require] instead to avoid parent constructor override - * - * @see \Symplify\PHPStanRules\Tests\PHPStan\Rule\NoGetRepositoryOutsideServiceRule\NoGetRepositoryOutsideServiceRuleTest + * @see \Symplify\PHPStanRules\Tests\Rules\Doctrine\NoGetRepositoryOutsideServiceRule\NoGetRepositoryOutsideServiceRuleTest * * @implements Rule */ @@ -34,7 +31,6 @@ public function getNodeType(): string /** * @param MethodCall $node - * @return RuleError[] */ public function processNode(Node $node, Scope $scope): array { @@ -47,7 +43,10 @@ public function processNode(Node $node, Scope $scope): array } if (! $scope->isInClass()) { - $ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)->build(); + $ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE) + ->identifier(RuleIdentifier::DOCTRINE_NO_GET_REPOSITORY_OUTSIDE_SERVICE) + ->build(); + return [$ruleError]; } @@ -57,7 +56,10 @@ public function processNode(Node $node, Scope $scope): array return []; } - $ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)->build(); + $ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE) + ->identifier(RuleIdentifier::DOCTRINE_NO_GET_REPOSITORY_OUTSIDE_SERVICE) + ->build(); + return [$ruleError]; } } diff --git a/src/PHPStan/Rules/Doctrine/NoParentRepositoryRule.php b/src/PHPStan/Rules/Doctrine/NoParentRepositoryRule.php index a672c7a8..bdddc053 100644 --- a/src/PHPStan/Rules/Doctrine/NoParentRepositoryRule.php +++ b/src/PHPStan/Rules/Doctrine/NoParentRepositoryRule.php @@ -9,8 +9,8 @@ use PhpParser\Node\Stmt\Class_; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; -use PHPStan\Rules\RuleError; use PHPStan\Rules\RuleErrorBuilder; +use Symplify\PHPStanRules\Enum\RuleIdentifier; /** * Check if class extends repository class, @@ -39,7 +39,6 @@ public function getNodeType(): string /** * @param Class_ $node - * @return RuleError[] */ public function processNode(Node $node, Scope $scope): array { @@ -53,6 +52,7 @@ public function processNode(Node $node, Scope $scope): array } $ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE) + ->identifier(RuleIdentifier::DOCTRINE_NO_PARENT_REPOSITORY) ->build(); return [$ruleError]; diff --git a/src/Testing/DataProviderMethodResolver.php b/src/PHPUnit/DataProviderMethodResolver.php similarity index 94% rename from src/Testing/DataProviderMethodResolver.php rename to src/PHPUnit/DataProviderMethodResolver.php index 86b568e4..409fa996 100644 --- a/src/Testing/DataProviderMethodResolver.php +++ b/src/PHPUnit/DataProviderMethodResolver.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Symplify\PHPStanRules\PHPStan; +namespace Symplify\PHPStanRules\PHPUnit; use PhpParser\Comment\Doc; use PhpParser\Node\Stmt\ClassMethod; diff --git a/src/Rules/Complexity/NoConstructorOverrideRule.php b/src/Rules/Complexity/NoConstructorOverrideRule.php index a5f29e91..acb22bff 100644 --- a/src/Rules/Complexity/NoConstructorOverrideRule.php +++ b/src/Rules/Complexity/NoConstructorOverrideRule.php @@ -10,8 +10,8 @@ use PhpParser\NodeFinder; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; -use PHPStan\Rules\RuleError; use PHPStan\Rules\RuleErrorBuilder; +use Symplify\PHPStanRules\Enum\RuleIdentifier; /** * @implements Rule @@ -35,7 +35,6 @@ public function getNodeType(): string /** * @param ClassMethod $node - * @return RuleError[] */ public function processNode(Node $node, Scope $scope): array { @@ -69,7 +68,10 @@ public function processNode(Node $node, Scope $scope): array return []; } - $ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)->build(); + $ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE) + ->identifier(RuleIdentifier::NO_CONSTRUCTOR_OVERRIDE) + ->build(); + return [$ruleError]; } } diff --git a/src/Rules/Doctrine/NoEntityMockingRule.php b/src/Rules/Doctrine/NoEntityMockingRule.php index 18be7a58..2e834c7e 100644 --- a/src/Rules/Doctrine/NoEntityMockingRule.php +++ b/src/Rules/Doctrine/NoEntityMockingRule.php @@ -10,8 +10,8 @@ use PHPStan\Analyser\Scope; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Rules\Rule; -use PHPStan\Rules\RuleError; use PHPStan\Rules\RuleErrorBuilder; +use Symplify\PHPStanRules\Enum\RuleIdentifier; use Symplify\PHPStanRules\PHPStan\DoctrineEntityDocumentAnalyser; /** @@ -40,7 +40,6 @@ public function getNodeType(): string /** * @param MethodCall $node - * @return RuleError[] */ public function processNode(Node $node, Scope $scope): array { @@ -62,6 +61,7 @@ public function processNode(Node $node, Scope $scope): array } $ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE) + ->identifier(RuleIdentifier::NO_ENTITY_MOCKING) ->build(); return [$ruleError]; diff --git a/src/Rules/PHPUnit/NoMockOnlyTestRule.php b/src/Rules/PHPUnit/NoMockOnlyTestRule.php index 4b6a2142..6ebcd060 100644 --- a/src/Rules/PHPUnit/NoMockOnlyTestRule.php +++ b/src/Rules/PHPUnit/NoMockOnlyTestRule.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Symplify\PHPStanRules\PHPStan\Rule; +namespace Symplify\PHPStanRules\Rules\PHPUnit; use PhpParser\Node; use PhpParser\Node\Name; @@ -10,12 +10,11 @@ use PHPStan\Analyser\Scope; use PHPStan\Node\InClassNode; use PHPStan\Rules\Rule; -use PHPStan\Rules\RuleError; use PHPStan\Rules\RuleErrorBuilder; -use Symplify\PHPStanRules\PHPStan\PHPUnitTestAnalyser; +use Symplify\PHPStanRules\Enum\RuleIdentifier; /** - * @see \Symplify\PHPStanRules\Tests\PHPStan\Rule\NoMockOnlyTestRule\NoMockOnlyTestRuleTest + * @see \Symplify\PHPStanRules\Tests\Rules\PHPUnit\NoMockOnlyTestRule\NoMockOnlyTestRuleTest * * @implements Rule */ @@ -38,11 +37,10 @@ public function getNodeType(): string /** * @param InClassNode $node - * @return RuleError[] */ public function processNode(Node $node, Scope $scope): array { - if (! PHPUnitTestAnalyser::isTestClass($scope)) { + if (! \Symplify\PHPStanRules\Testing\PHPUnitTestAnalyser::isTestClass($scope)) { return []; } @@ -74,7 +72,9 @@ public function processNode(Node $node, Scope $scope): array } $ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE) + ->identifier(RuleIdentifier::PHPUNIT_NO_MOCK_ONLY) ->build(); + return [$ruleError]; } } diff --git a/src/Rules/PHPUnit/PublicStaticDataProviderRule.php b/src/Rules/PHPUnit/PublicStaticDataProviderRule.php index 3629ff47..96cb75f8 100644 --- a/src/Rules/PHPUnit/PublicStaticDataProviderRule.php +++ b/src/Rules/PHPUnit/PublicStaticDataProviderRule.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Symplify\PHPStanRules\PHPStan\Rule; +namespace Symplify\PHPStanRules\Rules\PHPUnit; use PhpParser\Node; use PhpParser\Node\Stmt\ClassMethod; @@ -10,8 +10,8 @@ use PHPStan\Node\InClassNode; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; -use Symplify\PHPStanRules\PHPStan\DataProviderMethodResolver; -use Symplify\PHPStanRules\PHPStan\PHPUnitTestAnalyser; +use Symplify\PHPStanRules\Enum\RuleIdentifier; +use Symplify\PHPStanRules\PHPUnit\DataProviderMethodResolver; /** * PHPUnit data provider have to be public and static @@ -42,7 +42,7 @@ public function getNodeType(): string */ public function processNode(Node $node, Scope $scope): array { - if (! PHPUnitTestAnalyser::isTestClass($scope)) { + if (! \Symplify\PHPStanRules\Testing\PHPUnitTestAnalyser::isTestClass($scope)) { return []; } @@ -50,7 +50,7 @@ public function processNode(Node $node, Scope $scope): array $classLike = $node->getOriginalNode(); foreach ($classLike->getMethods() as $classMethod) { - if (! PHPUnitTestAnalyser::isTestClassMethod($classMethod)) { + if (! \Symplify\PHPStanRules\Testing\PHPUnitTestAnalyser::class::isTestClassMethod($classMethod)) { continue; } @@ -75,7 +75,7 @@ public function processNode(Node $node, Scope $scope): array if (! $dataProviderClassMethod->isStatic()) { $errorMessage = sprintf(self::PUBLIC_ERROR_MESSAGE, $dataProviderMethodName); $ruleErrors[] = RuleErrorBuilder::message($errorMessage) - ->identifier('phpunit.publicDataProvider') + ->identifier(RuleIdentifier::PHPUNIT_PUBLIC_STATIC_DATA_PROVIDER) ->line($dataProviderClassMethod->getLine()) ->build(); } diff --git a/src/Rules/Symfony/NoAbstractControllerConstructorRule.php b/src/Rules/Symfony/NoAbstractControllerConstructorRule.php index 8fd51ddf..8e6cc4de 100644 --- a/src/Rules/Symfony/NoAbstractControllerConstructorRule.php +++ b/src/Rules/Symfony/NoAbstractControllerConstructorRule.php @@ -9,8 +9,8 @@ use PhpParser\Node\Stmt\Class_; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; -use PHPStan\Rules\RuleError; use PHPStan\Rules\RuleErrorBuilder; +use Symplify\PHPStanRules\Enum\RuleIdentifier; /** * Check if abstract controller has constructor, as it should use @@ -34,7 +34,6 @@ public function getNodeType(): string /** * @param Class_ $node - * @return RuleError[] */ public function processNode(Node $node, Scope $scope): array { @@ -55,7 +54,10 @@ public function processNode(Node $node, Scope $scope): array return []; } - $ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)->build(); + $ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE) + ->identifier(RuleIdentifier::SYMFONY_NO_ABSTRACT_CONTROLLER_CONSTRUCTOR) + ->build(); + return [$ruleError]; } } diff --git a/src/Rules/Symfony/NoListenerWithoutContractRule.php b/src/Rules/Symfony/NoListenerWithoutContractRule.php index 3b157b3e..41326ab7 100644 --- a/src/Rules/Symfony/NoListenerWithoutContractRule.php +++ b/src/Rules/Symfony/NoListenerWithoutContractRule.php @@ -9,8 +9,8 @@ use PHPStan\Analyser\Scope; use PHPStan\Node\InClassNode; use PHPStan\Rules\Rule; -use PHPStan\Rules\RuleError; use PHPStan\Rules\RuleErrorBuilder; +use Symplify\PHPStanRules\Enum\RuleIdentifier; /** * Based on https://tomasvotruba.com/blog/2019/07/22/how-to-convert-listeners-to-subscribers-and-reduce-your-configs @@ -23,7 +23,7 @@ final class NoListenerWithoutContractRule implements Rule /** * @var string */ - public const ERROR_MESSAGE = 'There should be no listeners defined in yaml config, use contract + PHP instead'; + public const ERROR_MESSAGE = 'There should be no listeners modified in config. Use EventSubscriberInterface contract and PHP instead'; public function getNodeType(): string { @@ -32,7 +32,6 @@ public function getNodeType(): string /** * @param InClassNode $node - * @return RuleError[] */ public function processNode(Node $node, Scope $scope): array { @@ -54,7 +53,9 @@ public function processNode(Node $node, Scope $scope): array return []; } - $ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)->build(); + $ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE) + ->identifier(RuleIdentifier::NO_LISTENER_WITHOUT_CONTRACT) + ->build(); return [$ruleError]; } diff --git a/src/Rules/Symfony/NoRequiredOutsideClassRule.php b/src/Rules/Symfony/NoRequiredOutsideClassRule.php index 93bf69d3..22aa07ec 100644 --- a/src/Rules/Symfony/NoRequiredOutsideClassRule.php +++ b/src/Rules/Symfony/NoRequiredOutsideClassRule.php @@ -10,8 +10,8 @@ use PhpParser\Node\Stmt\Trait_; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; -use PHPStan\Rules\RuleError; use PHPStan\Rules\RuleErrorBuilder; +use Symplify\PHPStanRules\Enum\RuleIdentifier; /** * @see \Symplify\PHPStanRules\Tests\PHPStan\Rule\NoRequiredOutsideClassRule\NoRequiredOutsideClassRuleTest @@ -37,7 +37,6 @@ public function getNodeType(): string /** * @param Trait_ $node - * @return RuleError[] */ public function processNode(Node $node, Scope $scope): array { @@ -47,6 +46,7 @@ public function processNode(Node $node, Scope $scope): array if ($this->isAutowiredClassMethod($classMethod)) { $ruleErrors[] = RuleErrorBuilder::message(self::ERROR_MESSAGE) ->file($scope->getFile()) + ->identifier(RuleIdentifier::SYMFONY_NO_REQUIRED_OUTSIDE_CLASS) ->line($classMethod->getLine()) ->build(); } diff --git a/src/Rules/Symfony/NoStringInGetSubscribedEventsRule.php b/src/Rules/Symfony/NoStringInGetSubscribedEventsRule.php index c6640577..c74e1f88 100644 --- a/src/Rules/Symfony/NoStringInGetSubscribedEventsRule.php +++ b/src/Rules/Symfony/NoStringInGetSubscribedEventsRule.php @@ -13,9 +13,9 @@ use PHPStan\Analyser\Scope; use PHPStan\Reflection\ClassReflection; use PHPStan\Rules\Rule; -use PHPStan\Rules\RuleError; use PHPStan\Rules\RuleErrorBuilder; use Symplify\PHPStanRules\Enum\ClassName; +use Symplify\PHPStanRules\Enum\RuleIdentifier; /** * @implements Rule @@ -39,7 +39,6 @@ public function getNodeType(): string /** * @param ClassMethod $node - * @return RuleError[] */ public function processNode(Node $node, Scope $scope): array { @@ -95,7 +94,10 @@ public function processNode(Node $node, Scope $scope): array continue; } - $ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)->build(); + $ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE) + ->identifier(RuleIdentifier::NO_STRING_IN_GET_SUBSCRIBED_EVENTS) + ->build(); + return [$ruleError]; } diff --git a/src/Rules/Symfony/SingleArgEventDispatchRule.php b/src/Rules/Symfony/SingleArgEventDispatchRule.php index 6bc7f787..134ec1da 100644 --- a/src/Rules/Symfony/SingleArgEventDispatchRule.php +++ b/src/Rules/Symfony/SingleArgEventDispatchRule.php @@ -9,10 +9,10 @@ use PhpParser\Node\Identifier; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; -use PHPStan\Rules\RuleError; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\ObjectType; use Symplify\PHPStanRules\Enum\ClassName; +use Symplify\PHPStanRules\Enum\RuleIdentifier; /** * @implements Rule @@ -31,7 +31,6 @@ public function getNodeType(): string /** * @param MethodCall $node - * @return RuleError[] */ public function processNode(Node $node, Scope $scope): array { @@ -57,7 +56,10 @@ public function processNode(Node $node, Scope $scope): array return []; } - $ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)->build(); + $ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE) + ->identifier(RuleIdentifier::SINGLE_ARG_EVENT_DISPATCH) + ->build(); + return [$ruleError]; } } diff --git a/src/Testing/PHPUnitTestAnalyser.php b/src/Testing/PHPUnitTestAnalyser.php index 6a7b5947..bf951a4b 100644 --- a/src/Testing/PHPUnitTestAnalyser.php +++ b/src/Testing/PHPUnitTestAnalyser.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Symplify\PHPStanRules\PHPStan; +namespace Symplify\PHPStanRules\Testing; use PhpParser\Node\Stmt\ClassMethod; use PHPStan\Analyser\Scope; diff --git a/tests/Rules/PHPUnit/NoMockOnlyTestRule/NoMockOnlyTestRuleTest.php b/tests/Rules/PHPUnit/NoMockOnlyTestRule/NoMockOnlyTestRuleTest.php index 0b540bcc..1f7e7f85 100644 --- a/tests/Rules/PHPUnit/NoMockOnlyTestRule/NoMockOnlyTestRuleTest.php +++ b/tests/Rules/PHPUnit/NoMockOnlyTestRule/NoMockOnlyTestRuleTest.php @@ -8,7 +8,7 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; use PHPUnit\Framework\Attributes\DataProvider; -use Symplify\PHPStanRules\PHPStan\Rule\NoMockOnlyTestRule; +use Symplify\PHPStanRules\Rules\PHPUnit\NoMockOnlyTestRule; final class NoMockOnlyTestRuleTest extends RuleTestCase { diff --git a/tests/Rules/PHPUnit/PublicStaticDataProviderRule/PublicStaticDataProviderRuleTest.php b/tests/Rules/PHPUnit/PublicStaticDataProviderRule/PublicStaticDataProviderRuleTest.php index 2a729e2f..4f42c146 100644 --- a/tests/Rules/PHPUnit/PublicStaticDataProviderRule/PublicStaticDataProviderRuleTest.php +++ b/tests/Rules/PHPUnit/PublicStaticDataProviderRule/PublicStaticDataProviderRuleTest.php @@ -6,7 +6,7 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; use PHPUnit\Framework\Attributes\DataProvider; -use Symplify\PHPStanRules\PHPStan\Rule\PublicStaticDataProviderRule; +use Symplify\PHPStanRules\Rules\PHPUnit\PublicStaticDataProviderRule; final class PublicStaticDataProviderRuleTest extends RuleTestCase {