99 MissingPropertyFromReflectionException ,
1010 PropertiesClassReflectionExtension ,
1111 PropertyReflection ,
12+ ReflectionProvider ,
1213};
1314use PHPStan \Reflection \Annotations \AnnotationsPropertiesClassReflectionExtension ;
1415use PHPStan \Reflection \Dummy \DummyPropertyReflection ;
15- use PHPStan \Type \ObjectType ;
16+ use PHPStan \Type \Constant \ConstantBooleanType ;
17+ use PHPStan \Type \{IntegerType , NullType , ObjectType , StringType , TypeCombinator };
1618use yii \web \User ;
1719use yii2 \extensions \phpstan \ServiceMap ;
1820
@@ -49,20 +51,22 @@ final class UserPropertiesClassReflectionExtension implements PropertiesClassRef
4951 *
5052 * @param AnnotationsPropertiesClassReflectionExtension $annotationsProperties Extension for handling
5153 * annotation-based properties.
54+ * @param ReflectionProvider $reflectionProvider Reflection provider for class and property lookups.
55+ * @param ServiceMap $serviceMap Service map for resolving component classes by ID.
5256 */
5357 public function __construct (
5458 private readonly AnnotationsPropertiesClassReflectionExtension $ annotationsProperties ,
59+ private readonly ReflectionProvider $ reflectionProvider ,
5560 private readonly ServiceMap $ serviceMap ,
5661 ) {}
5762
5863 /**
5964 * Retrieves the property reflection for a given property on the Yii user component.
6065 *
6166 * Resolves the property reflection for the specified property name by checking for the dynamic
62- * {@see User::identity] property, native properties, and annotation-based properties on the Yii user instance.
67+ * {@see User::identity} property, native properties, and annotation-based properties on the Yii user instance.
6368 *
64- * This method ensures that the {@see User::identity] property and properties defined native or via annotations are
65- * accessible for static analysis and IDE support.
69+ * For the 'identity' property, it resolves the type based on the configured identityClass in the user component.
6670 *
6771 * @param ClassReflection $classReflection Class reflection instance for the Yii user component.
6872 * @param string $propertyName Name of the property to retrieve.
@@ -73,10 +77,35 @@ public function __construct(
7377 */
7478 public function getProperty (ClassReflection $ classReflection , string $ propertyName ): PropertyReflection
7579 {
76- if (
77- $ propertyName === 'identity ' &&
78- ($ componentClass = $ this ->serviceMap ->getComponentClassById ($ propertyName )) !== null
79- ) {
80+ if (in_array ($ propertyName , ['id ' , 'identity ' , 'isGuest ' ], true ) === true ) {
81+ $ identityClass = $ this ->getIdentityClass ();
82+
83+ if ($ propertyName === 'identity ' && $ identityClass !== null ) {
84+ return new ComponentPropertyReflection (
85+ new DummyPropertyReflection ($ propertyName ),
86+ new ObjectType ($ identityClass ),
87+ $ classReflection ,
88+ );
89+ }
90+
91+ if ($ propertyName === 'id ' ) {
92+ return new ComponentPropertyReflection (
93+ new DummyPropertyReflection ($ propertyName ),
94+ TypeCombinator::union (new IntegerType (), new StringType (), new NullType ()),
95+ $ classReflection ,
96+ );
97+ }
98+
99+ if ($ propertyName === 'isGuest ' ) {
100+ return new ComponentPropertyReflection (
101+ new DummyPropertyReflection ($ propertyName ),
102+ new ConstantBooleanType (true ),
103+ $ classReflection ,
104+ );
105+ }
106+ }
107+
108+ if (($ componentClass = $ this ->serviceMap ->getComponentClassById ($ propertyName )) !== null ) {
80109 return new ComponentPropertyReflection (
81110 new DummyPropertyReflection ($ propertyName ),
82111 new ObjectType ($ componentClass ),
@@ -94,30 +123,46 @@ public function getProperty(ClassReflection $classReflection, string $propertyNa
94123 /**
95124 * Determines whether the specified property exists on the Yii user component.
96125 *
97- * Checks for the existence of a property on the user instance by considering native properties and
98- * annotation-based properties.
99- *
100- * This method ensures compatibility with the user component context, enabling accurate property reflection for
101- * static analysis and IDE autocompletion.
126+ * Checks for the existence of a property on the user instance by considering native properties,
127+ * annotation-based properties, and the special 'identity' property.
102128 *
103129 * @param ClassReflection $classReflection Class reflection instance for the Yii user component.
104130 * @param string $propertyName Name of the property to check for existence.
105131 *
106- * @return bool `true` if the property exists as a native or annotated property; `false` otherwise.
132+ * @return bool `true` if the property exists as a native, annotated, or identity property; `false` otherwise.
107133 */
108134 public function hasProperty (ClassReflection $ classReflection , string $ propertyName ): bool
109135 {
110136 if (
111137 $ classReflection ->getName () !== User::class &&
112- $ classReflection ->isSubclassOf (User::class) === false ) {
138+ $ classReflection ->isSubclassOfClass ($ this ->reflectionProvider ->getClass (User::class)) === false
139+ ) {
113140 return false ;
114141 }
115142
116- if ($ propertyName === 'identity ' && $ this ->serviceMap ->getComponentClassById ($ propertyName ) !== null ) {
117- return true ;
143+ return in_array ($ propertyName , ['id ' , 'identity ' , 'isGuest ' ], true )
144+ ? $ this ->getIdentityClass () !== null
145+ : $ this ->serviceMap ->getComponentClassById ($ propertyName ) !== null ;
146+ }
147+
148+ /**
149+ * Attempts to resolve the identity class from the user component configuration.
150+ *
151+ * This method tries to determine the identityClass configured for the user component
152+ * by looking at the service map's user component configuration.
153+ *
154+ * @return string|null The fully qualified identity class name, or null if not found.
155+ */
156+ private function getIdentityClass (): string |null
157+ {
158+ $ identityClass = null ;
159+
160+ $ definition = $ this ->serviceMap ->getComponentDefinitionByClassName (User::class);
161+
162+ if (isset ($ definition ['identityClass ' ]) && is_string ($ definition ['identityClass ' ])) {
163+ $ identityClass = $ definition ['identityClass ' ];
118164 }
119165
120- return $ classReflection ->hasNativeProperty ($ propertyName )
121- || $ this ->annotationsProperties ->hasProperty ($ classReflection , $ propertyName );
166+ return $ identityClass ;
122167 }
123168}
0 commit comments