Skip to content

Conversation

@GautierDele
Copy link
Member

@GautierDele GautierDele commented Jul 6, 2025

Summary by CodeRabbit

  • New Features
    • Introduced a system for automatic discovery and registration of control classes associated with Eloquent models.
    • Enhanced the control creation command to support specifying a model, including interactive model selection and validation.
  • Improvements
    • Controls now explicitly declare the model they relate to, improving clarity and maintainability.
    • Centralized control retrieval for models, simplifying control instantiation across the system.
    • Updated policies and query scopes to utilize control instances directly, streamlining access control logic.
  • Bug Fixes
    • Ensured reliable control resolution for models by centralizing the lookup mechanism.
  • Tests
    • Added comprehensive tests for the new model option in the control creation command and improved test setup for cleaner test runs.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 6, 2025

Walkthrough

A new Access class is introduced to manage and discover control classes associated with Eloquent models, centralizing control registration and retrieval. Related static logic is removed from the Control class, and model association is now handled via an instance property. Command-line tooling is enhanced to support model selection when generating controls. Tests and service provider logic are updated to accommodate these changes.

Changes

File(s) Change Summary
src/Access.php Introduced Access class for control registration, discovery, and lookup by model.
src/Controls/Control.php, src/Controls/HasControl.php, src/Controls/HasControlScope.php, src/Policies/ControlledPolicy.php Removed static control resolution from Control, added instance $model property, updated usages to use Access.
src/AccessServiceProvider.php Added logic to discover and register controls during service provider registration.
src/Console/ControlMakeCommand.php, src/Console/stubs/control.stub Enhanced make command to support model association; updated stub to include $model property.
tests/Support/Access/Controls/ModelControl.php Added $model property to test control class.
tests/Support/Policies/ModelPolicy.php Changed policy to reference control class instead of model class.
tests/TestCase.php Registered test control in setup using new Access class.
tests/Unit/Console/MakeCommandsTest.php Refactored setup for file cleanup; added test for control generation with model association.

Sequence Diagram(s)

sequenceDiagram
    participant Developer
    participant Artisan
    participant ControlMakeCommand
    participant FileSystem

    Developer->>Artisan: Run make:control
    Artisan->>ControlMakeCommand: Execute command
    ControlMakeCommand->>FileSystem: List available models
    ControlMakeCommand->>Developer: Prompt for control name and model
    Developer->>ControlMakeCommand: Provide input
    ControlMakeCommand->>FileSystem: Generate control file with $model property
Loading
sequenceDiagram
    participant App
    participant Access
    participant Control
    participant Model

    App->>Access: controlForModel(Model)
    Access->>Access: Iterate registered controls
    Access->>Control: isModel(Model)
    Control-->>Access: true/false
    Access-->>App: Return matching Control instance or null
Loading

Poem

In the warren of code, new Access appears,
To gather the controls and calm model fears.
No more static guessing, just instance delight,
With models and controls now matched up just right.
Console commands hop, with model in tow—
The garden of logic continues to grow!
🐇✨


📜 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 a2815d4 and 31a9952.

📒 Files selected for processing (5)
  • src/Controls/Control.php (1 hunks)
  • src/Controls/HasControl.php (2 hunks)
  • src/Controls/HasControlScope.php (1 hunks)
  • src/Policies/ControlledPolicy.php (4 hunks)
  • tests/Support/Policies/ModelPolicy.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/Controls/HasControl.php
  • src/Policies/ControlledPolicy.php
  • src/Controls/Control.php
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/Controls/HasControlScope.php (1)
src/Controls/HasControl.php (1)
  • newControl (24-27)
