Skip to content
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

HP-1751 Create configurations for billing types #530

Open
wants to merge 25 commits into
base: master
Choose a base branch
from

Conversation

VadymHrechukha
Copy link
Contributor

@VadymHrechukha VadymHrechukha commented Dec 17, 2024

Summary by CodeRabbit

  • New Features

    • Added a new dependency for enhanced billing functionality.
    • Introduced a new billing registry service to the application configuration.
    • Added a new class, ConsumptionConfiguratorData, for better data encapsulation.
  • Improvements

    • Restricted access to certain methods in the ConsumptionConfigurator for better encapsulation.
    • Enhanced object instantiation practices within the ConsumptionConfigurator class.
    • Improved configuration retrieval logic in the ConsumptionConfigurator to utilize billing behaviors.
    • Simplified decorator handling across multiple resource classes using a new trait.
    • Updated resource classes to remove deprecated decorator methods and streamline functionality.
    • Adjusted import statements to reflect new dependency structure.
    • Updated the Target class to utilize the new ConsumptionConfiguratorData for configuration handling.
  • Bug Fixes

    • No specific bug fixes were noted in this release.

Copy link

coderabbitai bot commented Dec 17, 2024

Walkthrough

The pull request introduces a new dependency to the composer.json file for the hiqdev/hipanel-module-finance project. Specifically, a new package advancedhosters/billing-registry with the version dev-master has been added to the project's required dependencies, alongside the existing hiqdev/php-units package. Additionally, a new singleton definition for BillingRegistryInterface has been added to the config/web.php file, and the QuantityFormatterFactory class has been updated to include this new dependency in its constructor. The ConsumptionConfigurator class has undergone changes to restrict method visibility and improve object instantiation practices. Several classes related to decorators have been modified or removed, streamlining their functionality.

Changes

File Change Summary
composer.json Added new dependency "advancedhosters/billing-registry": "dev-master" to the require section
config/web.php Added singleton definition for BillingRegistryInterface mapped to TariffConfiguration::buildRegistry()
src/logic/bill/QuantityFormatterFactory.php Updated constructor to include BillingRegistryInterface $BillingRegistry as a new parameter
src/helpers/ConsumptionConfigurator.php Changed visibility of getGroups and getDecorator methods to private; updated logic in getConfigurations
src/models/ClientResource.php Removed decorator method; added trait HasDecorator for decorator functionality
src/models/HasDecorator.php Introduced new trait HasDecorator with a method for lazy instantiation of decorators
src/models/ServerResource.php Removed decorator method; added trait HasDecorator
src/models/TargetResource.php Removed decorator method; added trait HasDecorator
src/models/decorators/ResourceDecoratorFactory.php Removed typeMap method; updated createFromResource method logic to use TariffConfiguration
src/models/decorators/client/ClientResourceDecoratorFactory.php Removed class and typeMap method
src/models/decorators/server/ServerResourceDecoratorFactory.php Removed class and typeMap method
src/models/decorators/target/TargetResourceDecoratorFactory.php Removed class and typeMap method
src/models/stubs/ServerResourceStub.php Removed decorator method; now uses HasDecorator trait
src/models/Resource.php Removed property $decorator of type ResourceDecoratorInterface
src/models/decorators/DecoratedInterface.php Removed DecoratedInterface entirely
src/models/proxy/Resource.php Updated import statements for DecoratedInterface and ResourceDecoratorInterface to new namespace
src/models/stubs/AbstractResourceStub.php Updated to implement DecoratedInterface; removed $decorator property and method
src/helpers/ConsumptionConfiguratorData.php Added new class ConsumptionConfiguratorData with constructor and getLabel method
src/models/Target.php Updated getTypes method to accept ConsumptionConfiguratorData instead of an array

Possibly related PRs

Poem

🐰 A composer's tale, a dependency's dance,
New package joins the project's advance,
Billing registry hops into the scene,
With master's dev branch, fresh and keen.
Code grows stronger with each new friend! 🚀


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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. (Beta)
  • @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

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

🧹 Nitpick comments (1)
config/web.php (1)

293-295: Consider making the registry configuration more flexible

The current implementation uses a static factory method which might make testing harder and lacks configuration options. Consider:

  1. Making the registry configuration injectable for better testability
  2. Adding configuration parameters if needed for different environments

Example approach:

    \hiqdev\php\billing\product\BillingRegistryInterface::class => static function () {
-       return \hiqdev\billing\registry\TariffConfiguration::buildRegistry();
+       return \hiqdev\billing\registry\TariffConfiguration::buildRegistry([
+           'config' => $params['billing.registry'] ?? [],
+       ]);
    },
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 145f4f0 and 153f37d.

📒 Files selected for processing (2)
  • config/web.php (1 hunks)
  • src/logic/bill/QuantityFormatterFactory.php (1 hunks)
🔇 Additional comments (2)
src/logic/bill/QuantityFormatterFactory.php (1)

67-71: Clarify the intended usage of BillingRegistryInterface

The BillingRegistryInterface has been added as a dependency but isn't utilized in any of the class methods. This seems like an incomplete change. Could you please:

  1. Clarify how the billing registry will be used in this class
  2. Consider adding a TODO comment if this is preparatory work for future changes

Let's check if there are any related TODO comments or upcoming changes:

✅ Verification successful

The BillingRegistryInterface dependency appears to be properly configured

The verification shows that:

  1. BillingRegistryInterface is properly configured in the DI container (config/web.php) and mapped to a concrete implementation
  2. The class is part of a billing system handling various quantity formatting for different billing types
  3. The dependency injection is consistent with the system's architecture where billing registry is used for tariff configuration

The addition of BillingRegistryInterface as a dependency is valid and follows the application's design patterns, even if not immediately used in the current implementation. This is a common practice when preparing for upcoming features while maintaining proper dependency injection.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Look for related TODO comments or upcoming changes
rg -l "TODO.*[Bb]illing" 

Length of output: 26


Script:

#!/bin/bash
# Let's check if BillingRegistryInterface is used anywhere in the class
rg -A 5 "BillingRegistry" src/logic/bill/QuantityFormatterFactory.php

# Let's also check for any recent changes or additions related to BillingRegistry
rg -l "BillingRegistryInterface"

# Let's look at the actual implementation to understand the context better
ast-grep --pattern 'class QuantityFormatterFactory {
  $$$
}'

Length of output: 337


Script:

#!/bin/bash
# Let's check how BillingRegistryInterface is configured in web.php
cat config/web.php

# Let's check the full implementation of QuantityFormatterFactory to see all methods
rg -A 20 "class QuantityFormatterFactory" src/logic/bill/QuantityFormatterFactory.php

# Let's also check if there are any recent changes or PRs related to billing
rg -l "[Bb]illing" --type php

Length of output: 16191

config/web.php (1)

293-295: Review package version constraint

Using dev-master for advancedhosters/billing-registry in production could lead to stability issues. Consider:

  1. Using a stable version constraint
  2. Adding a minimum stability requirement if needed

Let's check the package's available versions:

Comment on lines +67 to +71
public function __construct(
private readonly IntlFormatter $intlFormatter,
private readonly BillTypesProvider $billTypesProvider,
private readonly BillingRegistryInterface $BillingRegistry,
)
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

⚠️ Potential issue

After reviewing the complete class implementation, I can now generate the final response:

Property naming issue confirmed and unused dependency detected

  1. The property $BillingRegistry violates PSR naming conventions and should be renamed to $billingRegistry
  2. The BillingRegistryInterface dependency is injected but never used in any of the class methods: create(), forBill(), forCharge(), forConsumption(), createByType(), or fixType()

This appears to be an incomplete implementation. Either:

  • Remove the unused dependency if it's not needed
  • Or implement the intended functionality that requires this dependency
🔗 Analysis chain

Property naming and unused dependency concerns

  1. The property name $BillingRegistry should follow PSR naming conventions and be in camelCase: $billingRegistry
  2. The injected BillingRegistryInterface is never used in any of the class methods

Apply this diff to fix the property naming:

    public function __construct(
        private readonly IntlFormatter $intlFormatter,
        private readonly BillTypesProvider $billTypesProvider,
-       private readonly BillingRegistryInterface $BillingRegistry,
+       private readonly BillingRegistryInterface $billingRegistry,
    )

Let's verify the usage of BillingRegistryInterface in this class:


Let me gather more context about this class to ensure a comprehensive verification.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if BillingRegistryInterface is used in the class methods
rg -U "billingRegistry|BillingRegistry" src/logic/bill/QuantityFormatterFactory.php

Length of output: 153


Script:

#!/bin/bash
# Get the full content of the class to understand its methods and usage
cat src/logic/bill/QuantityFormatterFactory.php

Length of output: 5817

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

🧹 Nitpick comments (1)
src/helpers/ConsumptionConfigurator.php (1)

162-174: Add defensive programming measures

While the new implementation using BillingRegistry behaviors is good, consider adding defensive programming measures:

  1. Add validation for behavior responses
  2. Handle the case when no behaviors are found
  3. Add error handling for invalid behavior data

