Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add no getDoctrine() rule #159

Merged
merged 2 commits into from
Dec 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config/symfony-rules.neon
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ rules:
- Symplify\PHPStanRules\Rules\Symfony\NoListenerWithoutContractRule
- Symplify\PHPStanRules\Rules\Symfony\NoStringInGetSubscribedEventsRule
- Symplify\PHPStanRules\Rules\Symfony\RequireInvokableControllerRule

# dependency injection
- Symplify\PHPStanRules\Rules\Symfony\NoGetDoctrineInControllerRule
- Symplify\PHPStanRules\Rules\Symfony\NoGetInControllerRule
101 changes: 2 additions & 99 deletions src/Enum/RuleIdentifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,169 +6,70 @@

final class RuleIdentifier
{
/**
* @var string
*/
public const UPPERCASE_CONSTANT = 'symplify.uppercaseConstant';

/**
* @var string
*/
public const SEE_ANNOTATION_TO_TEST = 'symplify.seeAnnotationToTest';

/**
* @var string
*/
public const REQUIRE_ATTRIBUTE_NAME = 'symplify.requireAttributeName';

/**
* @var string
*/
public const RECTOR_PHP_RULE_IMPLEMENTS_MIN_VERSION = 'rector.phpRuleImplementsMinVersion';

/**
* @var string
*/
public const RECTOR_UPGRADE_DOWNGRADE_REGISTERED_IN_SET = 'rector.upgradeDowngradeRegisteredInSet';

/**
* @var string
*/
public const PHP_PARSER_NO_LEADING_BACKSLASH_IN_NAME = 'phpParser.noLeadingBackslashInName';

/**
* @var string
*/
public const RECTOR_NO_INSTANCE_OF_STATIC_REFLECTION = 'rector.noInstanceOfStaticReflection';

/**
* @var string
*/
public const RECTOR_NO_CLASS_REFLECTION_STATIC_REFLECTION = 'rector.noClassReflectionStaticReflection';

/**
* @var string
*/
public const PARENT_METHOD_VISIBILITY_OVERRIDE = 'symplify.parentMethodVisibilityOverride';

/**
* @var string
*/
public const NO_RETURN_SETTER_METHOD = 'symplify.noReturnSetterMethod';

/**
* @var string
*/
public const FORBIDDEN_STATIC_CLASS_CONST_FETCH = 'symplify.forbiddenStaticClassConstFetch';

/**
* @var string
*/
public const PREFERRED_CLASS = 'symplify.preferredClass';

/**
* @var string
*/
public const NO_TEST_MOCKS = 'symplify.noTestMocks';

/**
* @var string
*/
public const NO_GLOBAL_CONST = 'symplify.noGlobalConst';

/**
* @var string
*/
public const NO_ENTITY_OUTSIDE_ENTITY_NAMESPACE = 'symplify.noEntityOutsideEntityNamespace';

/**
* @var string
*/
public const FORBIDDEN_NODE = 'symplify.forbiddenNode';

/**
* @var string
*/
public const MULTIPLE_CLASS_LIKE_IN_FILE = 'symplify.multipleClassLikeInFile';

/**
* @var string
*/
public const FORBIDDEN_FUNC_CALL = 'symplify.forbiddenFuncCall';

/**
* @var string
*/
public const REQUIRE_ATTRIBUTE_NAMESPACE = 'symplify.requireAttributeNamespace';

/**
* @var string
*/
public const FORBIDDEN_ARRAY_METHOD_CALL = 'symplify.forbiddenArrayMethodCall';

/**
* @var string
*/
public const FORBIDDEN_EXTEND_OF_NON_ABSTRACT_CLASS = 'symplify.forbiddenExtendOfNonAbstractClass';

/**
* @var string
*/
public const EXPLICIT_ABSTRACT_PREFIX_NAME = 'symplify.explicitAbstractPrefixName';

/**
* @var string
*/
public const EXPLICIT_INTERFACE_SUFFIX_NAME = 'symplify.explicitInterfaceSuffixName';

/**
* @var string
*/
public const EXPLICIT_TRAIT_SUFFIX_NAME = 'symplify.explicitTraitSuffixName';

/**
* @var string
*/
public const REQUIRE_UNIQUE_ENUM_CONSTANT = 'symplify.requireUniqueEnumConstant';

/**
* @var string
*/
public const REQUIRE_EXCEPTION_NAMESPACE = 'symplify.requireExceptionNamespace';

/**
* @var string
*/
public const CLASS_NAME_RESPECTS_PARENT_SUFFIX = 'symplify.classNameRespectsParentSuffix';

/**
* @var string
*/
public const REQUIRED_INTERFACE_CONTRACT_NAMESPACE = 'symplify.requiredInterfaceContractNamespace';

/**
* @var string
*/
public const SYMFONY_REQUIRE_INVOKABLE_CONTROLLER = 'symfony.requireInvokableController';

/**
* @var string
*/
public const NO_VALUE_OBJECT_IN_SERVICE_CONSTRUCTOR = 'symplify.noValueObjectInServiceConstructor';

/**
* @var string
*/
public const DOCTRINE_NO_REPOSITORY_CALL_IN_DATA_FIXTURES = 'doctrine.noRepositoryCallInDataFixtures';

/**
* @var string
*/
public const PHPUNIT_NO_DOCUMENT_MOCKING = 'phpunit.noDocumentMocking';

/**
* @var string
*/
public const NO_DYNAMIC_NAME = 'symplify.noDynamicName';

public const NO_REFERENCE = 'symplify.noReference';
Expand Down Expand Up @@ -200,4 +101,6 @@ final class RuleIdentifier
public const REQUIRE_QUERY_BUILDER_ON_REPOSITORY = 'doctrine.requireQueryBuilderOnRepository';

public const NO_GET_IN_CONTROLLER = 'symfony.noGetInController';

public const NO_GET_DOCTRINE_IN_CONTROLLER = 'symfony.noGetDoctrineInController';
}
34 changes: 34 additions & 0 deletions src/NodeAnalyzer/MethodCallNameAnalyzer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace Symplify\PHPStanRules\NodeAnalyzer;

