Skip to content

Commit 4b52686

Browse files
committed
Add MethodsShouldBePublicOrPrivateRule
1 parent 45580c1 commit 4b52686

File tree

11 files changed

+228
-0
lines changed

11 files changed

+228
-0
lines changed

README.md

1.07 KB
Binary file not shown.

ecs.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
declare(strict_types=1);
44

5+
use PhpCsFixer\Fixer\ClassNotation\ProtectedToPrivateFixer;
56
use Symplify\EasyCodingStandard\Config\ECSConfig;
67

78
return ECSConfig::configure()
@@ -11,4 +12,9 @@
1112
])
1213
->withRootFiles()
1314
->withPreparedSets(psr12: true, common: true)
15+
->withSkip([
16+
ProtectedToPrivateFixer::class => [
17+
__DIR__ . '/tests/Rules/TwigComponent/MethodsShouldBePublicOrPrivateRule/Fixture/*',
18+
],
19+
])
1420
;

phpstan-baseline.neon

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,15 @@ parameters:
1111
identifier: property.unused
1212
count: 1
1313
path: tests/Rules/TwigComponent/PublicPropertiesShouldBeCamelCaseRule/Fixture/ComponentWithPrivateNonCamelCaseProperties.php
14+
15+
-
16+
message: '#^Method Kocal\\PHPStanSymfonyUX\\Tests\\Rules\\TwigComponent\\MethodsShouldBePublicOrPrivateRule\\Fixture\\ComponentWithPublicAndPrivateMethods\:\:privateMethod\(\) is unused\.$#'
17+
identifier: method.unused
18+
count: 1
19+
path: tests/Rules/TwigComponent/MethodsShouldBePublicOrPrivateRule/Fixture/ComponentWithPublicAndPrivateMethods.php
20+
21+
-
22+
message: '#^Method Kocal\\PHPStanSymfonyUX\\Tests\\Rules\\TwigComponent\\MethodsShouldBePublicOrPrivateRule\\Fixture\\LiveComponentWithPublicAndPrivateMethods\:\:privateMethod\(\) is unused\.$#'
23+
identifier: method.unused
24+
count: 1
25+
path: tests/Rules/TwigComponent/MethodsShouldBePublicOrPrivateRule/Fixture/LiveComponentWithPublicAndPrivateMethods.php
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 Kocal\PHPStanSymfonyUX\Rules\TwigComponent;
6+
7+
use Kocal\PHPStanSymfonyUX\NodeAnalyzer\AttributeFinder;
8+
use PhpParser\Node;
9+
use PhpParser\Node\Stmt\Class_;
10+
use PHPStan\Analyser\Scope;
11+
use PHPStan\Rules\Rule;
12+
use PHPStan\Rules\RuleErrorBuilder;
13+
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
14+
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
15+
16+
/**
17+
* @implements Rule<Class_>
18+
*/
19+
final class MethodsShouldBePublicOrPrivateRule implements Rule
20+
{
21+
public function getNodeType(): string
22+
{
23+
return Class_::class;
24+
}
25+
26+
public function processNode(Node $node, Scope $scope): array
27+
{
28+
if (! AttributeFinder::findAnyAttribute($node, [AsTwigComponent::class, AsLiveComponent::class])) {
29+
return [];
30+
}
31+
32+
$errors = [];
33+
34+
foreach ($node->getMethods() as $method) {
35+
if ($method->isProtected()) {
36+
$methodName = $method->name->toString();
37+
38+
$errors[] = RuleErrorBuilder::message(
39+
sprintf('Method "%s()" in a Twig component should not be protected.', $methodName)
40+
)
41+
->identifier('symfonyUX.twigComponent.methodsShouldBePublicOrPrivate')
42+
->line($method->getLine())
43+
->tip('Twig component methods should be either public or private, not protected.')
44+
->build();
45+
}
46+
}
47+
48+
return $errors;
49+
}
50+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kocal\PHPStanSymfonyUX\Tests\Rules\TwigComponent\MethodsShouldBePublicOrPrivateRule\Fixture;
6+
7+
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
8+
9+
#[AsTwigComponent]
10+
final class ComponentWithProtectedMethod
11+
{
12+
public string $name = '';
13+
14+
protected function protectedMethod(): void
15+
{
16+
}
17+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kocal\PHPStanSymfonyUX\Tests\Rules\TwigComponent\MethodsShouldBePublicOrPrivateRule\Fixture;
6+
7+
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
8+
9+
#[AsTwigComponent]
10+
final class ComponentWithPublicAndPrivateMethods
11+
{
12+
public string $name = '';
13+
14+
public function publicMethod(): void
15+
{
16+
}
17+
18+
private function privateMethod(): void
19+
{
20+
}
21+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kocal\PHPStanSymfonyUX\Tests\Rules\TwigComponent\MethodsShouldBePublicOrPrivateRule\Fixture;
6+
7+
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
8+
9+
#[AsLiveComponent]
10+
final class LiveComponentWithProtectedMethod
11+
{
12+
public string $name = '';
13+
14+
protected function protectedMethod(): void
15+
{
16+
}
17+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kocal\PHPStanSymfonyUX\Tests\Rules\TwigComponent\MethodsShouldBePublicOrPrivateRule\Fixture;
6+
7+
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
8+
9+
#[AsLiveComponent]
10+
final class LiveComponentWithPublicAndPrivateMethods
11+
{
12+
public string $name = '';
13+
14+
public function publicMethod(): void
15+
{
16+
}
17+
18+
private function privateMethod(): void
19+
{
20+
}
21+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kocal\PHPStanSymfonyUX\Tests\Rules\TwigComponent\MethodsShouldBePublicOrPrivateRule\Fixture;
6+
7+
final class NotAComponent
8+
{
9+
public string $name = '';
10+
11+
protected function protectedMethod(): void
12+
{
13+
}
14+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kocal\PHPStanSymfonyUX\Tests\Rules\TwigComponent\MethodsShouldBePublicOrPrivateRule;
6+
7+
use Kocal\PHPStanSymfonyUX\Rules\TwigComponent\MethodsShouldBePublicOrPrivateRule;
8+
use PHPStan\Rules\Rule;
9+
use PHPStan\Testing\RuleTestCase;
10+
11+
/**
12+
* @extends RuleTestCase<MethodsShouldBePublicOrPrivateRule>
13+
*/
14+
final class MethodsShouldBePublicOrPrivateRuleTest extends RuleTestCase
15+
{
16+
public function testViolations(): void
17+
{
18+
$this->analyse(
19+
[__DIR__ . '/Fixture/ComponentWithProtectedMethod.php'],
20+
[
21+
[
22+
'Method "protectedMethod()" in a Twig component should not be protected.',
23+
14,
24+
'Twig component methods should be either public or private, not protected.',
25+
],
26+
]
27+
);
28+
29+
$this->analyse(
30+
[__DIR__ . '/Fixture/LiveComponentWithProtectedMethod.php'],
31+
[
32+
[
33+
'Method "protectedMethod()" in a Twig component should not be protected.',
34+
14,
35+
'Twig component methods should be either public or private, not protected.',
36+
],
37+
]
38+
);
39+
}
40+
41+
public function testNoViolations(): void
42+
{
43+
$this->analyse(
44+
[__DIR__ . '/Fixture/NotAComponent.php'],
45+
[]
46+
);
47+
48+
$this->analyse(
49+
[__DIR__ . '/Fixture/ComponentWithPublicAndPrivateMethods.php'],
50+
[]
51+
);
52+
53+
$this->analyse(
54+
[__DIR__ . '/Fixture/LiveComponentWithPublicAndPrivateMethods.php'],
55+
[]
56+
);
57+
}
58+
59+
public static function getAdditionalConfigFiles(): array
60+
{
61+
return [__DIR__ . '/config/configured_rule.neon'];
62+
}
63+
64+
protected function getRule(): Rule
65+
{
66+
return self::getContainer()->getByType(MethodsShouldBePublicOrPrivateRule::class);
67+
}
68+
}

0 commit comments

Comments
 (0)