File tree Expand file tree Collapse file tree 8 files changed +257
-0
lines changed
tests/Rules/LiveComponent/LiveListenerMethodsShouldBePublicRule Expand file tree Collapse file tree 8 files changed +257
-0
lines changed Original file line number Diff line number Diff line change @@ -92,6 +92,68 @@ final class TodoList
9292
9393<br >
9494
95+ ### LiveListenerMethodsShouldBePublicRule
96+
97+ Enforces that all methods annotated with ` #[LiveListener] ` in LiveComponents must be declared as public.
98+ LiveListener methods need to be publicly accessible to be invoked when listening to events from the frontend.
99+
100+ ``` yaml
101+ rules :
102+ - Kocal\PHPStanSymfonyUX\Rules\LiveComponent\LiveListenerMethodsShouldBePublicRule
103+ ` ` `
104+
105+ ` ` ` php
106+ // src/Twig/Components/Notification.php
107+ namespace App\Twig\Components;
108+
109+ use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
110+ use Symfony\UX\LiveComponent\Attribute\LiveListener;
111+
112+ # [AsLiveComponent]
113+ final class Notification
114+ {
115+ # [LiveListener('notification:received')]
116+ private function onNotificationReceived() : void
117+ {
118+ }
119+
120+ # [LiveListener('notification:dismissed')]
121+ protected function onNotificationDismissed() : void
122+ {
123+ }
124+ }
125+ ```
126+
127+ :x :
128+
129+ <br >
130+
131+ ``` php
132+ // src/Twig/Components/Notification.php
133+ namespace App\Twig\Components;
134+
135+ use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
136+ use Symfony\UX\LiveComponent\Attribute\LiveListener;
137+
138+ #[AsLiveComponent]
139+ final class Notification
140+ {
141+ #[LiveListener('notification:received')]
142+ public function onNotificationReceived(): void
143+ {
144+ }
145+
146+ #[LiveListener('notification:dismissed')]
147+ public function onNotificationDismissed(): void
148+ {
149+ }
150+ }
151+ ```
152+
153+ :+1 :
154+
155+ <br >
156+
95157## TwigComponent Rules
96158
97159> [ !NOTE]
Original file line number Diff line number Diff line change 1+ <?php
2+
3+ declare (strict_types=1 );
4+
5+ namespace Kocal \PHPStanSymfonyUX \Rules \LiveComponent ;
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 \LiveComponent \Attribute \LiveListener ;
15+
16+ /**
17+ * @implements Rule<Class_>
18+ */
19+ final class LiveListenerMethodsShouldBePublicRule 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 , [AsLiveComponent::class])) {
29+ return [];
30+ }
31+
32+ $ errors = [];
33+
34+ foreach ($ node ->getMethods () as $ method ) {
35+ if (! AttributeFinder::findAnyAttribute ($ method , [LiveListener::class])) {
36+ continue ;
37+ }
38+
39+ if (! $ method ->isPublic ()) {
40+ $ errors [] = RuleErrorBuilder::message (sprintf (
41+ 'LiveListener method "%s()" should be public. ' ,
42+ $ method ->name ->toString ()
43+ ))
44+ ->identifier ('symfonyUX.liveComponent.liveListenerMethodShouldBePublic ' )
45+ ->line ($ method ->getLine ())
46+ ->tip ('Change the method visibility to public. ' )
47+ ->build ();
48+ }
49+ }
50+
51+ return $ errors ;
52+ }
53+ }
Original file line number Diff line number Diff line change 1+ <?php
2+
3+ declare (strict_types=1 );
4+
5+ namespace Kocal \PHPStanSymfonyUX \Tests \Rules \LiveComponent \LiveListenerMethodsShouldBePublicRule \Fixture ;
6+
7+ use Symfony \UX \LiveComponent \Attribute \AsLiveComponent ;
8+
9+ #[AsLiveComponent]
10+ final class NoLiveListener
11+ {
12+ protected function someProtectedMethod (): void
13+ {
14+ }
15+
16+ private function somePrivateMethod (): void
17+ {
18+ }
19+ }
Original file line number Diff line number Diff line change 1+ <?php
2+
3+ declare (strict_types=1 );
4+
5+ namespace Kocal \PHPStanSymfonyUX \Tests \Rules \LiveComponent \LiveListenerMethodsShouldBePublicRule \Fixture ;
6+
7+ use Symfony \UX \LiveComponent \Attribute \LiveListener ;
8+
9+ final class NotAComponent
10+ {
11+ #[LiveListener('some.event ' )]
12+ private function onSomeEvent (): void
13+ {
14+ }
15+ }
Original file line number Diff line number Diff line change 1+ <?php
2+
3+ declare (strict_types=1 );
4+
5+ namespace Kocal \PHPStanSymfonyUX \Tests \Rules \LiveComponent \LiveListenerMethodsShouldBePublicRule \Fixture ;
6+
7+ use Symfony \UX \LiveComponent \Attribute \AsLiveComponent ;
8+ use Symfony \UX \LiveComponent \Attribute \LiveListener ;
9+
10+ #[AsLiveComponent]
11+ final class PrivateLiveListener
12+ {
13+ #[LiveListener('another.event ' )]
14+ protected function onAnotherEvent (): void
15+ {
16+ }
17+
18+ #[LiveListener('some.event ' )]
19+ private function onSomeEvent (): void
20+ {
21+ }
22+ }
Original file line number Diff line number Diff line change 1+ <?php
2+
3+ declare (strict_types=1 );
4+
5+ namespace Kocal \PHPStanSymfonyUX \Tests \Rules \LiveComponent \LiveListenerMethodsShouldBePublicRule \Fixture ;
6+
7+ use Symfony \UX \LiveComponent \Attribute \AsLiveComponent ;
8+ use Symfony \UX \LiveComponent \Attribute \LiveListener ;
9+
10+ #[AsLiveComponent]
11+ final class PublicLiveListener
12+ {
13+ #[LiveListener('some.event ' )]
14+ public function onSomeEvent (): void
15+ {
16+ }
17+
18+ #[LiveListener('another.event ' )]
19+ public function onAnotherEvent (): void
20+ {
21+ }
22+ }
Original file line number Diff line number Diff line change 1+ <?php
2+
3+ declare (strict_types=1 );
4+
5+ namespace Kocal \PHPStanSymfonyUX \Tests \Rules \LiveComponent \LiveListenerMethodsShouldBePublicRule ;
6+
7+ use Kocal \PHPStanSymfonyUX \Rules \LiveComponent \LiveListenerMethodsShouldBePublicRule ;
8+ use PHPStan \Rules \Rule ;
9+ use PHPStan \Testing \RuleTestCase ;
10+
11+ /**
12+ * @extends RuleTestCase<LiveListenerMethodsShouldBePublicRule>
13+ */
14+ final class LiveListenerMethodsShouldBePublicRuleTest extends RuleTestCase
15+ {
16+ public function testViolations (): void
17+ {
18+ $ this ->analyse (
19+ [__DIR__ . '/Fixture/PrivateLiveListener.php ' ],
20+ [
21+ [
22+ 'LiveListener method "onAnotherEvent()" should be public. ' ,
23+ 13 ,
24+ 'Change the method visibility to public. ' ,
25+ ],
26+ [
27+ 'LiveListener method "onSomeEvent()" should be public. ' ,
28+ 18 ,
29+ 'Change the method visibility to public. ' ,
30+ ],
31+ ]
32+ );
33+ }
34+
35+ public function testNoViolations (): void
36+ {
37+ $ this ->analyse (
38+ [__DIR__ . '/Fixture/NotAComponent.php ' ],
39+ []
40+ );
41+
42+ $ this ->analyse (
43+ [__DIR__ . '/Fixture/PublicLiveListener.php ' ],
44+ []
45+ );
46+
47+ $ this ->analyse (
48+ [__DIR__ . '/Fixture/NoLiveListener.php ' ],
49+ []
50+ );
51+ }
52+
53+ public static function getAdditionalConfigFiles (): array
54+ {
55+ return [__DIR__ . '/config/configured_rule.neon ' ];
56+ }
57+
58+ protected function getRule (): Rule
59+ {
60+ return self ::getContainer ()->getByType (LiveListenerMethodsShouldBePublicRule::class);
61+ }
62+ }
Original file line number Diff line number Diff line change 1+ rules :
2+ - Kocal\PHPStanSymfonyUX\Rules\LiveComponent\LiveListenerMethodsShouldBePublicRule
You can’t perform that action at this time.
0 commit comments