Skip to content

Commit 052e527

Browse files
authored
[symfony] Add NoGetInCommandRule (#184)
1 parent 55e005a commit 052e527

15 files changed

+159
-49
lines changed

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,6 +1379,19 @@ rules:
13791379
<br>
13801380

13811381

1382+
### NoGetInCommandRule
1383+
1384+
Prevents using `$this->get(...)` in commands, to promote dependency injection.
1385+
1386+
1387+
```yaml
1388+
rules:
1389+
- Symplify\PHPStanRules\Rules\Symfony\NoGetInCommandRule
1390+
```
1391+
1392+
<br>
1393+
1394+
13821395
### NoAbstractControllerConstructorRule
13831396

13841397
Abstract controller should not have constructor, as it can lead to tight coupling. Use @required annotation instead

config/symfony-rules.neon

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ rules:
1414
- Symplify\PHPStanRules\Rules\Symfony\RequireRouteNameToGenerateControllerRouteRule
1515

1616
# dependency injection
17-
- Symplify\PHPStanRules\Rules\Symfony\NoGetDoctrineInControllerRule
1817
- Symplify\PHPStanRules\Rules\Symfony\NoGetInControllerRule
18+
- Symplify\PHPStanRules\Rules\Symfony\NoGetInCommandRule
19+
- Symplify\PHPStanRules\Rules\Symfony\NoGetDoctrineInControllerRule
1920
- Symplify\PHPStanRules\Rules\Symfony\NoFindTaggedServiceIdsCallRule
2021

2122
# magic required inject

src/Enum/SymfonyClass.php

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,59 +6,30 @@
66

77
final class SymfonyClass
88
{
9-
/**
10-
* @var string
11-
*/
129
public const ROUTE_ATTRIBUTE = 'Symfony\Component\Routing\Attribute\Route';
1310

1411
/**
1512
* @api
16-
* @var string
1713
*/
1814
public const ROUTE_ANNOTATION = 'Symfony\Component\Routing\Annotation\Route';
1915

20-
/**
21-
* @var string
22-
*/
23-
public const SYMFONY_CONTROLLER = 'Symfony\Bundle\FrameworkBundle\Controller\Controller';
16+
public const CONTROLLER = 'Symfony\Bundle\FrameworkBundle\Controller\Controller';
2417

25-
/**
26-
* @var string
27-
*/
2818
public const REQUIRED_ATTRIBUTE = 'Symfony\Contracts\Service\Attribute\Required';
2919

30-
/**
31-
* @var string
32-
*/
33-
public const SYMFONY_ABSTRACT_CONTROLLER = 'Symfony\Bundle\FrameworkBundle\Controller\AbstractController';
20+
public const ABSTRACT_CONTROLLER = 'Symfony\Bundle\FrameworkBundle\Controller\AbstractController';
3421

35-
/**
36-
* @var string
37-
*/
3822
public const EVENT_SUBSCRIBER_INTERFACE = 'Symfony\Component\EventDispatcher\EventSubscriberInterface';
3923

40-
/**
41-
* @var string
42-
*/
4324
public const EVENT_DISPATCHER_INTERFACE = 'Symfony\Component\EventDispatcher\EventDispatcherInterface';
4425

45-
/**
46-
* @var string
47-
*/
4826
public const FORM_TYPE = 'Symfony\Component\Form\AbstractType';
4927

50-
/**
51-
* @var string
52-
*/
5328
public const ROUTE_IMPORT_CONFIGURATOR = 'Symfony\Component\Routing\Loader\Configurator\ImportConfigurator';
5429

55-
/**
56-
* @var string
57-
*/
5830
public const FORM_EVENTS = 'Symfony\Component\Form\FormEvents';
5931

60-
/**
61-
* @var string
62-
*/
6332
public const URL_GENERATOR = 'Symfony\Component\Routing\Generator\UrlGeneratorInterface';
33+
34+
public const COMMAND = 'Symfony\Component\Console\Command\Command';
6435
}

src/Enum/SymfonyRuleIdentifier.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ final class SymfonyRuleIdentifier
88
{
99
public const NO_GET_IN_CONTROLLER = 'symfony.noGetInController';
1010

11+
public const NO_GET_IN_COMMAND = 'symfony.noGetInCommand';
12+
1113
public const NO_GET_DOCTRINE_IN_CONTROLLER = 'symfony.noGetDoctrineInController';
1214

1315
public const SINGLE_ARG_EVENT_DISPATCH = 'symfony.singleArgEventDispatch';

src/Rules/ClassNameRespectsParentSuffixRule.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ final class ClassNameRespectsParentSuffixRule implements Rule
3434
* @var string[]
3535
*/
3636
private const DEFAULT_PARENT_CLASSES = [
37-
'Symfony\Component\Console\Command\Command',
37+
SymfonyClass::COMMAND,
3838
SymfonyClass::EVENT_SUBSCRIBER_INTERFACE,
39-
SymfonyClass::SYMFONY_ABSTRACT_CONTROLLER,
39+
SymfonyClass::ABSTRACT_CONTROLLER,
4040
ClassName::SNIFF,
4141
TestClassName::PHPUNIT_TEST_CASE,
4242
Exception::class,

src/Rules/Symfony/NoGetDoctrineInControllerRule.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,10 @@ public function processNode(Node $node, Scope $scope): array
4141
return [];
4242
}
4343

44-
$ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)
45-
->file($scope->getFile())
46-
->line($node->getStartLine())
44+
$identifierRuleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)
4745
->identifier(SymfonyRuleIdentifier::NO_GET_DOCTRINE_IN_CONTROLLER)
4846
->build();
4947