⏰ Context from checks skipped due to timeout of 90000ms (16)
  • GitHub Check: Tests on PHP 8.4 with Laravel ^12.0 and pgsql
  • GitHub Check: Tests on PHP 8.4 with Laravel ^12.0 and mysql
  • GitHub Check: Tests on PHP 8.3 with Laravel ^12.0 and mysql
  • GitHub Check: Tests on PHP 8.3 with Laravel ^12.0 and sqlite
  • GitHub Check: Tests on PHP 8.4 with Laravel ^11.0 and mysql
  • GitHub Check: Tests on PHP 8.4 with Laravel ^11.0 and sqlite
  • GitHub Check: Tests on PHP 8.4 with Laravel ^12.0 and sqlite
  • GitHub Check: Tests on PHP 8.4 with Laravel ^11.0 and pgsql
  • GitHub Check: Tests on PHP 8.3 with Laravel ^11.0 and sqlite
  • GitHub Check: Tests on PHP 8.2 with Laravel ^11.0 and pgsql
  • GitHub Check: Tests on PHP 8.3 with Laravel ^12.0 and pgsql
  • GitHub Check: Tests on PHP 8.2 with Laravel ^12.0 and mysql
  • GitHub Check: Tests on PHP 8.2 with Laravel ^12.0 and pgsql
  • GitHub Check: Tests on PHP 8.3 with Laravel ^11.0 and pgsql
  • GitHub Check: Tests on PHP 8.3 with Laravel ^11.0 and mysql
  • GitHub Check: Tests on PHP 8.2 with Laravel ^12.0 and sqlite
🔇 Additional comments (2)
tests/Support/Policies/ModelPolicy.php (1)

6-6: LGTM! Property refactoring aligns with architectural changes.

The import addition and property change from $model to $control correctly implements the architectural shift from direct model references to control class references, as described in the PR objectives.

Also applies to: 10-10

src/Controls/HasControlScope.php (1)

57-59: Potential null reference issue - verify intended behavior.

The newControl() method can return null if no control is found for the model (based on the relevant code snippet), which would cause a fatal error when calling queried() on line 59.

Is this the intended behavior (fail fast if no control exists), or should there be graceful handling for models without controls?

If graceful handling is desired, consider this approach:

-$control = $builder->getModel()->newControl();
-
-return $control->queried($builder, Auth::user());
+$control = $builder->getModel()->newControl();
+
+if ($control === null) {
+    return $builder; // or throw a more descriptive exception
+}
+
+return $control->queried($builder, Auth::user());
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 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
Contributor

@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: 7

🧹 Nitpick comments (2)
src/Access.php (2)

86-86: Fix docblock annotation

The docblock uses @var but should use @param for method parameters.

-     * @var string[]
+     * @param string[] $paths

139-139: Consider making classFromFile private

This method appears to be used only internally within the class.

-    protected function classFromFile(SplFileInfo $file, string $basePath)
+    private function classFromFile(SplFileInfo $file, string $basePath)
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ffa2ccf and 34421d3.

