99use PhpParser \Node \Stmt \Class_ ;
1010use PhpParser \Node \Stmt \ClassMethod ;
1111use PHPStan \Reflection \ClassReflection ;
12- use PHPStan \Type \ObjectType ;
13- use Rector \Php80 \NodeAnalyzer \PhpAttributeAnalyzer ;
1412use Rector \PhpParser \Node \BetterNodeFinder ;
1513use Rector \PHPStan \ScopeFetcher ;
14+ use Rector \Privatization \Guard \LaravelModelGuard ;
1615use Rector \Privatization \Guard \OverrideByParentClassGuard ;
1716use Rector \Privatization \NodeManipulator \VisibilityManipulator ;
1817use Rector \Privatization \VisibilityGuard \ClassMethodVisibilityGuard ;
1918use Rector \Rector \AbstractRector ;
20- use Rector \Util \StringUtils ;
2119use Symplify \RuleDocGenerator \ValueObject \CodeSample \CodeSample ;
2220use Symplify \RuleDocGenerator \ValueObject \RuleDefinition ;
2321
2624 */
2725final class PrivatizeFinalClassMethodRector extends AbstractRector
2826{
29- /**
30- * @var string
31- * @see https://regex101.com/r/Dx0WN5/2
32- */
33- private const LARAVEL_MODEL_ATTRIBUTE_REGEX = '/^[gs]et.+Attribute$/ ' ;
34-
35- /**
36- * @var string
37- * @see https://regex101.com/r/hxOGeN/2
38- */
39- private const LARAVEL_MODEL_SCOPE_REGEX = '/^scope.+$/ ' ;
40-
4127 public function __construct (
4228 private readonly ClassMethodVisibilityGuard $ classMethodVisibilityGuard ,
4329 private readonly VisibilityManipulator $ visibilityManipulator ,
4430 private readonly OverrideByParentClassGuard $ overrideByParentClassGuard ,
4531 private readonly BetterNodeFinder $ betterNodeFinder ,
46- private readonly PhpAttributeAnalyzer $ phpAttributeAnalyzer ,
32+ private readonly LaravelModelGuard $ laravelModelGuard ,
4733 ) {
4834 }
4935
@@ -105,7 +91,11 @@ public function refactor(Node $node): ?Node
10591 $ hasChanged = false ;
10692
10793 foreach ($ node ->getMethods () as $ classMethod ) {
108- if ($ this ->shouldSkipClassMethod ($ classReflection , $ classMethod )) {
94+ if ($ this ->shouldSkipClassMethod ($ classMethod )) {
95+ continue ;
96+ }
97+
98+ if ($ this ->laravelModelGuard ->isProtectedMethod ($ classReflection , $ classMethod )) {
10999 continue ;
110100 }
111101
@@ -134,7 +124,7 @@ public function refactor(Node $node): ?Node
134124 return null ;
135125 }
136126
137- private function shouldSkipClassMethod (ClassReflection $ classReflection , ClassMethod $ classMethod ): bool
127+ private function shouldSkipClassMethod (ClassMethod $ classMethod ): bool
138128 {
139129 // edge case in nette framework
140130 /** @var string $methodName */
@@ -151,10 +141,6 @@ private function shouldSkipClassMethod(ClassReflection $classReflection, ClassMe
151141 return true ;
152142 }
153143
154- if ($ this ->shouldSkipClassMethodLaravel ($ classReflection , $ classMethod )) {
155- return true ;
156- }
157-
158144 // if has parent call, its probably overriding parent one → skip it
159145 $ hasParentCall = (bool ) $ this ->betterNodeFinder ->findFirst (
160146 (array ) $ classMethod ->stmts ,
@@ -169,38 +155,4 @@ function (Node $node): bool {
169155
170156 return $ hasParentCall ;
171157 }
172-
173- private function shouldSkipClassMethodLaravel (ClassReflection $ classReflection , ClassMethod $ classMethod ): bool
174- {
175- if (! $ classReflection ->is ('Illuminate\Database\Eloquent\Model ' )) {
176- return false ;
177- }
178-
179- $ name = (string ) $ this ->getName ($ classMethod ->name );
180- $ returnType = $ classMethod ->returnType ;
181-
182- // Model attributes should be protected
183- if (
184- StringUtils::isMatch ($ name , self ::LARAVEL_MODEL_ATTRIBUTE_REGEX )
185- || ($ returnType instanceof Node && $ this ->isObjectType (
186- $ returnType ,
187- new ObjectType ('Illuminate\Database\Eloquent\Casts\Attribute ' )
188- ))
189- ) {
190- return true ;
191- }
192-
193- // Model scopes should be protected
194- if (
195- StringUtils::isMatch ($ name , self ::LARAVEL_MODEL_SCOPE_REGEX )
196- || $ this ->phpAttributeAnalyzer ->hasPhpAttribute (
197- $ classMethod ,
198- 'Illuminate\Database\Eloquent\Attributes\Scope '
199- )
200- ) {
201- return true ;
202- }
203-
204- return false ;
205- }
206158}
0 commit comments