use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;

final class MethodCallNameAnalyzer
{
public static function isThisMethodCall(MethodCall $methodCall, string $methodName): bool
{
if (! $methodCall->name instanceof Identifier) {
return false;
}

if ($methodCall->name->toString() !== $methodName) {
return false;
}

// is "$this"?
if (! $methodCall->var instanceof Variable) {
return false;
}

if (! is_string($methodCall->var->name)) {
return false;
}

return $methodCall->var->name === 'this';
}
}
17 changes: 2 additions & 15 deletions src/Rules/Doctrine/NoEntityMockingRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use PHPStan\Rules\RuleErrorBuilder;
use Symplify\PHPStanRules\Doctrine\DoctrineEntityDocumentAnalyser;
use Symplify\PHPStanRules\Enum\RuleIdentifier;
use Symplify\PHPStanRules\NodeAnalyzer\MethodCallNameAnalyzer;

/**
* The ORM entities and ODM documents should never be mocked, as it leads to typeless code.
Expand Down Expand Up @@ -44,7 +45,7 @@ public function getNodeType(): string
*/
public function processNode(Node $node, Scope $scope): array
{
if (! $this->isCreateMockMethod($node)) {
if (! MethodCallNameAnalyzer::isThisMethodCall($node, 'createMock')) {
return [];
}

Expand All @@ -70,18 +71,4 @@ public function processNode(Node $node, Scope $scope): array

return [];
}

private function isCreateMockMethod(MethodCall $methodCall): bool
{
if ($methodCall->isFirstClassCallable()) {
return false;
}

if (! $methodCall->name instanceof Identifier) {
return false;
}

$methodName = $methodCall->name->toString();
return $methodName === 'createMock';
}
}
2 changes: 1 addition & 1 deletion src/Rules/Symfony/NoAbstractControllerConstructorRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* Check if abstract controller has constructor, as it should use
* #[Require] instead to avoid parent constructor override
*
* @see \Symplify\PHPStanRules\Tests\PHPStan\Rule\NoAbstractControllerConstructorRule\NoAbstractControllerConstructorRuleTest
* @see \Symplify\PHPStanRules\Tests\Rules\Symfony\NoAbstractControllerConstructorRule\NoAbstractControllerConstructorRuleTest
*
* @implements Rule<Class_>
*/
Expand Down
52 changes: 52 additions & 0 deletions src/Rules/Symfony/NoGetDoctrineInControllerRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

declare(strict_types=1);

namespace Symplify\PHPStanRules\Rules\Symfony;

use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use Symplify\PHPStanRules\Enum\RuleIdentifier;
use Symplify\PHPStanRules\NodeAnalyzer\MethodCallNameAnalyzer;
use Symplify\PHPStanRules\Symfony\NodeAnalyzer\SymfonyControllerAnalyzer;

/**
* @implements Rule<MethodCall>
*/
final class NoGetDoctrineInControllerRule implements Rule
{
/**
* @var string
*/
private const ERROR_MESSAGE = 'Do not use $this->getDoctrine() method in controller. Use __construct(EntityManagerInterface $entityManager) instead';

public function getNodeType(): string
{
return MethodCall::class;
}

/**
* @param MethodCall $node
*/
public function processNode(Node $node, Scope $scope): array
{
if (! MethodCallNameAnalyzer::isThisMethodCall($node, 'getDoctrine')) {
return [];
}

if (! SymfonyControllerAnalyzer::isControllerScope($scope)) {
return [];
}

$ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)
->file($scope->getFile())
->line($node->getStartLine())
->identifier(RuleIdentifier::NO_GET_DOCTRINE_IN_CONTROLLER)
->build();

return [$ruleError];
}
}
Loading
Loading