Skip to content

Add support for yii\web\User Components (Identity Property) #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

samuelrajan747
Copy link
Contributor

@samuelrajan747 samuelrajan747 commented Jun 6, 2025

Added support for yii\web\User Components.
This is achieved by using generic types in yii\web\User (stubs for now).
Need to update inline comments (PHPDocs).
Need to write tests.
Need to upstream the addition of generic type in yii\web\User to Yii.

Q A
Is bugfix?
New feature? ✔️
Breaks BC?
Fixed issues

Before:

The Problem

As per the yii2 docs.
As of now, Yii::$app->__user_component_name__->identity after successful login will return \yii\web\IdentityInterface, irrespective of what is defined in $config['components']['__user_component_name__']['identityClass'].

Expected Outcome

Yii::$app->__user_component_name__->identity after successful login should return instance of class mentioned in $config['components']['__user_component_name__']['identityClass'].

After:

Yii::$app->__user_component_name__->identity after successful login will return whatever class mentioned in $config['components']['__user_component_name__']['identityClass'] which should be implementing yii\web\IdentityInterface

How it works:

  • A generic type T of yii\web\IdentityInterface is added to the yii\web\User class in the class level.
  • All references to yii\web\IdentityInterface in yii\web\User is replaced with generic type T.
  • An array of mapping between component names and identity class names is obtained by the service map when the extension initializes.
  • Whenever a component of type yii\web\User is accessed in yii\web\Application, a class property of generic object type with class yii\web\User and generic type T is set to identityClass defined in $config['components']['__user_component_name__']['identityClass'] is returned.
  • Whenever identity property of yii\web\User is accessed, the property reflection is derived from the PHPDoc annotation in yii\web\User is returned.
  • This works because the generic type T of yii\web\IdentityInterface of yii\web\User is set to the $config['components']['__user_component_name__']['identityClass'] earlier.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features
    • Added support for IdentityClass components, enabling enhanced handling of user components and identity classes.
    • Introduced new stub files for Yii base and web classes, including BaseObject, Component, Configurable, IdentityInterface, and User.
  • Bug Fixes
    • Improved type specificity for user-related properties in application property reflection.
  • Documentation
    • Updated changelog and improved README formatting and configuration examples.
  • Tests
    • Added tests and stubs to verify correct handling of user components and identity classes.
  • Chores
    • Updated configuration files to include new stub files and user component definitions.

Added support for IdentityClass Components implemented by yii\web\User.
This is acheived by using genric types in yii\web\User (stubs for now).
Need to update inline comments (PHPDocs).
Need to write tests.
Need to upstream the addition of generic type in yii\web\User to Yii.
Copy link

coderabbitai bot commented Jun 6, 2025

Walkthrough

This update introduces support for Yii User components with identity classes by extending the ServiceMap to distinguish user components and their identity classes. New stub files for Yii base and web classes/interfaces are added, configuration and test files are updated accordingly, and minor formatting adjustments are made to documentation and configuration files.

Changes

Files/Groups Change Summary
CHANGELOG.md Added entry for Enh #31: support for IdentityClass Components.
README.md, phpunit.xml.dist Formatting and whitespace adjustments; no content changes.
extension.neon Added stubFiles parameter listing new stub files.
src/ServiceMap.php Added handling for Yii User components: new property, methods, and logic to map user component IDs to identity classes.
src/reflection/ApplicationPropertiesClassReflectionExtension.php Enhanced property resolution to recognize user components and provide generic type reflection.
src/reflection/UserPropertiesClassReflectionExtension.php Removed custom logic for "identity" property; now delegates to annotation-based reflection; refined user component class checks.
stubs/Configurable.stub, stubs/BaseObject.stub, stubs/Component.stub Added stubs for Configurable interface, BaseObject, and Component classes under yii\base.
stubs/IdentityInterface.stub, stubs/User.stub Added stubs for IdentityInterface and generic User class under yii\web.
tests/ServiceMapTest.php Added assertions to verify correct user component resolution in ServiceMap.
tests/fixture/config.php Added customUser and customInitializedUser components with identityClass set to MyUser.
tests/stub/MyUser.php Added MyUser class stub implementing IdentityInterface for testing.

Sequence Diagram(s)

