88use PHPStan \Analyser \Scope ;
99use PHPStan \Broker \Broker ;
1010use PHPStan \Reflection \ClassReflection ;
11+ use PHPStan \Reflection \ReflectionProvider ;
1112use PHPStan \Rules \Rule ;
1213use PHPStan \Type \TypeWithClassName ;
1314use PHPStan \Type \VerbosityLevel ;
1718 */
1819class SetValueMethodRule implements Rule
1920{
20- /** @var Broker */
21- private $ broker ;
21+ /** @var ReflectionProvider */
22+ private $ reflectionProvider ;
2223
2324
24- public function __construct (Broker $ broker )
25+ public function __construct (ReflectionProvider $ reflectionProvider )
2526{
26- $ this ->broker = $ broker ;
27+ $ this ->reflectionProvider = $ reflectionProvider ;
2728}
2829
2930
@@ -48,36 +49,46 @@ public function processNode(Node $node, Scope $scope): array
4849if (!in_array ($ methodName , ['setValue ' , 'setReadOnlyValue ' ], true )) {
4950return [];
5051}
52+
5153$ args = $ node ->args ;
5254if (!isset ($ args [0 ], $ args [1 ])) {
5355return [];
5456}
57+ if (!$ args [0 ] instanceof Node \Arg || !$ args [1 ] instanceof Node \Arg) {
58+ return [];
59+ }
60+
5561$ valueType = $ scope ->getType ($ args [1 ]->value );
5662$ varType = $ scope ->getType ($ node ->var );
5763if (!$ varType instanceof TypeWithClassName) {
5864return [];
5965}
66+
6067$ firstValue = $ args [0 ]->value ;
6168if (!$ firstValue instanceof Node \Scalar \String_) {
6269return [];
6370}
71+
6472$ fieldName = $ firstValue ->value ;
65- $ class = $ this ->broker ->getClass ($ varType ->getClassName ());
73+ $ class = $ this ->reflectionProvider ->getClass ($ varType ->getClassName ());
6674$ interfaces = array_map (function (ClassReflection $ interface ) {
6775return $ interface ->getName ();
6876}, $ class ->getInterfaces ());
6977if (!in_array (IEntity::class, $ interfaces , true )) {
7078return [];
7179}
80+
7281if (!$ class ->hasProperty ($ fieldName )) {
7382return [sprintf (
7483'Entity %s has no $%s property. ' ,
7584$ varType ->getClassName (),
7685$ fieldName
7786)];
7887}
88+
7989$ property = $ class ->getProperty ($ fieldName , $ scope );
8090$ propertyType = $ property ->getWritableType ();
91+
8192if (!$ propertyType ->accepts ($ valueType , true )->yes ()) {
8293return [sprintf (
8394'Entity %s: property $%s (%s) does not accept %s. ' ,
@@ -87,13 +98,15 @@ public function processNode(Node $node, Scope $scope): array
8798$ valueType ->describe (VerbosityLevel::typeOnly ())
8899)];
89100}
101+
90102if (!$ property ->isWritable () && $ methodName !== 'setReadOnlyValue ' ) {
91103return [sprintf (
92104'Entity %s: property $%s is read-only. ' ,
93105$ varType ->getClassName (),
94106$ fieldName
95107)];
96108}
109+
97110return [];
98111}
99112}
0 commit comments