diff --git a/README.md b/README.md index 43c8a3b84..737b35f5f 100644 --- a/README.md +++ b/README.md @@ -1029,17 +1029,6 @@ class SomeClass extends SomeParentClass
-### RequiredOnlyInAbstractRule - -`@required` annotation should be used only in abstract classes, to child classes can use clean `__construct()` service injection. - -```yaml -rules: - - Symplify\PHPStanRules\Rules\Symfony\RequiredOnlyInAbstractRule -``` - -
- ### RequireRouteNameToGenerateControllerRouteRule To pass a controller class to generate() method, the controller must have "#[Route(name: self::class)]" above the __invoke() method diff --git a/config/symfony-rules.neon b/config/symfony-rules.neon index d79e87033..ae40eb476 100644 --- a/config/symfony-rules.neon +++ b/config/symfony-rules.neon @@ -21,7 +21,6 @@ rules: # magic required inject - Symplify\PHPStanRules\Rules\Symfony\SingleRequiredMethodRule - - Symplify\PHPStanRules\Rules\Symfony\RequiredOnlyInAbstractRule - Symplify\PHPStanRules\Rules\Symfony\NoConstructorAndRequiredTogetherRule # attributes diff --git a/src/Enum/RuleIdentifier/SymfonyRuleIdentifier.php b/src/Enum/RuleIdentifier/SymfonyRuleIdentifier.php index 18f10a05d..ed1c20b62 100644 --- a/src/Enum/RuleIdentifier/SymfonyRuleIdentifier.php +++ b/src/Enum/RuleIdentifier/SymfonyRuleIdentifier.php @@ -22,8 +22,6 @@ final class SymfonyRuleIdentifier public const string SINGLE_REQUIRED_METHOD = 'symfony.singleRequiredMethod'; - public const string SYMFONY_REQUIRED_ONLY_IN_ABSTRACT = 'symfony.requiredOnlyInAbstract'; - public const string NO_CONSTRUCT_AND_REQUIRED = 'symfony.noConstructAndRequired'; public const string FORM_TYPE_CLASS_NAME = 'symfony.formTypeClassName'; diff --git a/src/Rules/Symfony/RequiredOnlyInAbstractRule.php b/src/Rules/Symfony/RequiredOnlyInAbstractRule.php deleted file mode 100644 index 80dbed79b..000000000 --- a/src/Rules/Symfony/RequiredOnlyInAbstractRule.php +++ /dev/null @@ -1,105 +0,0 @@ - - */ -final class RequiredOnlyInAbstractRule implements Rule -{ - public const string ERROR_MESSAGE = '#Symfony @required or #[Required] is reserved exclusively for abstract classes. For the rest of classes, use clean constructor injection'; - - /** - * Magic parent types that require constructor internally, - * so @required on final class is allowed - * - * @var string[] - */ - private const array SKIPPED_PARENT_TYPES = [ - DoctrineClass::DOCUMENT_REPOSITORY, - ]; - - public function getNodeType(): string - { - return InClassNode::class; - } - - /** - * @param InClassNode $node - */ - public function processNode(Node $node, Scope $scope): array - { - $classLike = $node->getOriginalNode(); - if (! $classLike instanceof Class_) { - return []; - } - - if ($this->shouldSkipClass($scope)) { - return []; - } - - $class = $classLike; - foreach ($class->getMethods() as $classMethod) { - if (! SymfonyRequiredMethodAnalyzer::detect($classMethod)) { - continue; - } - - if ($this->hasCircularDocNote($classMethod)) { - continue; - } - - if ($class->isAbstract()) { - continue; - } - - $identifierRuleError = RuleErrorBuilder::message(self::ERROR_MESSAGE) - ->line($classMethod->getLine()) - ->identifier(SymfonyRuleIdentifier::SYMFONY_REQUIRED_ONLY_IN_ABSTRACT) - ->build(); - - return [$identifierRuleError]; - } - - return []; - } - - private function shouldSkipClass(Scope $scope): bool - { - $classReflection = $scope->getClassReflection(); - if (! $classReflection instanceof ClassReflection) { - return false; - } - - if ($classReflection->isAbstract()) { - return true; - } - - return array_any(self::SKIPPED_PARENT_TYPES, fn (string $skippedParentType): bool => $classReflection->is($skippedParentType)); - } - - private function hasCircularDocNote(Node $node): bool - { - $docComment = $node->getDocComment(); - if (! $docComment instanceof Doc) { - return false; - } - - return str_contains($docComment->getText(), 'circular'); - } -} diff --git a/tests/Rules/Symfony/RequiredOnlyInAbstractRule/Fixture/NonAbstractControllerWithRequired.php b/tests/Rules/Symfony/RequiredOnlyInAbstractRule/Fixture/NonAbstractControllerWithRequired.php deleted file mode 100644 index 2a3151faf..000000000 --- a/tests/Rules/Symfony/RequiredOnlyInAbstractRule/Fixture/NonAbstractControllerWithRequired.php +++ /dev/null @@ -1,15 +0,0 @@ -> $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/NonAbstractControllerWithRequired.php', [[ - RequiredOnlyInAbstractRule::ERROR_MESSAGE, - 12, - ]]]; - - yield [__DIR__ . '/Fixture/SkipCircularNote.php', []]; - yield [__DIR__ . '/Fixture/SkipAbstractClass.php', []]; - yield [__DIR__ . '/Fixture/SkipParentDocumentRepository.php', []]; - } - - protected function getRule(): Rule - { - return new RequiredOnlyInAbstractRule(); - } -}