sequenceDiagram
    participant Config as Config Loader
    participant ServiceMap
    participant AppReflectionExt as ApplicationPropertiesClassReflectionExtension
    participant UserComponent as yii\web\User
    participant Identity as IdentityClass

    Config->>ServiceMap: Load components from config
    ServiceMap->>ServiceMap: processComponents()
    alt Component is yii\web\User with identityClass
        ServiceMap->>ServiceMap: processUserComponent(id, identityClass)
        ServiceMap->>UserComponent: Map id to identityClass
    else Other component
        ServiceMap->>ServiceMap: Register in general components map
    end

    AppReflectionExt->>ServiceMap: getUserComponentClassById(id)
    alt User component found
        AppReflectionExt->>AppReflectionExt: Return ComponentPropertyReflection with GenericObjectType<User, IdentityClass>
    else Not a user component
        AppReflectionExt->>ServiceMap: getComponentClassById(id)
    end
Loading

Possibly related PRs

Poem

A hop and a skip, a new class appears,
User components mapped, the code now cheers!
With stubs and reflections, identities in tow,
The ServiceMap’s smarter, just watch it go!
🐇✨
From config to test, all changes align—
This rabbit’s quite proud of this new design!


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ab4a1e and 81cd5b4.

📒 Files selected for processing (2)
  • src/reflection/ApplicationPropertiesClassReflectionExtension.php (4 hunks)
  • src/reflection/UserPropertiesClassReflectionExtension.php (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/reflection/UserPropertiesClassReflectionExtension.php
  • src/reflection/ApplicationPropertiesClassReflectionExtension.php
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: phpunit / PHP 8.2-windows-latest
  • GitHub Check: phpunit-compatibility / PHP 8.2-windows-latest
  • GitHub Check: phpunit-compatibility / PHP 8.1-windows-latest
  • GitHub Check: phpunit-compatibility / PHP 8.2-ubuntu-latest
  • GitHub Check: composer-require-checker / PHP 8.4-ubuntu-latest
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

codecov bot commented Jun 6, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 100.00%. Comparing base (b910ed8) to head (81cd5b4).
Report is 1 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff             @@
##                main       #31   +/-   ##
===========================================
  Coverage     100.00%   100.00%           
- Complexity        53        59    +6     
===========================================
  Files              1         1           
  Lines             79        86    +7     
===========================================
+ Hits              79        86    +7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

wrote basic tests
need to update docs
@samuelrajan747
Copy link
Contributor Author

yiisoft/yii2#20400 - If this is merged, the added stubs can be removed.

@samuelrajan747 samuelrajan747 marked this pull request as ready for review June 7, 2025 15:32
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (2)
src/reflection/ApplicationPropertiesClassReflectionExtension.php (1)

153-155: ⚠️ Potential issue

Inconsistency between hasProperty and getProperty for user components.

The hasProperty method doesn't check for user components via getUserComponentClassById(), but getProperty can resolve them. This could lead to scenarios where hasProperty() returns false but getProperty() succeeds.

Add user component checking to maintain consistency:

 return $classReflection->hasNativeProperty($propertyName)
     || $this->annotationsProperties->hasProperty($classReflection, $propertyName)
-    || $this->serviceMap->getComponentClassById($propertyName) !== null;
+    || $this->serviceMap->getComponentClassById($propertyName) !== null
+    || $this->serviceMap->getUserComponentClassById($propertyName) !== null;
src/reflection/UserPropertiesClassReflectionExtension.php (1)

109-111: ⚠️ Potential issue

Questionable logic for identity property checking.

The logic checks $this->serviceMap->getComponentClassById($propertyName) when $propertyName === 'identity', but "identity" is not a component ID - it's a property on the User class. This condition will likely never be true and seems incorrect.

Consider removing this logic or replacing it with appropriate identity property checking:

-        if ($propertyName === 'identity' && $this->serviceMap->getComponentClassById($propertyName) !== null) {
-            return true;
-        }
🧹 Nitpick comments (4)
stubs/IdentityInterface.stub (1)

5-5: Consider enriching IdentityInterface stub with real method signatures
The stub is minimal, but adding the findIdentity(), getId(), getAuthKey(), and validateAuthKey() signatures could improve type checks in IDEs and static analysis.

src/reflection/UserPropertiesClassReflectionExtension.php (1)

53-53: Unused ServiceMap dependency.

Since the getProperty method no longer uses the ServiceMap and the logic in hasProperty appears incorrect, this dependency may be unnecessary.

Consider removing the unused ServiceMap dependency if it's no longer needed after the refactoring.

src/ServiceMap.php (2)

132-135: Add documentation for the new public method.

The method implementation is correct, but it lacks PHPDoc documentation that would be consistent with other public methods in the class.

+    /**
+     * Retrieves the fully qualified identity class name of a Yii User component by its identifier.
+     *
+     * Looks up the identity class name registered under the specified user component ID in the internal user component map.
+     *
+     * This method enables static analysis tools and IDEs to resolve the actual identity class type of User
+     * components for accurate generic type inference and autocompletion.
+     *
+     * @param string $id User component identifier to look up in the user component map.
+     *
+     * @return string|null Fully qualified identity class name, or `null` if not found.
+     */
     public function getUserComponentClassById(string $id): string|null

374-377: Consider adding parameter validation.

The method implementation is straightforward, but consider adding validation to ensure the identity class exists and implements the required interface.

 private function processUserComponent(string $id, string $identityClass): void
 {
+    if (!class_exists($identityClass)) {
+        throw new RuntimeException(sprintf("Identity class '%s' for user component '%s' does not exist.", $identityClass, $id));
+    }
+    
+    if (!is_subclass_of($identityClass, \yii\web\IdentityInterface::class)) {
+        throw new RuntimeException(sprintf("Identity class '%s' for user component '%s' must implement IdentityInterface.", $identityClass, $id));
+    }
+    
     $this->userComponents[$id] = $identityClass;
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c74ff83 and 4cab780.

📒 Files selected for processing (15)
  • CHANGELOG.md (1 hunks)
  • README.md (3 hunks)
  • extension.neon (1 hunks)
  • phpunit.xml.dist (1 hunks)
  • src/ServiceMap.php (5 hunks)
  • src/reflection/ApplicationPropertiesClassReflectionExtension.php (2 hunks)
  • src/reflection/UserPropertiesClassReflectionExtension.php (1 hunks)
  • stubs/BaseObject.stub (1 hunks)
  • stubs/Component.stub (1 hunks)
  • stubs/Configurable.stub (1 hunks)
  • stubs/IdentityInterface.stub (1 hunks)
  • stubs/User.stub (1 hunks)
  • tests/ServiceMapTest.php (2 hunks)
  • tests/fixture/config.php (2 hunks)
  • tests/stub/MyUser.php (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/reflection/ApplicationPropertiesClassReflectionExtension.php (2)
src/ServiceMap.php (1)
  • getUserComponentClassById (132-135)
src/reflection/ComponentPropertyReflection.php (1)
  • ComponentPropertyReflection (37-271)
tests/ServiceMapTest.php (2)
tests/stub/MyUser.php (1)
  • MyUser (10-36)
src/ServiceMap.php (2)
  • getComponentClassById (127-130)
  • getUserComponentClassById (132-135)
🔇 Additional comments (19)
phpunit.xml.dist (1)

24-24: Trivial whitespace alignment: This change only adjusts indentation of the <directory> element for consistency and has no functional impact.

stubs/Configurable.stub (1)

5-5: Approve new Configurable stub interface
This empty stub correctly defines the interface for static analysis.

CHANGELOG.md (1)

10-10: Verify enhancement numbering continuity
Entry Enh #31 skips #30. Ensure no enhancement is missing or misnumbered in the changelog.

extension.neon (1)

8-13: Approve addition of stub files to configuration
The new stubFiles list correctly registers all custom stub files required for enhanced type reflection.

stubs/BaseObject.stub (1)

5-5: Approve new BaseObject stub class
This stub correctly extends the empty Configurable interface for static mapping purposes.

stubs/Component.stub (1)

1-5:

✅ Verification successful

LGTM! Verify BaseObject dependency.

The stub correctly defines the basic Component class hierarchy for static analysis.

Verify that BaseObject stub is properly defined and available:


🏁 Script executed:

#!/bin/bash
# Description: Verify BaseObject stub exists and check extension configuration

# Check if BaseObject stub exists
fd -t f "BaseObject" stubs/

# Check extension.neon for stub file configurations
cat extension.neon | grep -A 10 -B 5 "stubFiles"

Length of output: 435


BaseObject Stub Verified and Properly Configured

  • stubs/BaseObject.stub exists.
  • extension.neon’s stubFiles list includes stubs/Component.stub and stubs/BaseObject.stub.

No further changes needed—LGTM!

README.md (2)

17-17: LGTM! Clean formatting improvements.

Removing trailing spaces after anchor tags improves code quality and consistency.

Also applies to: 21-21, 23-23, 26-26


142-144: LGTM! Proper PHPStan configuration indentation.

The level: 8 parameter is now correctly indented within the parameters block.

stubs/User.stub (1)

7-10:

✅ Verification successful

LGTM! Excellent generic type implementation.

The template parameter T properly constrained to IdentityInterface and the nullable $identity property correctly typed with T perfectly implements the feature described in the PR objectives.

Verify that IdentityInterface is properly available for the constraint:


🏁 Script executed:

#!/bin/bash
# Description: Verify IdentityInterface stub/definition exists

# Check for IdentityInterface stub files
fd -t f "IdentityInterface" stubs/

# Check if it's defined in extension configuration
rg -A 5 -B 5 "IdentityInterface" extension.neon

Length of output: 347


IdentityInterface constraint verified, LGTM

  • Confirmed stubs/IdentityInterface.stub exists
  • Verified it’s listed under stubFiles in extension.neon

No further changes needed—approving these updates.

tests/ServiceMapTest.php (2)

17-17: LGTM! Proper import for user component testing.

Adding the MyUser import is necessary for the new user component test assertions.


115-132:

✅ Verification successful

LGTM! Comprehensive user component testing.

The test assertions correctly verify the new functionality:

  • User components return null from getComponentClassById (lines 115-118, 124-127)
  • User components correctly resolve via getUserComponentClassById to MyUser::class (lines 119-123, 128-132)
  • Tests cover both customUser and customInitializedUser variants
  • Descriptive assertion messages clearly explain expected behavior

This properly validates the separation of user component handling from regular components.

Verify the test configuration includes the expected user components:


🏁 Script executed:

#!/bin/bash
# Description: Verify test fixture contains the expected user component configurations

# Check test fixture for customUser and customInitializedUser definitions
cat tests/fixture/config.php | grep -A 10 -B 2 "customUser\|customInitializedUser"

# Verify MyUser stub exists
cat tests/stub/MyUser.php

Length of output: 1331


All user component tests and configurations are valid
Verified presence of both customUser and customInitializedUser in tests/fixture/config.php and confirmed the MyUser stub in tests/stub/MyUser.php. No further changes required.

tests/fixture/config.php (1)

5-7: Good test coverage for user components.

The configuration provides comprehensive testing for both array-based and direct instantiation approaches for user components with identity classes. This aligns well with the PR objectives to support generic typing for yii\web\User.

Also applies to: 18-22

src/reflection/ApplicationPropertiesClassReflectionExtension.php (1)

102-109: Excellent implementation of generic user component support.

The logic correctly uses getUserComponentClassById() to resolve identity classes and returns a proper GenericObjectType representing yii\web\User<IdentityClass>. This aligns perfectly with the PR objective to enable generic typing for user components.

tests/stub/MyUser.php (1)

1-36: Clean and appropriate test stub implementation.

The MyUser class correctly implements IdentityInterface with simple return values suitable for testing the generic user component functionality. All required methods are properly implemented.

src/reflection/UserPropertiesClassReflectionExtension.php (1)

75-77: Verify the delegation to annotations is correct.

The change from custom identity property handling to delegating to the annotations extension should be correct if the generic typing is now handled via stubs. However, ensure that the stubs properly define the generic identity property with the correct type.

src/ServiceMap.php (4)

14-14: LGTM!

The import statement is correctly added and follows the existing import organization.


80-83: LGTM!

The new property is correctly typed and follows the existing pattern for component storage.


300-304: LGTM!

The logic correctly identifies User class definitions with identityClass configuration and processes them appropriately. The type checks are comprehensive and safe.


290-294:

✅ Verification successful

Verify identityClass property access for User instances.

The logic correctly handles User object instances, but direct property access to $definition->identityClass may not be safe if the property is private or protected.


🏁 Script executed:

#!/bin/bash
# Description: Check the visibility of identityClass property in yii\web\User class

# Search for identityClass property declaration in Yii User class
ast-grep --pattern $'class User {
  $$$
  $_ $identityClass$$$;
  $$$
}'

# Alternative search for identityClass property
rg -A 3 -B 1 "identityClass" --type php

Length of output: 2777


Direct access to identityClass is safe

The identityClass property on yii\web\User is declared public in the Yii2 framework, so using $definition->identityClass is safe and requires no further changes.

@samuelrajan747 samuelrajan747 changed the title Add support for IdentityClass Components Add support for yii\web\User Components (Identity Property) Jun 7, 2025
@samuelrajan747 samuelrajan747 marked this pull request as draft June 7, 2025 19:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant