Skip to content

Commit

Permalink
use rule identifiers
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Dec 18, 2024
1 parent 5edccce commit 48bf682
Show file tree
Hide file tree
Showing 27 changed files with 134 additions and 71 deletions.
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,28 @@ final class SomeClass

<br>

## 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);
}
}
```


<!-- ruledoc-end -->

<br>
Expand Down
1 change: 0 additions & 1 deletion composer-dependency-analyser.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
return (new Configuration())->addPathToScan(__DIR__ . '/src', false)
->addPathToExclude(__DIR__ . '/tests/Rules/Rector/NoInstanceOfStaticReflectionRule/Fixture')
->addPathToExclude(__DIR__ . '/tests/Rules/Enum/RequireUniqueEnumConstantRule/Fixture')
->addPathToExclude(__DIR__ . '/tests/Rules/NoReturnArrayVariableListRule/Fixture')
->addPathToExclude(__DIR__ . '/tests/Rules/ForbiddenExtendOfNonAbstractClassRule/Fixture')
->addPathToExclude(__DIR__ . '/tests/Rules/PHPUnit/NoTestMocksRule/Fixture')

Expand Down
3 changes: 3 additions & 0 deletions config/services/services.neon
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ services:
- Symplify\PHPStanRules\PhpDoc\BarePhpDocParser
- Symplify\PHPStanRules\PhpDoc\PhpDocResolver
- Symplify\PHPStanRules\TypeAnalyzer\CallableTypeAnalyzer

# doctrine
- Symplify\PHPStanRules\Doctrine\DoctrineEntityDocumentAnalyser
2 changes: 1 addition & 1 deletion src/Doctrine/DoctrineEntityDocumentAnalyser.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Symplify\PHPStanRules\PHPStan;
namespace Symplify\PHPStanRules\Doctrine;

use PHPStan\PhpDoc\ResolvedPhpDocBlock;
use PHPStan\Reflection\ClassReflection;
Expand Down
2 changes: 1 addition & 1 deletion src/Enum/ClassName.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ final class ClassName
/**
* @var string
*/
public const EVENT_DISPATCHER_INTERFACE = 'Symfony\Component\EventDispatcher\EventSubscriberInterface';
public const EVENT_DISPATCHER_INTERFACE = 'Symfony\Component\EventDispatcher\EventDispatcherInterface';

/**
* @var string
Expand Down
22 changes: 22 additions & 0 deletions src/Enum/RuleIdentifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,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';
}
18 changes: 10 additions & 8 deletions src/PHPStan/Rules/Doctrine/NoGetRepositoryOutsideServiceRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<MethodCall>
*/
Expand All @@ -34,7 +31,6 @@ public function getNodeType(): string

/**
* @param MethodCall $node
* @return RuleError[]
*/
public function processNode(Node $node, Scope $scope): array
{
Expand All @@ -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];
}

Expand All @@ -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];
}
}
8 changes: 4 additions & 4 deletions src/PHPStan/Rules/Doctrine/NoParentRepositoryRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -39,7 +39,6 @@ public function getNodeType(): string

/**
* @param Class_ $node
* @return RuleError[]
*/
public function processNode(Node $node, Scope $scope): array
{
Expand All @@ -52,9 +51,10 @@ public function processNode(Node $node, Scope $scope): array
return [];
}

$ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)
$identifierRuleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)
->identifier(RuleIdentifier::DOCTRINE_NO_PARENT_REPOSITORY)
->build();

return [$ruleError];
return [$identifierRuleError];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ public function processNode(Node $node, Scope $scope): array
return [];
}

$ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)
$identifierRuleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)
->identifier(RuleIdentifier::DOCTRINE_NO_REPOSITORY_CALL_IN_DATA_FIXTURES)
->build();

return [$ruleError];
return [$identifierRuleError];
}

private function isDataFixtureClass(Scope $scope): bool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 6 additions & 4 deletions src/Rules/Complexity/NoConstructorOverrideRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<ClassMethod>
Expand All @@ -35,7 +35,6 @@ public function getNodeType(): string

/**
* @param ClassMethod $node
* @return RuleError[]
*/
public function processNode(Node $node, Scope $scope): array
{
Expand Down Expand Up @@ -69,7 +68,10 @@ public function processNode(Node $node, Scope $scope): array
return [];
}

$ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)->build();
return [$ruleError];
$identifierRuleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)
->identifier(RuleIdentifier::NO_CONSTRUCTOR_OVERRIDE)
->build();

return [$identifierRuleError];
}
}
9 changes: 5 additions & 4 deletions src/Rules/Doctrine/NoEntityMockingRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\Rules\RuleErrorBuilder;
use Symplify\PHPStanRules\PHPStan\DoctrineEntityDocumentAnalyser;
use Symplify\PHPStanRules\Doctrine\DoctrineEntityDocumentAnalyser;
use Symplify\PHPStanRules\Enum\RuleIdentifier;

/**
* The ORM entities and ODM documents should never be mocked, as it leads to typeless code.
* Use them directly instead.
*
* @see \Symplify\PHPStanRules\Tests\PHPStan\Rule\NoEntityMockingRule\NoEntityMockingRuleTest
* @see \Symplify\PHPStanRules\Tests\Rules\PHPUnit\NoEntityMockingRule\NoEntityMockingRuleTest
*
* @implements Rule<MethodCall>
*/
final readonly class NoEntityMockingRule implements Rule
Expand All @@ -40,7 +41,6 @@ public function getNodeType(): string

/**
* @param MethodCall $node
* @return RuleError[]
*/
public function processNode(Node $node, Scope $scope): array
{
Expand All @@ -62,6 +62,7 @@ public function processNode(Node $node, Scope $scope): array
}

$ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)
->identifier(RuleIdentifier::NO_ENTITY_MOCKING)
->build();

return [$ruleError];
Expand Down
4 changes: 2 additions & 2 deletions src/Rules/NoDynamicNameRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@
*
* @implements Rule<Node>
*/
final class NoDynamicNameRule implements Rule
final readonly class NoDynamicNameRule implements Rule
{
/**
* @var string
*/
public const ERROR_MESSAGE = 'Use explicit names over dynamic ones';

public function __construct(
private readonly CallableTypeAnalyzer $callableTypeAnalyzer,
private CallableTypeAnalyzer $callableTypeAnalyzer,
) {
}

Expand Down
6 changes: 3 additions & 3 deletions src/Rules/NoReferenceRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@
/**
* @see \Symplify\PHPStanRules\Tests\Rules\NoReferenceRule\NoReferenceRuleTest
*
* @implements Rule<\PhpParser\Node>
* @implements Rule<Node>
*/
final class NoReferenceRule implements Rule
final readonly class NoReferenceRule implements Rule
{
/**
* @var string
*/
public const ERROR_MESSAGE = 'Use explicit return value over magic &reference';

public function __construct(
private readonly ParentClassMethodNodeResolver $parentClassMethodNodeResolver,
private ParentClassMethodNodeResolver $parentClassMethodNodeResolver,
) {
}

Expand Down
15 changes: 8 additions & 7 deletions src/Rules/PHPUnit/NoMockOnlyTestRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@

declare(strict_types=1);

namespace Symplify\PHPStanRules\PHPStan\Rule;
namespace Symplify\PHPStanRules\Rules\PHPUnit;

use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\Class_;
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;
use Symplify\PHPStanRules\Testing\PHPUnitTestAnalyser;

/**
* @see \Symplify\PHPStanRules\Tests\PHPStan\Rule\NoMockOnlyTestRule\NoMockOnlyTestRuleTest
* @see \Symplify\PHPStanRules\Tests\Rules\PHPUnit\NoMockOnlyTestRule\NoMockOnlyTestRuleTest
*
* @implements Rule<InClassNode>
*/
Expand All @@ -38,7 +38,6 @@ public function getNodeType(): string

/**
* @param InClassNode $node
* @return RuleError[]
*/
public function processNode(Node $node, Scope $scope): array
{
Expand Down Expand Up @@ -73,8 +72,10 @@ public function processNode(Node $node, Scope $scope): array
return [];
}

$ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)
$identifierRuleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)
->identifier(RuleIdentifier::PHPUNIT_NO_MOCK_ONLY)
->build();
return [$ruleError];

return [$identifierRuleError];
}
}
11 changes: 6 additions & 5 deletions src/Rules/PHPUnit/PublicStaticDataProviderRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

declare(strict_types=1);

namespace Symplify\PHPStanRules\PHPStan\Rule;
namespace Symplify\PHPStanRules\Rules\PHPUnit;

use PhpParser\Node;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Analyser\Scope;
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;
use Symplify\PHPStanRules\Testing\PHPUnitTestAnalyser;

/**
* PHPUnit data provider have to be public and static
Expand Down Expand Up @@ -50,7 +51,7 @@ public function processNode(Node $node, Scope $scope): array

$classLike = $node->getOriginalNode();
foreach ($classLike->getMethods() as $classMethod) {
if (! PHPUnitTestAnalyser::isTestClassMethod($classMethod)) {
if (! PHPUnitTestAnalyser::class::isTestClassMethod($classMethod)) {
continue;
}

Expand All @@ -75,7 +76,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();
}
Expand Down
Loading

0 comments on commit 48bf682

Please sign in to comment.