Consider applying this improvement:

 public function getConfigurations(): array
 {
     $configurations = [];
     /** @var ConsumptionConfigurationBehaviour $behavior */
+    $behaviors = $this->billingRegistry->getBehaviors(ConsumptionConfigurationBehaviour::class);
+    if (empty($behaviors)) {
+        Yii::warning('No consumption configuration behaviors found');
+    }
-    foreach ($this->billingRegistry->getBehaviors(ConsumptionConfigurationBehaviour::class) as $behavior) {
+    foreach ($behaviors as $behavior) {
         $tariffType = $behavior->getTariffType();
+        if ($tariffType === null) {
+            Yii::warning('Invalid tariff type returned by behavior');
+            continue;
+        }
 
         $configurations[$tariffType->name()] = [
-            'label' => $behavior->getLabel(),
+            'label' => $behavior->getLabel() ?? ['hipanel:finance', 'Unknown'],
             'columns' => $behavior->columns,
             'groups' => $behavior->groups,
             'model' => $this->createObject($behavior->getModel() ?? Target::class),
             'resourceModel' => $this->createObject($behavior->getResourceModel() ?? TargetResource::class),
         ];
     }
 
     return $configurations;
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 35e187c and c848e29.

📒 Files selected for processing (1)
  • src/helpers/ConsumptionConfigurator.php (3 hunks)
🔇 Additional comments (3)
src/helpers/ConsumptionConfigurator.php (3)

12-13: LGTM: Clean dependency injection implementation

The new imports and constructor properly implement dependency injection for the BillingRegistry, with good use of PHP 8 features like constructor property promotion and readonly properties.

Also applies to: 21-23


153-154: LGTM: Improved object creation pattern

Good improvement using createObject for dependency injection instead of direct instantiation. This makes the code more testable and flexible.


30-30: Verify no external usage of previously public methods

The visibility changes to getGroups and getDecorator improve encapsulation. However, since these were previously public, we should verify there are no external dependencies on these methods.

Also applies to: 106-106

✅ Verification successful

Let me try a different approach to search for these method calls.


Let me check if the getGroups method found in other files is related to our class.


Visibility changes to getGroups and getDecorator are safe

The search results confirm that:

  • The getGroups method found in other files (FormulaExamplesProvider and formulaHelpModal) is a different implementation, not related to ConsumptionConfigurator
  • All calls to getGroups and getDecorator in ConsumptionConfigurator are internal to the class
  • No external usage of these methods from ConsumptionConfigurator was found

Therefore, changing the visibility of these methods to private is safe and improves encapsulation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any external usage of these methods
echo "Searching for external usage of getGroups and getDecorator methods..."
rg -l "->getGroups\(" --type php
rg -l "->getDecorator\(" --type php

Length of output: 1031


Script:

#!/bin/bash
# Search for method calls using escaped characters and word boundaries
echo "Searching for external usage of getGroups..."
rg "\bgetGroups\(" --type php

echo -e "\nSearching for external usage of getDecorator..."
rg "\bgetDecorator\(" --type php

Length of output: 998


Script:

#!/bin/bash
# Get more context around getGroups usage
echo "Context for getGroups in formulaHelpModal.php:"
rg -B 2 -A 2 "getGroups\(" src/widgets/views/formulaHelpModal.php

echo -e "\nContext for getGroups in FormulaExamplesProvider.php:"
rg -B 2 -A 2 "getGroups\(" src/providers/FormulaExamplesProvider.php

echo -e "\nChecking if these files import ConsumptionConfigurator:"
rg -l "ConsumptionConfigurator" src/widgets/views/formulaHelpModal.php src/providers/FormulaExamplesProvider.php

Length of output: 993

…rFactory, TargetResourceDecoratorFactory and ClientResourceDecoratorFactory classes because ResourceDecoratorFactory in enough
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

🧹 Nitpick comments (2)
src/models/decorators/ResourceDecoratorFactory.php (1)

22-35: Consider inverting this dependency for improved testability and flexibility.
Building the registry inline is convenient, but injecting it as a dependency simplifies mocking and unit testing in the future.

src/models/HasDecorator.php (1)

10-11: Consider declaring a default value for the private property.
You might consider initializing $decorator with null to be explicit and avoid potential uninitialized property errors if PHP initialization rules change in the future.

- private ResourceDecoratorInterface $decorator;
+ private ?ResourceDecoratorInterface $decorator = null;
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between c848e29 and 547de81.

📒 Files selected for processing (9)
  • src/models/ClientResource.php (1 hunks)
  • src/models/HasDecorator.php (1 hunks)
  • src/models/ServerResource.php (1 hunks)
  • src/models/TargetResource.php (1 hunks)
  • src/models/decorators/ResourceDecoratorFactory.php (2 hunks)
  • src/models/decorators/client/ClientResourceDecoratorFactory.php (0 hunks)
  • src/models/decorators/server/ServerResourceDecoratorFactory.php (0 hunks)
  • src/models/decorators/target/TargetResourceDecoratorFactory.php (0 hunks)
  • src/models/stubs/ServerResourceStub.php (1 hunks)
💤 Files with no reviewable changes (3)
  • src/models/decorators/target/TargetResourceDecoratorFactory.php
  • src/models/decorators/server/ServerResourceDecoratorFactory.php
  • src/models/decorators/client/ClientResourceDecoratorFactory.php
🔇 Additional comments (12)
src/models/decorators/ResourceDecoratorFactory.php (2)

1-1: Great job introducing strict typing.
This enhances type safety and helps identify potential type-related issues at compile time.


5-7: Confirm that newly imported classes are fully utilized.
These imports look appropriate, but please ensure they are all used in the implementations.

✅ Verification successful

All imported classes are properly utilized in the implementation

The verification shows that all imported classes are actively used within the ResourceDecoratorFactory.php:

  • TariffConfiguration is used to build the registry: TariffConfiguration::buildRegistry()
  • ResourceDecoratorBehavior is used in type hint and class reference: @var ResourceDecoratorBehavior and ResourceDecoratorBehavior::class
  • ResourceDecoratorData is instantiated: new ResourceDecoratorData(
  • BehaviorNotFoundException is used in catch block: catch (BehaviorNotFoundException)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify references to newly added imports:
rg "ResourceDecoratorBehavior|ResourceDecoratorData|TariffConfiguration|BehaviorNotFoundException"

Length of output: 1226

src/models/ServerResource.php (1)

28-28: Using the HasDecorator trait centralizes and simplifies the decorator logic.
This approach enhances maintainability across multiple resource classes.

src/models/TargetResource.php (2)

1-1: Enabling strict typing is a solid choice.
It helps maintain consistent and correct type usage throughout the file.


9-9: The trait-based approach simplifies decorator handling.
Refactoring for a single, shared decorator logic approach is a good architectural improvement.

src/models/ClientResource.php (2)

1-1: Strict typing fosters safer code.
Thank you for maintaining a consistent coding standard across files.


9-9: Strongly aligned with the new decorator pattern approach.
Using HasDecorator eliminates boilerplate code in each resource class.

src/models/stubs/ServerResourceStub.php (2)

13-13: The addition of the HasDecorator trait unifies the stub with the updated resource structure.
This helps ensure test stubs remain aligned with the actual resource implementations.


17-17: Eliminating the manual decorator method removes extraneous duplication.
Consolidating the decorator logic in one trait simplifies future maintenance.

src/models/HasDecorator.php (3)

1-1: Great use of strict typing.
Declaring strict_types=1 enforces type safety and is a recommended practice in modern PHP development.


8-9: Well-structured trait introduction.
Using a trait like HasDecorator encourages code reuse and keeps the classes that include it focused on their core responsibilities.


12-19: Lazy-loading approach looks clean and maintainable.
The decorator() method neatly defers the instantiation until it’s needed, reducing overhead if the resource decorator is never accessed.

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

🧹 Nitpick comments (2)
src/helpers/ConsumptionConfigurator.php (2)

147-156: Consider extracting the fallback configuration to a constant or private method.

The fallback configuration could be extracted to improve maintainability and reusability.

Here's a suggested refactor:

+    private function getDefaultConfiguration(): array
+    {
+        return [
+            'label' => ['hipanel:finance', $class],
+            'columns' => [],
+            'groups' => [],
+            'model' => $this->createObject(Target::class),
+            'resourceModel' => $this->createObject(TargetResource::class),
+        ];
+    }
+
     public function getConfigurationByClass(string $class): array
     {
-        $fallback = [
-            'label' => ['hipanel:finance', $class],
-            'columns' => [],
-            'groups' => [],
-            'model' => $this->createObject(Target::class),
-            'resourceModel' => $this->createObject(TargetResource::class),
-        ];
-
-        return $this->getConfigurations()[$class] ?? $fallback;
+        return $this->getConfigurations()[$class] ?? $this->getDefaultConfiguration();
     }

161-176: Consider adding error handling for invalid behavior configurations.

While the implementation is good, it could benefit from validation and error handling for cases where behavior methods return invalid or unexpected values.

Here's a suggested improvement:

     public function getConfigurations(): array
     {
         $configurations = [];
         /** @var ConsumptionConfigurationBehaviour $behavior */
         foreach ($this->billingRegistry->getBehaviors(ConsumptionConfigurationBehaviour::class) as $behavior) {
             $tariffType = $behavior->getTariffType();
+            if ($tariffType === null) {
+                continue; // or throw new InvalidConfigurationException
+            }
 
             $configurations[$tariffType->name()] = [
-                'label' => $behavior->getLabel(),
-                'columns' => $behavior->columns,
-                'groups' => $behavior->groups,
+                'label' => $behavior->getLabel() ?? ['hipanel:finance', 'Unknown'],
+                'columns' => $behavior->columns ?? [],
+                'groups' => $behavior->groups ?? [],
                 'model' => $this->createObject($behavior->getModel() ?? Target::class),
                 'resourceModel' => $this->createObject($behavior->getResourceModel() ?? TargetResource::class),
             ];
         }
 
         return $configurations;
     }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 547de81 and 3c477b0.

📒 Files selected for processing (1)
  • src/helpers/ConsumptionConfigurator.php (3 hunks)
🔇 Additional comments (2)
src/helpers/ConsumptionConfigurator.php (2)

12-13: LGTM! Well-structured dependency injection implementation.

The addition of BillingRegistryInterface as a constructor dependency with proper readonly property promotion follows good practices for dependency injection and immutability.

Also applies to: 21-23


30-30: LGTM! Improved encapsulation through visibility restrictions.

Changing the visibility of getGroups and getDecorator to private properly encapsulates these implementation details.

Let's verify there are no external calls to these methods:

Also applies to: 106-106

✅ Verification successful

Visibility changes are safe to apply

The external call to getGroups() found in formulaHelpModal.php is actually calling a different method from a formulaExamplesProvider instance, not the ConsumptionConfigurator::getGroups() method being modified. All other calls to both getGroups() and getDecorator() are internal to the ConsumptionConfigurator class itself, so changing their visibility to private is safe.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any external calls to these methods that might break due to visibility changes
rg -l "->getGroups\s*\(" --type php
rg -l "->getDecorator\s*\(" --type php

Length of output: 888


Script:

#!/bin/bash
# Search for any external calls to these methods that might break due to visibility changes
# Escape the special characters in the pattern
rg "\->getGroups\(" --type php
rg "\->getDecorator\(" --type php

Length of output: 492


Script:

#!/bin/bash
# Let's check the context of the external call to getGroups in formulaHelpModal.php
# to see if it's calling the same method or a different one
rg -B 2 -A 2 "\->getGroups\(" src/widgets/views/formulaHelpModal.php

# Also check what class is $widget in formulaHelpModal.php
rg -B 5 "widget" src/widgets/views/formulaHelpModal.php

Length of output: 968

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

🧹 Nitpick comments (1)
src/models/stubs/AbstractResourceStub.php (1)

14-14: Consider documenting the new interface usage.
It might be helpful to document how and why this interface is being used, especially if future contributors need to understand its relationship to the rest of the codebase.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3c477b0 and e39fa0a.

📒 Files selected for processing (9)
  • src/models/ClientResource.php (1 hunks)
  • src/models/HasDecorator.php (1 hunks)
  • src/models/Resource.php (0 hunks)
  • src/models/ServerResource.php (2 hunks)
  • src/models/TargetResource.php (1 hunks)
  • src/models/decorators/DecoratedInterface.php (0 hunks)
  • src/models/decorators/ResourceDecoratorFactory.php (1 hunks)
  • src/models/proxy/Resource.php (1 hunks)
  • src/models/stubs/AbstractResourceStub.php (1 hunks)
💤 Files with no reviewable changes (2)
  • src/models/Resource.php
  • src/models/decorators/DecoratedInterface.php
✅ Files skipped from review due to trivial changes (1)
  • src/models/proxy/Resource.php
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/models/HasDecorator.php
  • src/models/TargetResource.php
  • src/models/decorators/ResourceDecoratorFactory.php
🔇 Additional comments (5)
src/models/ClientResource.php (2)

1-1: LGTM! Good practice adding strict types.

Adding strict type declarations helps catch type-related errors at compile time rather than runtime.


5-9: Verify the HasDecorator trait implementation.

The change from direct decorator implementation to using the HasDecorator trait looks good and follows DRY principles. However, let's verify the trait implementation and its usage across other resource classes.

✅ Verification successful

HasDecorator trait implementation is consistent and properly used

The verification shows that:

  • The HasDecorator trait is well-implemented with proper decorator initialization and caching logic
  • It's consistently used across all resource classes: ClientResource, TargetResource, ServerResource (and its stub)
  • No direct decorator() method implementations remain in the codebase, confirming complete migration to the trait
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the HasDecorator trait implementation and usage

# Check the HasDecorator trait implementation
echo "Checking HasDecorator trait implementation:"
rg -A 10 "trait HasDecorator"

# Check other classes using the HasDecorator trait
echo -e "\nChecking HasDecorator trait usage:"
rg "use HasDecorator"

# Verify no remaining direct decorator() method implementations
echo -e "\nChecking for any remaining direct decorator() implementations:"
ast-grep --pattern 'function decorator()'

Length of output: 1254

src/models/ServerResource.php (2)

14-14: LGTM! Import statement aligns with interface implementation.

The addition of the DecoratedInterface import is consistent with the class's implementation of this interface.


28-28: LGTM! Trait usage improves code organization.

The addition of the HasDecorator trait is a good refactoring that:

  • Standardizes decorator handling across resource classes
  • Removes duplicated decorator initialization code
  • Improves maintainability

Let's verify consistent implementation across related resource classes:

✅ Verification successful

Let me try a different search pattern since the previous one didn't work correctly.


Let me check the trait implementation to ensure it properly supports the interface.


Trait implementation is consistent and properly supports decorator pattern

Based on the verification:

  • HasDecorator trait is used consistently in ServerResource, TargetResource, and ClientResource
  • These classes correctly implement DecoratedInterface
  • The trait provides proper implementation with lazy loading of decorators via factory
  • CertificateResource and DomainResource don't use decorators, which is fine as they might not need this functionality
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistent implementation of HasDecorator trait
# across all resource classes

# Check for HasDecorator trait usage
echo "Checking HasDecorator trait usage in resource classes:"
rg -l "use HasDecorator;" "src/models/*Resource.php"

# Check for DecoratedInterface implementation
echo -e "\nChecking DecoratedInterface implementation in resource classes:"
ast-grep --pattern 'class $NAME extends Resource implements DecoratedInterface'

Length of output: 463


Script:

#!/bin/bash
# First find all resource files
echo "Finding all resource files:"
fd "Resource\.php$" src/

# Check HasDecorator usage
echo -e "\nChecking HasDecorator trait usage:"
rg "use HasDecorator;" $(fd "Resource\.php$" src/)

# Check DecoratedInterface implementation
echo -e "\nChecking DecoratedInterface implementation:"
rg "implements.*DecoratedInterface" $(fd "Resource\.php$" src/)

# Look at the trait definition
echo -e "\nLooking for HasDecorator trait definition:"
fd "HasDecorator.php" src/

Length of output: 1720


Script:

#!/bin/bash
# Check the HasDecorator trait implementation
echo "HasDecorator trait implementation:"
cat src/models/HasDecorator.php

# Check if there are any decorator-related methods in Resource classes that don't use the trait
echo -e "\nChecking for decorator methods in other resources:"
rg "decorator|getDecorator|setDecorator" src/models/CertificateResource.php src/models/DomainResource.php

Length of output: 873

src/models/stubs/AbstractResourceStub.php (1)

17-17: Verify that all interface requirements are fulfilled.
This class now implements DecoratedInterface. Confirm whether additional methods or traits are needed for full compliance, or if the interface acts purely as a marker with no required methods.

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

🧹 Nitpick comments (1)
src/helpers/ConsumptionConfigurator.php (1)

162-174: Add error handling for invalid behaviors.

While the new implementation is more dynamic and extensible, it lacks error handling for invalid behaviors. Consider adding validation and error handling for cases where:

  • Behavior doesn't implement required methods
  • Invalid model classes are specified
  • Required configuration values are missing

Here's a suggested improvement:

 public function getConfigurations(): array
 {
     $configurations = [];
     /** @var ConsumptionConfigurationBehaviour $behavior */
     foreach ($this->billingRegistry->getBehaviors(ConsumptionConfigurationBehaviour::class) as $behavior) {
+        try {
             $tariffType = $behavior->getTariffType();
+            if (!method_exists($behavior, 'getLabel') || !method_exists($behavior, 'getModel')) {
+                throw new \RuntimeException("Behavior must implement getLabel() and getModel() methods");
+            }
 
             $configurations[$tariffType->name()] = [
                 'label' => $behavior->getLabel(),
                 'columns' => $behavior->columns,
                 'groups' => $behavior->groups,
                 'model' => $this->createObject($behavior->getModel() ?? Target::class),
                 'resourceModel' => $this->createObject($behavior->getResourceModel() ?? TargetResource::class),
             ];
+        } catch (\Throwable $e) {
+            Yii::warning("Failed to load configuration from behavior: " . $e->getMessage());
+            continue;
+        }
     }
 
     return $configurations;
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e39fa0a and ac6d395.

📒 Files selected for processing (1)
  • src/helpers/ConsumptionConfigurator.php (3 hunks)
🔇 Additional comments (3)
src/helpers/ConsumptionConfigurator.php (3)

11-13: LGTM! Well-structured dependency injection.

The constructor properly implements dependency injection using PHP 8's readonly property promotion, making the dependency on BillingRegistryInterface explicit and immutable.

Also applies to: 21-23


153-154: LGTM! Improved object instantiation pattern.

The change to use createObject method leverages Yii's dependency injection container, making the code more flexible and testable.


30-30: Verify impact of method visibility changes.

The following methods have changed visibility which could break existing code:

  • getGroups: public → private
  • getDecorator: public → private
  • getConfigurationByClass: private → public

Let's verify the usage of these methods:

Also applies to: 106-106, 147-147

✅ Verification successful

Method visibility changes are safe to proceed

Based on the codebase analysis:

  • getGroups(): The only external usage found is from FormulaExamplesProvider which is a different class with its own implementation. The usage in ConsumptionConfigurator is internal (self calls).
  • getDecorator(): All usages are internal within ConsumptionConfigurator class itself.
  • getConfigurationByClass(): All usages are within ConsumptionConfigurator class, and making it public actually improves accessibility where needed.

The visibility changes are safe as they don't break any existing code:

  • The methods that became private (getGroups, getDecorator) are only used internally
  • The method that became public (getConfigurationByClass) maintains backward compatibility
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for direct usage of these methods in the codebase
echo "Searching for getGroups() usage..."
rg "->getGroups\(" --type php

echo "Searching for getDecorator() usage..."
rg "->getDecorator\(" --type php

echo "Searching for getConfigurationByClass() usage..."
rg "->getConfigurationByClass\(" --type php

Length of output: 1598


Script:

#!/bin/bash
# Search for direct usage of these methods in the codebase
echo "Searching for getGroups() usage..."
rg -e "getGroups\(" --type php

echo "Searching for getDecorator() usage..."
rg -e "getDecorator\(" --type php

echo "Searching for getConfigurationByClass() usage..."
rg -e "getConfigurationByClass\(" --type php

# Let's also check the class usage to understand the context better
echo "Searching for ConsumptionConfigurator usage..."
rg -e "ConsumptionConfigurator" --type php

Length of output: 4402

…urce() method to understand what parameter types can be passed to the function
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

🧹 Nitpick comments (2)
src/models/decorators/ResourceDecoratorFactory.php (2)

25-25: Consider caching the registry instance.

Building the registry on every method call (TariffConfiguration::buildRegistry()) could impact performance. Consider caching the registry instance or making it a singleton.

+ private static ?object $registry = null;

  public static function createFromResource($resource): ResourceDecoratorInterface
  {
      $type = $resource->model_type ?? $resource->type;
-     $registry = TariffConfiguration::buildRegistry();
+     self::$registry ??= TariffConfiguration::buildRegistry();

38-40: Enhance error handling with more descriptive messages.

The current error message could be more helpful by including:

  1. The available behavior types from the registry
  2. The actual reason for the behavior not being found
- } catch (BehaviorNotFoundException) {
-     throw new InvalidConfigException('No representative decoration class found for type "' . $type . '"');
+ } catch (BehaviorNotFoundException $e) {
+     throw new InvalidConfigException(sprintf(
+         'No representative decoration class found for type "%s". Available types: [%s]. Reason: %s',
+         $type,
+         implode(', ', $registry->getAvailableTypes()),
+         $e->getMessage()
+     ));
  }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ac6d395 and f1aa881.

📒 Files selected for processing (1)
  • src/models/decorators/ResourceDecoratorFactory.php (1 hunks)
🔇 Additional comments (3)
src/models/decorators/ResourceDecoratorFactory.php (3)

1-11: LGTM! Good practices in type safety and imports.

The addition of strict types and well-organized imports from the billing registry package enhance code reliability and maintainability.


14-24: LGTM! Well-documented method signature.

The PHPDoc block properly documents the parameter types, return type, and possible exceptions.


25-37: Verify the registry behavior types are properly configured.

The new registry-based approach requires proper configuration of behavior types. Let's verify the configuration:

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

🧹 Nitpick comments (1)
config/web.php (1)

199-199: Remove commented-out code.

The commented-out singleton definition for ConsumptionConfigurator should be removed as it's no longer needed.

-//            \hipanel\modules\finance\helpers\ConsumptionConfigurator::class => \hipanel\modules\finance\helpers\ConsumptionConfigurator::class,
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f43333b and 08f66cb.

📒 Files selected for processing (1)
  • config/web.php (1 hunks)
🔇 Additional comments (2)
config/web.php (2)

200-202: LGTM! Good architectural improvement.

The switch to BillingRegistryInterface with a factory method is a solid improvement that:

  • Follows dependency injection principles
  • Provides better abstraction through interface usage
  • Enables easier testing and maintenance

200-202: Verify the registry configuration.

Please ensure that the TariffConfiguration::buildRegistry() is properly configured with all required billing types and behaviors.

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

🧹 Nitpick comments (1)
src/helpers/ConsumptionConfigurator.php (1)

177-188: Address TODOs and document the special case

The code contains:

  1. TODO comments about missing traffic types in the database
  2. A hardcoded 'tariff' configuration that "Can't be added to Billing Registry"

Consider:

  • Creating tickets to track the missing traffic types investigation
  • Adding more detailed documentation explaining why the 'tariff' configuration can't be added to the registry

Would you like me to help create GitHub issues to track these TODOs?

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 08f66cb and 9535ff5.

📒 Files selected for processing (1)
  • src/helpers/ConsumptionConfigurator.php (3 hunks)
🔇 Additional comments (4)
src/helpers/ConsumptionConfigurator.php (4)

11-14: LGTM! Good use of dependency injection

The constructor properly implements dependency injection using the BillingRegistryInterface, following SOLID principles. The use of PHP 8's readonly property promotion is a nice touch for immutability.

Also applies to: 22-24


163-175: LGTM! Good refactoring to dynamic configuration

The refactoring to use BillingRegistry behaviors for configuration retrieval is a good improvement that makes the system more maintainable and extensible.


154-155: LGTM! Good use of factory method pattern

The consistent use of createObject for model instantiation is a good practice that:

  • Leverages Yii's dependency injection container
  • Makes object creation more maintainable and testable
  • Provides a single point of control for object instantiation

Also applies to: 172-173


31-31: Verify the impact of method visibility changes

The visibility changes improve encapsulation but might break existing code. Please ensure:

  1. No external code directly calls getGroups or getDecorator
  2. All code requiring configuration access uses the now-public getConfigurationByClass

Also applies to: 107-107, 148-148

✅ Verification successful

Method visibility changes are safe to apply

The visibility changes to getGroups and getDecorator methods in ConsumptionConfigurator are safe because:

  1. getGroups is only used internally by the public getGroupsWithLabels method, which serves as the proper public interface
  2. No external code directly calls these methods
  3. The FormulaExamplesProvider::getGroups() is a different method in a different class
  4. The Consumption::getGroupsWithLabels() properly uses the public interface
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for direct calls to getGroups and getDecorator
echo "Searching for potential breaking changes..."
rg --type php "->getGroups\(|->getDecorator\(" --glob '!src/helpers/ConsumptionConfigurator.php'

Length of output: 600


Script:

#!/bin/bash
# Search for potential calls to getGroups and getDecorator methods
echo "Searching for potential breaking changes..."
rg -t php "getGroups|getDecorator" --glob '!src/helpers/ConsumptionConfigurator.php'

# Let's also check if there are any class references to ConsumptionConfigurator
echo -e "\nSearching for ConsumptionConfigurator usage..."
rg -t php "ConsumptionConfigurator" --glob '!src/helpers/ConsumptionConfigurator.php'

# Check the class definition and its inheritance
echo -e "\nChecking class definition..."
rg -t php "class ConsumptionConfigurator" -A 5

Length of output: 3607


Script:

#!/bin/bash
# Let's check the actual usage of getGroups and getDecorator in the found files
echo "Checking getGroups usage in Consumption model..."
rg -t php "getGroups" src/models/Consumption.php -B 2 -A 2

echo -e "\nChecking getGroupsWithLabels implementation..."
rg -t php "getGroupsWithLabels" src/helpers/ConsumptionConfigurator.php -B 2 -A 5

echo -e "\nChecking FormulaExamplesProvider getGroups implementation..."
rg -t php "getGroups" src/providers/FormulaExamplesProvider.php -B 2 -A 5

Length of output: 1502

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

🧹 Nitpick comments (1)
src/helpers/ResourceHelper.php (1)

22-22: Leverage shared conversion logic from the external billing registry.

By delegating the conversion to \hiqdev\billing\registry\helper\ResourceHelper::convertAmount, you ensure consistent conversion rules. However, consider adding error handling or validating the response from the external helper in case of unexpected inputs.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 9535ff5 and 36e414d.

📒 Files selected for processing (50)
  • src/helpers/ResourceHelper.php (2 hunks)
  • src/models/decorators/AbstractResourceDecorator.php (0 hunks)
  • src/models/decorators/ResourceDecoratorInterface.php (0 hunks)
  • src/models/decorators/client/AbstractClientResourceDecorator.php (0 hunks)
  • src/models/decorators/client/ReferralResourceDecorator.php (0 hunks)
  • src/models/decorators/server/AbstractServerResourceDecorator.php (0 hunks)
  • src/models/decorators/server/BackupResourceDecorator.php (0 hunks)
  • src/models/decorators/server/ChassisResourceDecorator.php (0 hunks)
  • src/models/decorators/server/CpuResourceDecorator.php (0 hunks)
  • src/models/decorators/server/HALoadBalancerResourceDecorator.php (0 hunks)
  • src/models/decorators/server/HddResourceDecorator.php (0 hunks)
  • src/models/decorators/server/IpResourceDecorator.php (0 hunks)
  • src/models/decorators/server/Isp5ResourceDecorator.php (0 hunks)
  • src/models/decorators/server/IspResourceDecorator.php (0 hunks)
  • src/models/decorators/server/LoadBalancerResourceDecorator.php (0 hunks)
  • src/models/decorators/server/LocationResourceDecorator.php (0 hunks)
  • src/models/decorators/server/MonthlyResourceDecorator.php (0 hunks)
  • src/models/decorators/server/PanelResourceDecorator.php (0 hunks)
  • src/models/decorators/server/PowerResourceDecorator.php (0 hunks)
  • src/models/decorators/server/RackUnitResourceDecorator.php (0 hunks)
  • src/models/decorators/server/RamResourceDecorator.php (0 hunks)
  • src/models/decorators/server/ServerDUResourceDecorator.php (0 hunks)
  • src/models/decorators/server/ServerFilesResourceDecorator.php (0 hunks)
  • src/models/decorators/server/ServerSSDResourceDecorator.php (0 hunks)
  • src/models/decorators/server/ServerSataDUResourceDecorator.php (0 hunks)
  • src/models/decorators/server/SpeedResourceDecorator.php (0 hunks)
  • src/models/decorators/server/StorageDUResourceDecorator.php (0 hunks)
  • src/models/decorators/server/SupportResourceDecorator.php (0 hunks)
  • src/models/decorators/server/Traffic95ResourceDecorator.php (0 hunks)
  • src/models/decorators/server/TrafficResourceDecorator.php (0 hunks)
  • src/models/decorators/target/AbstractTargetResourceDecorator.php (0 hunks)
  • src/models/decorators/target/CdnCache95ResourceDecorator.php (0 hunks)
  • src/models/decorators/target/CdnCacheResourceDecorator.php (0 hunks)
  • src/models/decorators/target/CdnTraffic95MaxResourceDecorator.php (0 hunks)
  • src/models/decorators/target/CdnTraffic95ResourceDecorator.php (0 hunks)
  • src/models/decorators/target/CdnTrafficMaxResourceDecorator.php (0 hunks)
  • src/models/decorators/target/CdnTrafficPlainResourceDecorator.php (0 hunks)
  • src/models/decorators/target/CdnTrafficResourceDecorator.php (0 hunks)
  • src/models/decorators/target/CdnTrafficSSLResourceDecorator.php (0 hunks)
  • src/models/decorators/target/IpAnycastResourceDecorator.php (0 hunks)
  • src/models/decorators/target/IpPublicResourceDecorator.php (0 hunks)
  • src/models/decorators/target/IpRegularResourceDecorator.php (0 hunks)
  • src/models/decorators/target/PrivateCloudBackupDuResourceDecorator.php (0 hunks)
  • src/models/decorators/target/SnapshotDuResourceDecorator.php (0 hunks)
  • src/models/decorators/target/StorageDu95ResourceDecorator.php (0 hunks)
  • src/models/decorators/target/StorageDuResourceDecorator.php (0 hunks)
  • src/models/decorators/target/VolumeDuResourceDecorator.php (0 hunks)
  • src/models/decorators/target/VpsTrafficInResourceDecorator.php (0 hunks)
  • src/models/decorators/target/VpsTrafficMaxResourceDecorator.php (0 hunks)
  • src/models/decorators/target/VpsTrafficResourceDecorator.php (0 hunks)
💤 Files with no reviewable changes (49)
  • src/models/decorators/server/RackUnitResourceDecorator.php
  • src/models/decorators/target/CdnTrafficResourceDecorator.php
  • src/models/decorators/target/CdnCacheResourceDecorator.php
  • src/models/decorators/server/ServerDUResourceDecorator.php
  • src/models/decorators/server/TrafficResourceDecorator.php
  • src/models/decorators/target/VpsTrafficMaxResourceDecorator.php
  • src/models/decorators/target/CdnTraffic95MaxResourceDecorator.php
  • src/models/decorators/target/CdnTrafficSSLResourceDecorator.php
  • src/models/decorators/server/LoadBalancerResourceDecorator.php
  • src/models/decorators/target/StorageDu95ResourceDecorator.php
  • src/models/decorators/target/VpsTrafficInResourceDecorator.php
  • src/models/decorators/server/Isp5ResourceDecorator.php
  • src/models/decorators/server/ServerSSDResourceDecorator.php
  • src/models/decorators/target/IpAnycastResourceDecorator.php
  • src/models/decorators/server/IpResourceDecorator.php
  • src/models/decorators/target/VolumeDuResourceDecorator.php
  • src/models/decorators/server/MonthlyResourceDecorator.php
  • src/models/decorators/target/IpRegularResourceDecorator.php
  • src/models/decorators/server/BackupResourceDecorator.php
  • src/models/decorators/server/Traffic95ResourceDecorator.php
  • src/models/decorators/server/StorageDUResourceDecorator.php
  • src/models/decorators/target/CdnTrafficMaxResourceDecorator.php
  • src/models/decorators/target/CdnTrafficPlainResourceDecorator.php
  • src/models/decorators/server/SupportResourceDecorator.php
  • src/models/decorators/target/CdnTraffic95ResourceDecorator.php
  • src/models/decorators/target/StorageDuResourceDecorator.php
  • src/models/decorators/target/CdnCache95ResourceDecorator.php
  • src/models/decorators/AbstractResourceDecorator.php
  • src/models/decorators/server/HddResourceDecorator.php
  • src/models/decorators/server/RamResourceDecorator.php
  • src/models/decorators/target/AbstractTargetResourceDecorator.php
  • src/models/decorators/target/SnapshotDuResourceDecorator.php
  • src/models/decorators/server/IspResourceDecorator.php
  • src/models/decorators/client/AbstractClientResourceDecorator.php
  • src/models/decorators/server/CpuResourceDecorator.php
  • src/models/decorators/server/ServerSataDUResourceDecorator.php
  • src/models/decorators/server/SpeedResourceDecorator.php
  • src/models/decorators/ResourceDecoratorInterface.php
  • src/models/decorators/server/PowerResourceDecorator.php
  • src/models/decorators/server/LocationResourceDecorator.php
  • src/models/decorators/server/ChassisResourceDecorator.php
  • src/models/decorators/target/IpPublicResourceDecorator.php
  • src/models/decorators/server/HALoadBalancerResourceDecorator.php
  • src/models/decorators/target/VpsTrafficResourceDecorator.php
  • src/models/decorators/server/ServerFilesResourceDecorator.php
  • src/models/decorators/client/ReferralResourceDecorator.php
  • src/models/decorators/target/PrivateCloudBackupDuResourceDecorator.php
  • src/models/decorators/server/PanelResourceDecorator.php
  • src/models/decorators/server/AbstractServerResourceDecorator.php
🔇 Additional comments (2)
src/helpers/ResourceHelper.php (2)

10-10: Handle the new import reference carefully.

The changed import now points to hiqdev\billing\registry\ResourceDecorator\ResourceDecoratorInterface, which aligns with the new billing registry approach. Ensure that implementations of this interface in your codebase are updated to maintain consistent behavior.


20-20: Confirm that external dependencies do not rely on this method.

Changing the convertAmount method from public to private may break external callers if they previously referenced this method. Verify that no external references exist.

✅ Verification successful

Let me gather more information about the usage and context of this method.


Let me try one more search to ensure we have a complete picture.


The method change from public to private is safe

The convertAmount method in hipanel\modules\finance\helpers\ResourceHelper is only used internally within the same class to delegate the call to \hiqdev\billing\registry\helper\ResourceHelper::convertAmount(). From the search results:

  1. The method is only called once within its own class implementation
  2. No external files are using ResourceHelper::convertAmount directly
  3. The method acts as a proxy to another class's implementation in the hiqdev\billing\registry namespace
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search occurrences of the old public method usage outside this file
rg -A 3 -B 3 -F 'ResourceHelper::convertAmount'

Length of output: 520


Script:

#!/bin/bash
# Check the full implementation of ResourceHelper class
ast-grep --pattern $'class ResourceHelper {
  $$$
}'

Length of output: 53


Script:

#!/bin/bash
# Look for any other potential usages with different patterns
rg -A 3 -B 3 "convertAmount.*ResourceDecorator"

Length of output: 473


Script:

#!/bin/bash
# Check if there are any test files that might be using this method
fd "ResourceHelperTest" --exec cat {}

Length of output: 39


Script:

#!/bin/bash
# Check the namespace and see if this is actually calling itself
cat src/helpers/ResourceHelper.php | head -n 5

Length of output: 132


Script:

#!/bin/bash
# Look for any class that extends or uses ResourceHelper
rg -l "ResourceHelper"

Length of output: 232

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 (1)
src/helpers/ResourceHelper.php (1)

Line range hint 67-82: Move hardcoded types to configuration.

The totalsOverMax array contains hardcoded resource types that should be managed through the billing registry configuration.

Would you like me to help create a configuration structure for these resource types?

🧹 Nitpick comments (2)
src/helpers/ResourceHelper.php (2)

100-107: LGTM! Consider adding PHPDoc.

The implementation is clean and handles both aggregation types properly. Consider adding PHPDoc to document the parameters and return type.

+    /**
+     * Calculates the amount based on the aggregate type
+     * @param Aggregate $aggregate The aggregate configuration
+     * @param float|string $amount The current amount
+     * @param ResourceDecoratorInterface $decorator The resource decorator
+     * @return string The calculated amount
+     */
     private static function calculateAmount(Aggregate $aggregate, $amount, ResourceDecoratorInterface $decorator)

65-66: Consider completing the migration to BillingRegistry.

The introduction of BillingRegistry is a good architectural change. However, there's still a mix of old and new approaches (e.g., hardcoded types). Consider creating a migration plan to fully transition to the registry-based configuration.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 07c37be and 1ff5462.

📒 Files selected for processing (1)
  • src/helpers/ResourceHelper.php (4 hunks)
🔇 Additional comments (3)
src/helpers/ResourceHelper.php (3)

10-12: LGTM! Clean import additions.

The new imports from the billing registry are well-organized and properly aligned with the implementation changes.


89-93: LGTM! Clean implementation of aggregate-based calculation.

The new implementation properly delegates to the calculateAmount method while maintaining the aggregate state.


22-25: Verify external usage of convertAmount method.

The visibility change from public to private is good for encapsulation, but we should verify there are no external consumers of this method.

✅ Verification successful

Let me search for more specific usage patterns to ensure we don't miss any external calls.


The visibility change to private is safe to proceed

Based on the search results, the convertAmount method is only used internally within the ResourceHelper class itself. All external usages of ResourceHelper class are calling other public methods like prepareDetailView, calculateTotal, getResourceLoader, and buildGridColumns. The method is not directly accessed from outside the class.

The change from public to private visibility is safe as:

  • The only calls to convertAmount are internal (self::convertAmount)
  • These calls appear in the implementation of other methods within the same class
  • No external classes are directly using this method
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for external usage of convertAmount method
rg -l "ResourceHelper::convertAmount" --type php

Length of output: 79


Script:

#!/bin/bash
# Search for any usage of convertAmount with context
rg "convertAmount" --type php -B2 -A2

# Also check for class usage patterns
rg "ResourceHelper" --type php -B2 -A2

Length of output: 6384

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

🧹 Nitpick comments (5)
src/helpers/ResourceHelper.php (1)

95-102: Consider making the decimal precision configurable.

The method uses a hardcoded precision of 3 decimal places. Consider making this configurable to support different currency requirements.

+    private const DEFAULT_PRECISION = 3;
+
     private static function calculateAmount(Aggregate $aggregate, $amount, ResourceDecoratorInterface $decorator)
     {
         if ($aggregate->isMax()) {
             return max($amount, self::convertAmount($decorator));
         } else {
-            return bcadd($amount, self::convertAmount($decorator), 3);
+            return bcadd($amount, self::convertAmount($decorator), self::DEFAULT_PRECISION);
         }
     }
src/models/decorators/ResourceDecoratorFactory.php (1)

31-34: Consider caching the registry instance.

The buildRegistry() call might be expensive if called frequently. Consider caching the registry instance.

 class ResourceDecoratorFactory
 {
+    private static ?object $registry = null;
+
     public static function createFromResource($resource): ResourceDecoratorInterface
     {
         $type = $resource->model_type ?? $resource->type;
-        $registry = TariffConfiguration::buildRegistry();
+        self::$registry ??= TariffConfiguration::buildRegistry();
src/helpers/ConsumptionConfigurator.php (3)

163-175: Consider extracting configuration building logic.

The configuration building logic could be moved to a separate private method for better maintainability.

+    private function buildConfigurationFromBehavior(ConsumptionConfigurationBehaviour $behavior): array 
+    {
+        $tariffType = $behavior->getTariffType();
+        return [
+            'label' => $behavior->getLabel(),
+            'columns' => $behavior->columns,
+            'groups' => $behavior->groups,
+            'model' => $this->createObject($behavior->getModel() ?? Target::class),
+            'resourceModel' => $this->createObject($behavior->getResourceModel() ?? TargetResource::class),
+        ];
+    }

     public function getConfigurations(): array
     {
         $configurations = [];
         /** @var ConsumptionConfigurationBehaviour $behavior */
         foreach ($this->billingRegistry->getBehaviors(ConsumptionConfigurationBehaviour::class) as $behavior) {
-            $tariffType = $behavior->getTariffType();
-
-            $configurations[$tariffType->name()] = [
-                'label' => $behavior->getLabel(),
-                'columns' => $behavior->columns,
-                'groups' => $behavior->groups,
-                'model' => $this->createObject($behavior->getModel() ?? Target::class),
-                'resourceModel' => $this->createObject($behavior->getResourceModel() ?? TargetResource::class),
-            ];
+            $configurations[$behavior->getTariffType()->name()] = $this->buildConfigurationFromBehavior($behavior);
         }

177-188: Document the reason for hard-coded tariff configuration.

The comment "Can't be added to Billing Registry" needs more context. Consider adding a TODO to track this technical debt.

-        // Can't be added to Billing Registry, so left as it is
+        // TODO: HP-XXXX This tariff configuration can't be added to Billing Registry because <reason>.
+        // Consider refactoring to allow all configurations to be managed through the registry.
         $configurations['tariff'] = [

180-185: Consider using an enum for traffic types.

The traffic-related columns could be defined using an enum for better type safety and maintainability.

enum TrafficType: string {
    case TRAF95_MAX = 'server_traf95_max';
    case TRAF95 = 'server_traf95';
    case TRAF95_IN = 'server_traf95_in';
}

// Usage:
'columns' => [
    TrafficType::TRAF95_MAX->value,
    TrafficType::TRAF95->value,
    TrafficType::TRAF95_IN->value,
],
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1ff5462 and 1658f36.

📒 Files selected for processing (3)
  • src/helpers/ConsumptionConfigurator.php (3 hunks)
  • src/helpers/ResourceHelper.php (3 hunks)
  • src/models/decorators/ResourceDecoratorFactory.php (1 hunks)
🔇 Additional comments (7)
src/helpers/ResourceHelper.php (5)

10-13: LGTM! Good architectural separation of billing logic.

The migration of billing-related interfaces and classes to a dedicated hiqdev\billing\registry namespace improves separation of concerns and modularity.


23-26: LGTM! Good encapsulation and delegation.

The convertAmount method's visibility change to private improves encapsulation, while delegation to the registry helper maintains clean separation of concerns.


87-93: Address the TODO comment and improve type handling.

The TODO comment indicates incomplete implementation for type handling. This needs to be addressed before the code goes to production.

Would you like me to help create a comprehensive list of types that should support overuse and implement proper validation?


66-78: Verify the billing registry initialization.

The billing registry is initialized without error handling. Consider wrapping the initialization in a try-catch block to handle potential configuration errors gracefully.

-        $billingRegistry = TariffConfiguration::buildRegistry();
+        try {
+            $billingRegistry = TariffConfiguration::buildRegistry();
+        } catch (\Exception $e) {
+            throw new \RuntimeException('Failed to initialize billing registry: ' . $e->getMessage(), 0, $e);
+        }

Line range hint 1-102: Verify integration with existing consumption logic.

The changes introduce significant architectural improvements but require verification of integration points:

  1. Ensure the billing registry is properly configured in all environments
  2. Verify that all existing consumption calculations remain accurate
  3. Add integration tests for the new billing registry functionality

Run the following script to check for potential integration issues:

✅ Verification successful

Integration verification completed successfully

The changes are properly integrated with the existing consumption logic:

  • Billing registry is correctly configured in the DI container
  • Resource conversion is properly delegated to the registry implementation
  • Existing test infrastructure covers the modified functionality
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for potential integration points that might be affected
rg -l "ConsumptionConfigurator|ResourceHelper::convertAmount" --type php

# Check for existing tests that need updates
rg -l "class.*Test.*Consumption|class.*Test.*Resource" --type php

Length of output: 483


Script:

#!/bin/bash
# Check how ResourceHelper::convertAmount is used
rg "ResourceHelper::convertAmount" -B 2 -A 2 --type php

# Check for any existing test files that might have been missed
fd -e php -e phpt --full-path ".*tests?.*" 

# Look for billing registry configuration
rg "TariffConfiguration::buildRegistry" -B 2 -A 2 --type php

Length of output: 4412

src/models/decorators/ResourceDecoratorFactory.php (1)

27-44: Improved error handling and dynamic decorator resolution.

The refactoring from static type mapping to dynamic registry-based decorator resolution is a good improvement. However, there are a few considerations:

Please verify that all existing resource types have corresponding behaviors registered in the registry to avoid runtime exceptions. Run this script to check:

✅ Verification successful

Resource type verification completed successfully

The codebase shows a comprehensive set of well-defined resource types with corresponding registry configuration. The error handling in ResourceDecoratorFactory is appropriate for catching missing behaviors, while ResourceHelper::addOveruseToTypeIfNeeded() ensures proper type processing before behavior lookup.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all unique resource types in the codebase and compare with registered behaviors

# Find all resource types
echo "Resource types in codebase:"
rg -g '*.php' 'model_type\s*=|type\s*=' --no-filename | sort -u

# List registered behaviors
echo -e "\nRegistered behaviors in TariffConfiguration:"
ast-grep --pattern 'TariffConfiguration::buildRegistry()' -A 10

Length of output: 9789


Script:

#!/bin/bash
# First, locate TariffConfiguration file
echo "Locating TariffConfiguration file:"
fd TariffConfiguration

echo -e "\nSearching for resource type definitions:"
# Look for resource type constants and property definitions
rg -g '*.php' '(protected|private|public)\s+\$type\s*=\s*[\'"][\w_]+[\'"]|const\s+TYPE_\w+\s*=\s*[\'"][\w_]+[\'"]' --no-filename

# Look specifically at ResourceHelper class for type handling
echo -e "\nExamining ResourceHelper type handling:"
ast-grep --pattern 'class ResourceHelper'

Length of output: 318


Script:

#!/bin/bash

echo "Locating TariffConfiguration class:"
fd -e php TariffConfiguration

echo -e "\nSearching for resource type definitions:"
rg -g "*.php" "const TYPE_\w+" --no-filename

echo -e "\nLooking for registry building implementation:"
rg -g "*.php" "buildRegistry|registerBehavior" -B 2 -A 5

echo -e "\nSearching for behavior registrations:"
rg -g "*.php" "ResourceDecoratorBehavior" -B 2 -A 5

Length of output: 6930

src/helpers/ConsumptionConfigurator.php (1)

22-24: Good use of constructor injection and PHP 8 features.

The constructor properly uses dependency injection with the readonly property, following best practices.

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

🧹 Nitpick comments (5)
src/helpers/ResourceHelper.php (2)

23-26: Consider improving testability of amount conversion

The direct use of a static method from \hiqdev\billing\registry\helper\ResourceHelper makes the code harder to test. Consider dependency injection or an interface-based approach.

-    private static function convertAmount(ResourceDecoratorInterface $decorator)
-    {
-        return \hiqdev\billing\registry\helper\ResourceHelper::convertAmount($decorator);
-    }
+    private static function convertAmount(ResourceDecoratorInterface $decorator, ?ResourceHelperInterface $helper = null)
+    {
+        $helper = $helper ?? \hiqdev\billing\registry\helper\ResourceHelper::class;
+        return $helper::convertAmount($decorator);
+    }

95-102: Consider making precision configurable

The precision value of 3 in bcadd is hardcoded. Consider making this configurable to support different billing requirements.

+    private const DEFAULT_PRECISION = 3;
+
-    private static function calculateAmount(Aggregate $aggregate, $amount, ResourceDecoratorInterface $decorator)
+    private static function calculateAmount(Aggregate $aggregate, $amount, ResourceDecoratorInterface $decorator, int $precision = self::DEFAULT_PRECISION)
     {
         if ($aggregate->isMax()) {
             return max($amount, self::convertAmount($decorator));
         } else {
-            return bcadd($amount, self::convertAmount($decorator), 3);
+            return bcadd($amount, self::convertAmount($decorator), $precision);
         }
     }
src/helpers/ConsumptionConfigurator.php (3)

62-91: Review hard-coded tariff configuration

The tariff configuration is hard-coded with a comment "Can't be added to Billing Registry". This might be a code smell.

Consider:

  1. Moving this configuration to a separate class that implements ConsumptionConfigurationBehaviour
  2. Creating a custom behavior for tariff-specific configurations
  3. Adding a TODO comment explaining why this can't be added to the registry and tracking it in the issue system

Would you like me to help create a separate configuration class for this?


159-171: Good caching implementation for column labels

The caching of column labels is well implemented, preventing redundant calculations. However, consider adding memory limit protection for large configurations.

 if ($this->allPossibleColumnsWithLabels === null) {
+    $columnCount = 0;
     $this->allPossibleColumnsWithLabels = [];
     foreach ($this->getConfigurations() as $class => $configuration) {
         $columns = $configuration['columns'];
         foreach ($columns as $column) {
+            if (++$columnCount > 1000) {
+                throw new \RuntimeException('Too many columns in configurations');
+            }
             $decorator = $this->getDecorator($class, $column);
             $this->allPossibleColumnsWithLabels[$column] = $decorator->displayTitle();
         }
     }
 }

Line range hint 174-183: Consider caching decorators

The getDecorator method creates a new decorator instance on each call. For frequently accessed types, this could be inefficient.

Consider implementing a decorator cache:

+    private array $decoratorCache = [];
+
     private function getDecorator(string $class, string $type): ResourceDecoratorInterface
     {
+        $cacheKey = $class . ':' . $type;
+        if (isset($this->decoratorCache[$cacheKey])) {
+            return $this->decoratorCache[$cacheKey];
+        }
+
         $config = $this->getConfigurationByClass($class);
         $config['resourceModel']->type = $type;
-        /** @var ResourceDecoratorInterface $decorator */
-        $decorator = $config['resourceModel']->decorator();
-        return $decorator;
+        return $this->decoratorCache[$cacheKey] = $config['resourceModel']->decorator();
     }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1658f36 and d71bbd3.

📒 Files selected for processing (3)
  • src/helpers/ConsumptionConfigurator.php (5 hunks)
  • src/helpers/ResourceHelper.php (3 hunks)
  • src/models/decorators/ResourceDecoratorFactory.php (1 hunks)
🔇 Additional comments (5)
src/helpers/ResourceHelper.php (1)

85-93: Address TODO comment and improve type safety

The TODO comment indicates incomplete implementation. Additionally, string manipulation for type handling is error-prone.

Consider:

  1. Documenting which types should not have overuse
  2. Using type-safe enums or constants instead of string manipulation
  3. Adding validation for supported types

Would you like me to help implement a more type-safe solution or create an issue to track this improvement?

src/models/decorators/ResourceDecoratorFactory.php (2)

19-23: Improved type safety with explicit parameter typing

The method signature now clearly specifies accepted types (Resource|AbstractResourceStub) and return type (ResourceDecoratorInterface), enhancing type safety and code clarity.


27-44: Verify error handling for null registry

The implementation looks good with proper error handling and type checking. However, we should ensure the registry is never null.

Also, consider adding null check:

+        if ($registry === null) {
+            throw new InvalidConfigException('BillingRegistryInterface is not configured');
+        }
src/helpers/ConsumptionConfigurator.php (2)

18-24: Good use of dependency injection and property promotion

The constructor now properly injects dependencies and uses PHP 8's constructor property promotion. The nullable properties with proper initialization improve type safety.


31-46: Improved type safety with detailed return type annotation

The method documentation now includes a detailed array shape type, which is excellent for type checking and IDE support.

However, the fallback structure might need validation:

✅ Verification successful

Translation key is properly configured and widely used

The translation key "hipanel:finance" is valid and extensively used throughout the codebase as the primary namespace for finance-related translations. The fallback structure follows the established pattern.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if these translation keys exist
rg "hipanel:finance" -g '*.php' .

Length of output: 66662

Comment on lines +66 to +78
$billingRegistry = TariffConfiguration::buildRegistry();

$totals = [];
$totalsOverMax = [
'cdn_cache',
'cdn_cache95',
'cdn_traf95',
'cdn_traf95_max',
'server_traf95',
'server_traf95_in',
'server_traf95_max',
'storage_du',
'storage_du95',
'server_du',
'server_sata',
'server_ssd',
'server_files',
];
foreach (self::filterByAvailableTypes($resources) as $resource) {
$decorator = $resource->buildResourceModel()->decorator();
if (in_array($resource->type, $totalsOverMax, true)) {
$totals[$resource->type]['amount'] = max(($totals[$resource->type]['amount'] ?? 0),
self::convertAmount($decorator));
} else {
$totals[$resource->type]['amount'] = bcadd($totals[$resource->type]['amount'] ?? 0,
self::convertAmount($decorator),
3);
}
$type = $resource->type;
$aggregate = $billingRegistry->getAggregate(self::addOveruseToTypeIfNeeded($type));

$totals[$type]['amount'] = self::calculateAmount(
$aggregate,
$totals[$type]['amount'] ?? 0,
$decorator,
);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid direct instantiation of the billing registry

The direct use of TariffConfiguration::buildRegistry() creates tight coupling. Consider injecting the registry as a dependency.

-    public static function calculateTotal(array $resources): array
+    public static function calculateTotal(array $resources, ?BillingRegistryInterface $registry = null): array
     {
-        $billingRegistry = TariffConfiguration::buildRegistry();
+        $billingRegistry = $registry ?? TariffConfiguration::buildRegistry();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$billingRegistry = TariffConfiguration::buildRegistry();
$totals = [];
$totalsOverMax = [
'cdn_cache',
'cdn_cache95',
'cdn_traf95',
'cdn_traf95_max',
'server_traf95',
'server_traf95_in',
'server_traf95_max',
'storage_du',
'storage_du95',
'server_du',
'server_sata',
'server_ssd',
'server_files',
];
foreach (self::filterByAvailableTypes($resources) as $resource) {
$decorator = $resource->buildResourceModel()->decorator();
if (in_array($resource->type, $totalsOverMax, true)) {
$totals[$resource->type]['amount'] = max(($totals[$resource->type]['amount'] ?? 0),
self::convertAmount($decorator));
} else {
$totals[$resource->type]['amount'] = bcadd($totals[$resource->type]['amount'] ?? 0,
self::convertAmount($decorator),
3);
}
$type = $resource->type;
$aggregate = $billingRegistry->getAggregate(self::addOveruseToTypeIfNeeded($type));
$totals[$type]['amount'] = self::calculateAmount(
$aggregate,
$totals[$type]['amount'] ?? 0,
$decorator,
);
public static function calculateTotal(array $resources, ?BillingRegistryInterface $registry = null): array
{
$billingRegistry = $registry ?? TariffConfiguration::buildRegistry();
$totals = [];
foreach (self::filterByAvailableTypes($resources) as $resource) {
$decorator = $resource->buildResourceModel()->decorator();
$type = $resource->type;
$aggregate = $billingRegistry->getAggregate(self::addOveruseToTypeIfNeeded($type));
$totals[$type]['amount'] = self::calculateAmount(
$aggregate,
$totals[$type]['amount'] ?? 0,
$decorator,
);

Comment on lines +10 to +13
use hiqdev\billing\registry\product\Aggregate;
use hiqdev\billing\registry\product\GType;
use hiqdev\billing\registry\ResourceDecorator\ResourceDecoratorInterface;
use hiqdev\billing\registry\TariffConfiguration;
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Migration to billing registry system is incomplete

The codebase shows a mixed usage of old and new decorator implementations:

  • The old ResourceDecoratorFactory in src/models/decorators/ is still active
  • New registry-based decorators are being adopted across multiple files
  • Both old and new namespaces are currently in use

This partial migration could lead to inconsistent behavior. Consider completing the migration by:

  • Moving the ResourceDecoratorFactory to the new namespace
  • Updating all remaining references to the old namespace
  • Ensuring consistent usage of the new registry-based decorators throughout the codebase
🔗 Analysis chain

Architectural change: Migration to billing registry system

The shift from local decorators to the billing registry system suggests a move towards a more standardized billing configuration. This change improves maintainability by centralizing billing logic.

Let's verify that all local decorator usages have been migrated:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining references to the old decorator namespace
rg "hipanel\\\\modules\\\\finance\\\\models\\\\decorators\\\\ResourceDecoratorInterface" --type php

Length of output: 91


Script:

#!/bin/bash
# Search for any references to the old namespace pattern
rg "hipanel\\\\modules\\\\finance\\\\models\\\\decorators" --type php

# Search for the new decorator interface usage
rg "hiqdev\\\\billing\\\\registry\\\\ResourceDecorator" --type php

# Search for class implementations of ResourceDecoratorInterface
ast-grep --pattern 'class $_ implements ResourceDecoratorInterface'

Length of output: 1562

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

🧹 Nitpick comments (3)
src/helpers/ConsumptionConfiguratorData.php (1)

14-20: Consider making all constructor parameters private

Currently, only $label is private while others are public. For better encapsulation, consider making all parameters private and providing getter methods if needed.

 public function __construct(
     private readonly string $label,
-    public readonly array $columns,
-    public readonly array $groups,
-    public readonly Target|Server|Hub|Client $model,
-    public readonly Resource|ResourceProxy $resourceModel
+    private readonly array $columns,
+    private readonly array $groups,
+    private readonly Target|Server|Hub|Client $model,
+    private readonly Resource|ResourceProxy $resourceModel
 )
src/helpers/ConsumptionConfigurator.php (2)

82-93: Consider extracting hardcoded 'tariff' configuration

The comment "Can't be added to Billing Registry" suggests a design limitation. Consider:

  1. Adding this configuration to the registry
  2. Or creating a dedicated factory for special configurations

66-80: Consider breaking down the configuration building logic

The buildConfigurations method handles multiple responsibilities:

  • Iterating through behaviors
  • Creating configuration objects
  • Setting up models
    Consider extracting the configuration creation logic into a separate factory class.
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between d71bbd3 and c882709.

📒 Files selected for processing (4)
  • src/helpers/ConsumptionConfigurator.php (3 hunks)
  • src/helpers/ConsumptionConfiguratorData.php (1 hunks)
  • src/models/Target.php (2 hunks)
  • src/models/decorators/ResourceDecoratorFactory.php (1 hunks)
🔇 Additional comments (4)
src/helpers/ConsumptionConfiguratorData.php (1)

12-28: Well-designed data transfer object with strong type safety!

Great use of PHP 8 features:

  • Readonly properties ensure immutability
  • Union types provide type safety
  • Strict types enabled
src/models/Target.php (1)

45-53: LGTM! Good improvement in type safety

The change from array to ConsumptionConfiguratorData improves type safety and makes the code more maintainable.

src/models/decorators/ResourceDecoratorFactory.php (1)

29-40: Good error handling with specific exception message

The try-catch block properly handles BehaviorNotFoundException and provides a clear error message.

src/helpers/ConsumptionConfigurator.php (1)

24-26: LGTM! Good use of dependency injection

The constructor properly injects BillingRegistryInterface as a readonly dependency.

Comment on lines +42 to +51
private static function createResourceDecoratorData(Resource|AbstractResourceStub $resource): ResourceDecoratorData
{
return new ResourceDecoratorData(
$resource->quantity,
$resource->price,
$resource->unit,
$resource->currency,
$resource->type,
$resource->part->partno,
);
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Property access validation required

The codebase analysis confirms that part property access is not validated before use. This could lead to runtime errors if the property is null. Add null checks before accessing part->partno:

if ($resource->part === null) {
    throw new InvalidConfigException('Resource part cannot be null');
}
🔗 Analysis chain

Consider validating required properties

The createResourceDecoratorData method assumes all required properties exist. Consider adding null checks for critical properties like part->partno.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for potential null dereference of part->partno
ast-grep --pattern 'resource->part->partno'

Length of output: 45


Script:

#!/bin/bash
# Find Resource and AbstractResourceStub class definitions
echo "=== Searching for Resource class ==="
fd -e php -E vendor -E tests | xargs rg "class Resource" -A 5

echo -e "\n=== Searching for AbstractResourceStub class ==="
fd -e php -E vendor -E tests | xargs rg "class AbstractResourceStub" -A 5

echo -e "\n=== Looking for part property declarations ==="
fd -e php -E vendor -E tests | xargs rg "protected.*part|private.*part|public.*part" --type php

echo -e "\n=== Checking for validation in ResourceDecoratorFactory ==="
fd ResourceDecoratorFactory.php -E vendor -E tests | xargs cat

Length of output: 7150


Script:

#!/bin/bash
# Search for Model class and property validation
echo "=== Searching for Model class and property validation ==="
fd -e php -E vendor -E tests | xargs rg "class Model" -A 10

echo -e "\n=== Searching for ModelTrait usage ==="
fd -e php -E vendor -E tests | xargs rg "trait ModelTrait" -A 10

echo -e "\n=== Looking for property validation patterns ==="
fd -e php -E vendor -E tests | xargs rg "isset.*part|property_exists.*part|hasProperty.*part" --type php

echo -e "\n=== Searching for part property in all PHP files ==="
fd -e php -E vendor -E tests | xargs rg "\$part|\->part" --type php

Length of output: 844

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

♻️ Duplicate comments (1)
src/models/decorators/ResourceDecoratorFactory.php (1)

42-51: ⚠️ Potential issue

Add property validation before access.

The method directly accesses properties without validation. Add null checks for critical properties to prevent runtime errors.

 private static function createResourceDecoratorData(Resource|AbstractResourceStub $resource): ResourceDecoratorData
 {
+    if ($resource->part === null) {
+        throw new InvalidConfigException('Resource part cannot be null');
+    }
+
+    if ($resource->quantity === null) {
+        throw new InvalidConfigException('Resource quantity cannot be null');
+    }
+
     return new ResourceDecoratorData(
         $resource->quantity,
         $resource->price,
         $resource->unit,
         $resource->currency,
         $resource->type,
         $resource->part->partno,
     );
 }
🧹 Nitpick comments (1)
src/models/decorators/ResourceDecoratorFactory.php (1)

19-40: Validate registry object creation.

While the new registry-based approach is good, consider validating the registry object creation to handle potential configuration issues gracefully.

-        $registry = Yii::createObject(BillingRegistryInterface::class);
+        try {
+            $registry = Yii::createObject(BillingRegistryInterface::class);
+        } catch (\Throwable $e) {
+            throw new InvalidConfigException(
+                "Failed to create billing registry: " . $e->getMessage(),
+                0,
+                $e
+            );
+        }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between c882709 and ba3b462.

📒 Files selected for processing (1)
  • src/models/decorators/ResourceDecoratorFactory.php (1 hunks)
🔇 Additional comments (2)
src/models/decorators/ResourceDecoratorFactory.php (2)

1-14: LGTM! Good improvements to type safety.

The addition of strict types and well-organized imports enhance code reliability.


27-36: Verify integration with billing registry.

Let's verify that all components are properly integrated with the new billing registry approach.

✅ Verification successful

Integration with billing registry is properly implemented

The changes in ResourceDecoratorFactory are consistent with the codebase-wide integration pattern. All components are properly connected:

  • Registry is correctly configured in the application
  • Resource classes implement required interfaces
  • Decorator creation is properly centralized through the factory
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the integration of billing registry components

# Check for other classes using BillingRegistryInterface
echo "=== Classes using BillingRegistryInterface ==="
rg "BillingRegistryInterface" --type php

# Check for ResourceDecoratorBehavior implementations
echo -e "\n=== ResourceDecoratorBehavior implementations ==="
rg "implements.*ResourceDecoratorBehavior|extends.*ResourceDecoratorBehavior" --type php

# Check for other classes creating decorators
echo -e "\n=== Other decorator creation patterns ==="
rg "createDecorator|createFromResource" --type php

Length of output: 1606


Script:

#!/bin/bash
# Description: Deep verification of decorator behavior and registry configuration

# Check for ResourceDecoratorBehavior class implementations using AST
echo "=== ResourceDecoratorBehavior implementations (AST) ==="
ast-grep --pattern 'class $_ implements ResourceDecoratorBehavior { $$$ }'

# Check registry configuration
echo -e "\n=== Registry Configuration ==="
cat config/web.php | grep -A 10 "BillingRegistryInterface::class"

Length of output: 558


Script:

#!/bin/bash
# Description: Final verification of behavior patterns

# Check for behavior trait implementations
echo "=== Behavior Trait Patterns ==="
rg "trait.*ResourceDecorator|use.*ResourceDecorator" --type php

# Check for behavior usage in type hints
echo -e "\n=== Behavior Type Usage ==="
rg "ResourceDecoratorBehavior" --type php

Length of output: 1955

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

🧹 Nitpick comments (3)
src/helpers/ConsumptionConfigurator.php (3)

82-93: Consider extracting hard-coded tariff configuration.

The hard-coded tariff configuration should be moved to a configuration file or registry for better maintainability.


111-126: Consider simplifying groups handling logic.

The current implementation is complex and could benefit from:

  1. Adding PHPDoc with array shape description
  2. Using array_values to ensure sequential keys
  3. Consider using collection objects for better type safety
-    private function getGroups(string $class): array
+    /**
+     * @param string $class
+     * @return array<int, array<int, string>>
+     */
+    private function getGroups(string $class): array
     {
         $groups = [];
         $columns = $this->getColumns($class);
         foreach ($this->getConfigurationByClass($class)->groups as $group) {
-            $groups[] = $group;
+            $groups[] = array_values($group);
             foreach ($group as $item) {
                 $columns = array_diff($columns, [$item]);
             }
         }
         foreach ($columns as $column) {
             $groups[] = [$column];
         }

         return $groups;
     }

Line range hint 1-241: Good architectural improvements, consider further enhancements.

The changes show good progress in terms of:

  1. Integration with BillingRegistry
  2. Performance optimization with caching
  3. Better encapsulation

Consider these architectural improvements:

  1. Extract configuration building to a separate service
  2. Add interfaces for better dependency inversion
  3. Consider using value objects for complex data structures
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ba3b462 and 0582250.

📒 Files selected for processing (1)
  • src/helpers/ConsumptionConfigurator.php (2 hunks)
🔇 Additional comments (4)
src/helpers/ConsumptionConfigurator.php (4)

1-18: LGTM! Good use of encapsulation.

The class is properly marked as final and has well-organized imports.


19-26: LGTM! Excellent use of modern PHP features.

Good practices observed:

  • Private properties with proper type hints
  • Constructor property promotion with readonly
  • Null initialization for lazy loading

142-163: LGTM! Excellent performance optimization.

Good implementation of caching to avoid repeated heavy decorator instantiation.


33-47: Verify type safety in createObject method.

While the fallback mechanism is good, ensure that all possible class names passed to createObject extend Model to prevent runtime errors.

✅ Verification successful

Type safety is properly maintained

Both Target and TargetResource classes extend from Model (directly or through inheritance), ensuring type safety with the createObject method's return type.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for class declarations to verify they extend Model
ast-grep --pattern 'class $_ extends Model {
  $$$
}'

Length of output: 55


Script:

#!/bin/bash
# Find Target and TargetResource class definitions
rg "class (Target|TargetResource)" -A 5

# Find createObject method implementation
ast-grep --pattern 'function createObject($$$) {
  $$$
}'

# Fallback to grep for createObject
rg "function createObject" -A 5

# Find any base class that Target or TargetResource might extend
rg "class (Target|TargetResource) extends" -A 2

Length of output: 5486


Script:

#!/bin/bash
# Find Resource class definition
rg "class Resource" -A 3

# Alternative search in case Resource is in a namespace
rg "class Resource(\s|$)" -A 3

Length of output: 3468

Comment on lines +213 to +232
public function buildResourceModel(ActiveRecordInterface $resource): object
{
$config = $this->getConfigurationByClass($resource->class);
$config['resourceModel']->setAttributes([

$config->resourceModel->setAttributes([
'type' => $resource->type,
'unit' => $resource->unit,
'quantity' => $resource->getAmount(),
]);

return $config['resourceModel'];
return $config->resourceModel;
}

public function fillTheOriginalModel(Consumption $consumption)
public function fillTheOriginalModel(Consumption $consumption): object
{
$configuration = $this->getConfigurationByClass($consumption->class);
$configuration['model']->setAttributes($consumption->mainObject, false);

return $configuration['model'];
$configuration->model->setAttributes($consumption->mainObject, false);

return $configuration->model;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider improving type safety and validation.

Two potential improvements:

  1. Use a more specific return type instead of object
  2. Consider using setAttributes($attributes, true) to enable validation

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

🧹 Nitpick comments (1)
config/web.php (1)

199-202: Consider the architectural implications of the registry pattern.

The introduction of a billing registry suggests a move towards a more flexible and maintainable billing type configuration system. However, consider the following architectural recommendations:

  1. Document the registry's role and responsibilities
  2. Consider using a non-static factory for better testability
  3. Add integration tests to verify the registry's initialization and configuration
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 0582250 and 1467874.

📒 Files selected for processing (1)
  • config/web.php (1 hunks)
🔇 Additional comments (1)
config/web.php (1)

200-202: Verify the registry initialization.

The new BillingRegistryInterface singleton is initialized using a static factory method. Please ensure that:

  1. The registry is properly initialized with all required billing types
  2. The static initialization doesn't cause any issues with testing or dependency injection

Run this script to verify the usage of BillingRegistryInterface across the codebase:

✅ Verification successful

The registry initialization appears to be properly implemented

The implementation shows good practices:

  • Registry is properly configured as a singleton in the DI container
  • Consumer classes correctly use dependency injection
  • Static initialization is isolated to the configuration layer

While there is one static call in ResourceHelper, it's an acceptable utility usage that doesn't impact the overall architecture.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check how BillingRegistryInterface is used across the codebase

# Find all files that use BillingRegistryInterface
echo "Files using BillingRegistryInterface:"
rg -l "BillingRegistryInterface"

# Find all calls to buildRegistry
echo -e "\nCalls to buildRegistry:"
rg "buildRegistry\(\)"

Length of output: 552


Script:

#!/bin/bash
# Check implementation and test coverage

# Find TariffConfiguration implementation
echo "TariffConfiguration implementation:"
rg -p "class TariffConfiguration"

# Look for buildRegistry implementation
echo -e "\nbuildRegistry implementation:"
ast-grep --pattern 'static function buildRegistry() { $$$ }'

# Check test files
echo -e "\nTest files mentioning BillingRegistryInterface:"
fd -e php test | xargs rg "BillingRegistryInterface"

# Check how it's used in the dependent files
echo -e "\nUsage patterns:"
rg -A 5 "BillingRegistryInterface" --type php

Length of output: 3002


Script:

#!/bin/bash
# Check for registry implementation and test helpers

# Look for buildRegistry implementation in vendor
echo "Looking for TariffConfiguration in vendor:"
fd -t f TariffConfiguration.php

# Check for test helpers or mocks
echo -e "\nLooking for test helpers or mocks:"
fd -e php -t f mock test
fd -e php -t f fake test

# Check ResourceHelper implementation
echo -e "\nResourceHelper implementation:"
rg -p "class ResourceHelper" -A 10

Length of output: 1008

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