📒 Files selected for processing (10)
  • src/Access.php (1 hunks)
  • src/AccessServiceProvider.php (2 hunks)
  • src/Console/ControlMakeCommand.php (10 hunks)
  • src/Console/stubs/control.stub (1 hunks)
  • src/Controls/Control.php (1 hunks)
  • src/Controls/HasControl.php (2 hunks)
  • src/Policies/ControlledPolicy.php (3 hunks)
  • tests/Support/Access/Controls/ModelControl.php (1 hunks)
  • tests/TestCase.php (2 hunks)
  • tests/Unit/Console/MakeCommandsTest.php (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (5)
tests/Support/Access/Controls/ModelControl.php (2)
src/Access.php (1)
  • Access (14-149)
tests/Support/Models/Model.php (1)
  • Model (12-43)
src/Policies/ControlledPolicy.php (1)
src/Access.php (2)
  • Access (14-149)
  • controlForModel (67-80)
tests/Unit/Console/MakeCommandsTest.php (2)
tests/TestCase.php (1)
  • setUp (18-26)
tests/Unit/TestCase.php (1)
  • setUp (10-15)
src/AccessServiceProvider.php (1)
src/Access.php (3)
  • Access (14-149)
  • discoverControls (87-117)
  • discoverControlsWithin (124-129)
src/Access.php (3)
tests/Support/Models/Model.php (1)
  • Model (12-43)
src/Controls/Control.php (2)
  • Control (12-222)
  • isModel (28-31)
src/Policies/ControlledPolicy.php (1)
  • create (72-75)
🔇 Additional comments (11)
tests/Support/Access/Controls/ModelControl.php (1)

15-15: LGTM! Model association follows the new pattern correctly.

The explicit declaration of the associated model via the $model property aligns with the refactoring to centralize control-model associations through the Access class.

src/Console/stubs/control.stub (1)

12-16: LGTM! Stub template correctly implements the new model association pattern.

The property declaration includes proper documentation and type annotations. The {{ namespacedModel }} placeholder will be appropriately replaced by the command that uses this stub.

tests/TestCase.php (2)

9-9: LGTM! Proper imports for the new control system.

The imports are necessary for the new Access-based control registration system used in the test setup.

Also applies to: 11-11


22-25: LGTM! Test setup correctly registers controls for the new system.

The test setup properly creates an Access instance and registers the ModelControl to ensure the control discovery system works correctly during testing.

src/AccessServiceProvider.php (2)

34-34: LGTM! Integration of control discovery into service provider registration.

The call to registerAccessControls() properly integrates the new Access-based control discovery system into the service provider lifecycle.


97-107: LGTM! Control discovery implementation is correct.

The method correctly instantiates the Access class and triggers control discovery from the default paths. Since Access uses static arrays to store controls, the instance-based approach works correctly.

src/Controls/HasControl.php (2)

5-5: LGTM! Necessary import for the new control system.

The Access import is required for the updated newControl() method implementation.


26-26: LGTM! Control discovery now uses the centralized Access class.

The change from static control resolution to Access::controlForModel() aligns with the refactoring to centralize control management. The method correctly handles the nullable return type.

src/Policies/ControlledPolicy.php (1)

37-37: Verify direct property access is intentional

The change from $this->getModel() to $this->model uses direct property access instead of the getter method. While more efficient, this bypasses any potential logic in the getter.

If the getter method getModel() on line 25 performs no additional logic beyond returning the property, this change is fine. Otherwise, consider keeping the getter usage for consistency and future flexibility.

src/Controls/Control.php (1)

28-31: LGTM!

The isModel() method provides a clean way to check model association.

src/Console/ControlMakeCommand.php (1)

119-134: Well-implemented model replacements

The buildModelReplacements() method properly generates all necessary stub replacements for the model, including namespaced and variable forms.

Comment on lines +13 to 16
@unlink(app_path('Access/Perimeters/TestPerimeter.php'));
@unlink(app_path('Access/Controls/TestControl.php'));
@unlink(app_path('Access/Controls/Control.php'));
@unlink(app_path('Access/Perimeters/TestPerimeter.php'));
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove duplicate file deletion

Line 16 duplicates the file deletion already performed on line 13.

         @unlink(app_path('Access/Perimeters/TestPerimeter.php'));
         @unlink(app_path('Access/Controls/TestControl.php'));
         @unlink(app_path('Access/Controls/Control.php'));
-        @unlink(app_path('Access/Perimeters/TestPerimeter.php'));
         @unlink(app_path('Access/Perimeters/SecondTestPerimeter.php'));
🤖 Prompt for AI Agents
In tests/Unit/Console/MakeCommandsTest.php between lines 13 and 16, there is a
duplicate call to unlink the file 'Access/Perimeters/TestPerimeter.php' on lines
13 and 16. Remove the duplicate unlink call on line 16 to avoid redundant file
deletion attempts.

Comment on lines 14 to +19
/**
* The control name resolver.
* The model the control refers to.
*
* @var callable
* @var class-string<Model>
*/
protected static $controlNameResolver;
protected string $model;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider initializing the model property

The $model property is declared but not initialized. This could cause issues if accessed before being set by subclasses.

Consider providing a default value or making it nullable:

     /**
      * The model the control refers to.
      *
      * @var class-string<Model>
      */
-    protected string $model;
+    protected string $model = '';
🤖 Prompt for AI Agents
In src/Controls/Control.php around lines 14 to 19, the protected string property
$model is declared but not initialized, which may lead to errors if accessed
before being set. To fix this, either initialize $model with a default
class-string value or change its type to nullable by adding a question mark and
set it to null by default, ensuring safe access before assignment.

@GautierDele GautierDele merged commit 9c40752 into main Jul 6, 2025
21 checks passed
@GautierDele GautierDele deleted the feat/rewrote-control-registering branch July 6, 2025 15:55
@coderabbitai coderabbitai bot mentioned this pull request Jul 27, 2025
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.

3 participants