50-
return [$ruleError];
48+
return [$identifierRuleError];
5149
}
5250
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Symplify\PHPStanRules\Rules\Symfony;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr\MethodCall;
9+
use PHPStan\Analyser\Scope;
10+
use PHPStan\Rules\Rule;
11+
use PHPStan\Rules\RuleErrorBuilder;
12+
use Symplify\PHPStanRules\Enum\SymfonyRuleIdentifier;
13+
use Symplify\PHPStanRules\NodeAnalyzer\MethodCallNameAnalyzer;
14+
use Symplify\PHPStanRules\Symfony\NodeAnalyzer\SymfonyCommandAnalyzer;
15+
16+
/**
17+
* @implements Rule<MethodCall>
18+
*/
19+
final class NoGetInCommandRule implements Rule
20+
{
21+
/**
22+
* @var string
23+
*/
24+
public const ERROR_MESSAGE = 'Do not use $this->get(Type::class) method in commands to get services. Use __construct(Type $type) instead';
25+
26+
public function getNodeType(): string
27+
{
28+
return MethodCall::class;
29+
}
30+
31+
/**
32+
* @param MethodCall $node
33+
*/
34+
public function processNode(Node $node, Scope $scope): array
35+
{
36+
if (! MethodCallNameAnalyzer::isThisMethodCall($node, 'get')) {
37+
return [];
38+
}
39+
40+
if (! SymfonyCommandAnalyzer::isCommandScope($scope)) {
41+
return [];
42+
}
43+
44+
$identifierRuleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)
45+
->identifier(SymfonyRuleIdentifier::NO_GET_IN_COMMAND)
46+
->build();
47+
48+
return [$identifierRuleError];
49+
}
50+
}

src/Rules/Symfony/NoGetInControllerRule.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,10 @@ public function processNode(Node $node, Scope $scope): array
4141
return [];
4242
}
4343

44-
$ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)
45-
->file($scope->getFile())
46-
->line($node->getStartLine())
44+
$identifierRuleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)
4745
->identifier(SymfonyRuleIdentifier::NO_GET_IN_CONTROLLER)
4846
->build();
4947

50-
return [$ruleError];
48+
return [$identifierRuleError];
5149
}
5250
}

src/Rules/Symfony/NoRequiredOutsideClassRule.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ public function processNode(Node $node, Scope $scope): array
4242
}
4343

4444
$ruleErrors[] = RuleErrorBuilder::message(self::ERROR_MESSAGE)
45-
->file($scope->getFile())
4645
->identifier(SymfonyRuleIdentifier::SYMFONY_NO_REQUIRED_OUTSIDE_CLASS)
4746
->line($classMethod->getLine())
4847
->build();

src/Rules/Symfony/RequireInvokableControllerRule.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ public function processNode(Node $node, Scope $scope): array
4040
{
4141
$classReflection = $node->getClassReflection();
4242
if (
43-
! $classReflection->isSubclassOf(SymfonyClass::SYMFONY_ABSTRACT_CONTROLLER) &&
44-
! $classReflection->isSubclassOf(SymfonyClass::SYMFONY_CONTROLLER)
43+
! $classReflection->isSubclassOf(SymfonyClass::ABSTRACT_CONTROLLER) &&
44+
! $classReflection->isSubclassOf(SymfonyClass::CONTROLLER)
4545
) {
4646
return [];
4747
}

0 commit comments

Comments
 (0)