Skip to content

Institution : Set Office Details#481

Merged
belwalshubham merged 5 commits intodevelopfrom
feat/institution-setOfficeDetails
Nov 23, 2024
Merged

Institution : Set Office Details#481
belwalshubham merged 5 commits intodevelopfrom
feat/institution-setOfficeDetails

Conversation

@belwalshubham
Copy link
Copy Markdown
Collaborator

@belwalshubham belwalshubham commented Nov 22, 2024

  • Assign Goonj office based on state
  • Assign Coordinating POC

Summary by CodeRabbit

  • New Features

    • Enhanced InstitutionService class with improved event handling and data processing logic.
    • Introduced a new method to retrieve contact subtype names associated with entity IDs.
  • Bug Fixes

    • Improved error handling for cases where state IDs and organization data are not found.
  • Documentation

    • Updated method signatures for clarity and consistency.

@belwalshubham belwalshubham self-assigned this Nov 22, 2024
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Nov 22, 2024

Walkthrough

The changes in this pull request focus on the InstitutionService class and the CollectionSource trait within the Civi extension. Key modifications include the introduction of a new constant, a private method for field retrieval, and updates to existing methods for improved event handling and data processing. The setOfficeDetails method's parameters have been revised, and a new method to fetch contact subtype names has been added to the trait, enhancing the overall functionality and clarity of these components.

Changes

File Path Change Summary
wp-content/civi-extensions/goonjcustom/Civi/InstitutionService.php - Updated setOfficeDetails method signature and logic.
- Added findStateField method.
- Introduced constant ENTITY_SUBTYPE_NAME with value 'Institute'.
- Updated getSubscribedEvents to listen for &hook_civicrm_custom.
- Modified getRelationshipTypeName method to return NULL if no organization is found.
wp-content/civi-extensions/goonjcustom/Civi/Traits/CollectionSource.php - Added getContactSubtypeName method to retrieve contact subtype name based on entity ID.

Possibly related PRs

Suggested labels

status : ready for review

Suggested reviewers

  • tarunnjoshi
  • nishant22029

🎉 In the code where logic flows,
New methods and constants now brightly glow.
From setOfficeDetails to findStateField,
A clearer structure, the changes have revealed.
With traits that gather subtypes with ease,
This PR brings improvements that aim to please! 🌟

Warning

Rate limit exceeded

@belwalshubham has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 3 minutes and 33 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 4116aca and 4f9ea05.


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 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
Copy Markdown

@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

🧹 Outside diff range and nitpick comments (7)
wp-content/civi-extensions/goonjcustom/Civi/Traits/CollectionSource.php (3)

48-50: Add PHPDoc documentation for the new method.

Please add comprehensive PHPDoc documentation including:

  • Method description
  • @param annotation with type and description
  • @return annotation with type and description
 /**
-  *
+  * Retrieves the contact subtype name for a given entity ID.
+  *
+  * @param int $entityID The ID of the organization entity
+  * @return string|null The contact subtype name or null if not found
   */

48-65: Consider abstracting common API call patterns.

The trait has multiple methods making similar API calls to fetch subtype information. Consider creating a private helper method to handle the common API call pattern.

Example abstraction:

/**
 * Makes a standardized API call to fetch entity information.
 *
 * @param string $entity The API entity name
 * @param string $field The field to select
 * @param int $id The entity ID
 * @return array|null The API result
 */
private static function fetchEntityField($entity, $field, $id) {
    $result = civicrm_api4($entity, 'get', [
        'select' => [$field],
        'where' => [['id', '=', $id]],
        'checkPermissions' => FALSE,
    ]);
    return $result[0][$field] ?? NULL;
}

This would allow simplifying both getContactSubtypeName and getEntitySubtypeName methods.


Line range hint 1-66: Consider reviewing the trait's design for testability and responsibility separation.

The current implementation using static methods and properties makes unit testing more challenging and creates global state. Consider:

  1. Moving towards instance methods for better testability
  2. Separating contact-specific and entity-specific subtype handling into different traits

This would allow for better dependency injection and easier testing. For example:

trait ContactSubtypeSource {
    protected $api;
    
    public function setApi($api) {
        $this->api = $api;
    }
    
    public function getContactSubtypeName($entityID) {
        // Implementation using instance methods
    }
}
wp-content/civi-extensions/goonjcustom/Civi/InstitutionService.php (4)

34-56: Improve parameter naming and code clarity in findStateField method

The parameter $array in the findStateField method is not descriptive. To enhance code readability and maintain coding standards, consider renaming it to something more indicative of its purpose, such as $params or $customFieldsArray.


141-147: Consolidate multiple Organization::update calls to reduce code duplication

There are two consecutive Organization::update calls that update the same organization with different values:

Organization::update('Organization', FALSE)
  ->addValue('Review.Status', 1)
  ->addValue('Review.Initiated_by', 1)
  ->addWhere('id', '=', $contactId)
  ->execute();

Organization::update('Organization', FALSE)
  ->addValue('Review.Coordinating_POC', $coordinatorId)
  ->addWhere('id', '=', $contactId)
  ->execute();

To improve efficiency and adhere to the DRY (Don't Repeat Yourself) principle, consider combining these into a single update call.

Apply this diff to refactor the code:

 Organization::update('Organization', FALSE)
   ->addValue('Review.Status', 1)
   ->addValue('Review.Initiated_by', 1)
+  ->addValue('Review.Coordinating_POC', $coordinatorId)
   ->addWhere('id', '=', $contactId)
   ->execute();
-
-Organization::update('Organization', FALSE)
-  ->addValue('Review.Coordinating_POC', $coordinatorId)
-  ->addWhere('id', '=', $contactId)
-  ->execute();

204-211: Ensure consistent return values in getRelationshipTypeName method

In the getRelationshipTypeName method, if $organization is not found, the function returns without a value:

if (!$organization) {
  return;
}

For clarity and to maintain consistent return types, consider explicitly returning NULL to indicate that no relationship type name is available.

Apply this diff:

 if (!$organization) {
-  return;
+  return NULL;
 }

Line range hint 70-146: Refactor setOfficeDetails method to adhere to Single Responsibility Principle

The setOfficeDetails method handles multiple responsibilities, including validating parameters, fetching data, and updating records. This can make the code harder to read and maintain. To improve code quality, consider refactoring this method into smaller, focused methods that each handle a single responsibility.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between b9ac20a and 4ddff3e.

📒 Files selected for processing (2)
  • wp-content/civi-extensions/goonjcustom/Civi/InstitutionService.php (4 hunks)
  • wp-content/civi-extensions/goonjcustom/Civi/Traits/CollectionSource.php (1 hunks)
🔇 Additional comments (1)
wp-content/civi-extensions/goonjcustom/Civi/Traits/CollectionSource.php (1)

51-65: Verify usage and impact of the new method.

Let's verify where this new method is being used and ensure it's properly integrated.

✅ Verification successful

The new method is properly integrated and used correctly

The getContactSubtypeName method is:

  • Correctly implemented in the CollectionSource trait
  • Properly imported and used in InstitutionService class
  • Used appropriately to check for institute subtype (ENTITY_SUBTYPE_NAME = 'Institute') in a guard clause
  • Has no breaking changes as it's the only usage of the Organization API endpoint in this context
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usages of getContactSubtypeName
rg "getContactSubtypeName" --type php

# Look for potential breaking changes in Organization API usage
rg "civicrm_api4\('Organization'" --type php

Length of output: 521


Script:

#!/bin/bash
# Let's check the context of usage in InstitutionService.php
rg -B 5 -A 5 "getContactSubtypeName" wp-content/civi-extensions/goonjcustom/Civi/InstitutionService.php

# Check if ENTITY_SUBTYPE_NAME is defined in the same class
rg "ENTITY_SUBTYPE_NAME" wp-content/civi-extensions/goonjcustom/Civi/InstitutionService.php

# Check if InstitutionService uses CollectionSource trait
ast-grep --pattern 'class InstitutionService {
  $$$
}'

Length of output: 10042


Script:

#!/bin/bash
# Let's check if InstitutionService uses the CollectionSource trait with a different pattern
rg -B 2 -A 2 "class InstitutionService" wp-content/civi-extensions/goonjcustom/Civi/InstitutionService.php

# Check for use statements of CollectionSource trait
rg "use.*CollectionSource" wp-content/civi-extensions/goonjcustom/Civi/InstitutionService.php

Length of output: 383

Comment on lines +51 to +65
public static function getContactSubtypeName($entityID) {
$getSubtypeName = civicrm_api4('Organization', 'get', [
'select' => [
'contact_sub_type',
],
'where' => [
['id', '=', $entityID],
],
'checkPermissions' => FALSE,
]);

$entityData = $getSubtypeName[0]['contact_sub_type'] ?? [];

return $entityData[0] ?? NULL;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling and reduce code duplication.

The method has several areas for improvement:

  1. No input validation for $entityID
  2. Unsafe array access could trigger notices
  3. Similar code pattern to getEntitySubtypeName suggests potential for abstraction

Consider applying these improvements:

 public static function getContactSubtypeName($entityID) {
+    if (!is_numeric($entityID)) {
+        throw new \InvalidArgumentException('Entity ID must be numeric');
+    }
+
     $getSubtypeName = civicrm_api4('Organization', 'get', [
       'select' => [
         'contact_sub_type',
       ],
       'where' => [
         ['id', '=', $entityID],
       ],
       'checkPermissions' => FALSE,
     ]);

-    $entityData = $getSubtypeName[0]['contact_sub_type'] ?? [];
-
-    return $entityData[0] ?? NULL;
+    return !empty($getSubtypeName[0]['contact_sub_type'][0])
+        ? $getSubtypeName[0]['contact_sub_type'][0]
+        : NULL;
 }
📝 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
public static function getContactSubtypeName($entityID) {
$getSubtypeName = civicrm_api4('Organization', 'get', [
'select' => [
'contact_sub_type',
],
'where' => [
['id', '=', $entityID],
],
'checkPermissions' => FALSE,
]);
$entityData = $getSubtypeName[0]['contact_sub_type'] ?? [];
return $entityData[0] ?? NULL;
}
public static function getContactSubtypeName($entityID) {
if (!is_numeric($entityID)) {
throw new \InvalidArgumentException('Entity ID must be numeric');
}
$getSubtypeName = civicrm_api4('Organization', 'get', [
'select' => [
'contact_sub_type',
],
'where' => [
['id', '=', $entityID],
],
'checkPermissions' => FALSE,
]);
return !empty($getSubtypeName[0]['contact_sub_type'][0])
? $getSubtypeName[0]['contact_sub_type'][0]
: NULL;
}

Comment on lines 80 to 83
$stateId = $stateField['value'];
$contactId = $stateField['entity_id'];

if (!$stateId) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove redundant check for $stateId to eliminate unreachable code

There is a redundant check for $stateId:

if (!$stateId) {
  return;
}

if (!$stateId) {
  \CRM_Core_Error::debug_log_message('Cannot assign Goonj Office to institution id: ' . $contactId);
  return;
}

The first if (!$stateId) block returns early, making the subsequent check unreachable. To adhere to best practices and avoid confusion, consider combining these checks and logging the error before returning.

Apply this diff to fix the issue:

-    if (!$stateId) {
-      return;
-    }
-
-    if (!$stateId) {
+    if (!$stateId) {
       \CRM_Core_Error::debug_log_message('Cannot assign Goonj Office to institution id: ' . $contactId);
       return;
     }

Comment on lines +147 to 150
Organization::update('Organization', FALSE)
->addValue('Review.Coordinating_POC', $coordinatorId)
->addWhere('id', '=', $contactId)
->execute();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

why using two diffrent query to update values of single contact of type organization ?

Copy link
Copy Markdown
Collaborator Author

@belwalshubham belwalshubham Nov 22, 2024

Choose a reason for hiding this comment

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

I’ve added another query because there’s an issue with the form where hidden default values are not being saved. To work around this, I’m updating it through the query.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

but why you are not updating all together

Organization::update('Organization', FALSE)
      ->addValue('Review.Status', 1)
      ->addValue('Review.Initiated_by', 1)
      ->addWhere('id', '=', $contactId)
      ->execute();

Comment on lines 205 to 206
->addSelect('Institute_Registration.Type_of_Institution:label')
->addWhere('id', '=', $contactId)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

fix identation

Comment on lines +52 to +65
$getSubtypeName = civicrm_api4('Organization', 'get', [
'select' => [
'contact_sub_type',
],
'where' => [
['id', '=', $entityID],
],
'checkPermissions' => FALSE,
]);

$entityData = $getSubtypeName[0]['contact_sub_type'] ?? [];

return $entityData[0] ?? NULL;
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

dont use tradional query

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

Copy link
Copy Markdown

@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

🧹 Outside diff range and nitpick comments (2)
wp-content/civi-extensions/goonjcustom/Civi/InstitutionService.php (2)

31-56: Add PHPDoc and type hints to improve code clarity

The new findStateField method would benefit from proper documentation and type hints.

-  private static function findStateField(array $array) {
+  /**
+   * Finds the state field in the given array of custom fields.
+   *
+   * @param array $array Array of custom fields
+   * @return array|false Returns field data if found, FALSE otherwise
+   */
+  private static function findStateField(array $array): array|false {

204-212: Enhance error handling in getRelationshipTypeName

While the null check is good, consider:

  1. Adding type hints
  2. Using early return pattern
  3. Adding logging for debugging
-  private static function getRelationshipTypeName($contactId) {
+  private static function getRelationshipTypeName(int $contactId): ?string {
     $organization = Organization::get(FALSE)
       ->addSelect('Institute_Registration.Type_of_Institution:label')
       ->addWhere('id', '=', $contactId)
       ->execute()->single();

     if (!$organization) {
+      \CRM_Core_Error::debug_log_message("Organization not found for contact ID: $contactId");
       return NULL;
     }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 4ddff3e and 27c5b01.

📒 Files selected for processing (2)
  • wp-content/civi-extensions/goonjcustom/Civi/InstitutionService.php (4 hunks)
  • wp-content/civi-extensions/goonjcustom/Civi/Traits/CollectionSource.php (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • wp-content/civi-extensions/goonjcustom/Civi/Traits/CollectionSource.php
🔇 Additional comments (4)
wp-content/civi-extensions/goonjcustom/Civi/InstitutionService.php (4)

6-6: LGTM: Clean trait integration and imports

The addition of the CustomField API import and CollectionSource trait integration follows PSR standards and improves code organization.

Also applies to: 10-10, 16-16


18-18: LGTM: Well-defined constant

Good practice to define 'Institute' as a constant, making it easier to maintain and reuse.


Line range hint 89-93: Redundant state ID checks still present

This is a duplicate of a previous review comment. The redundant checks should be combined.


25-28: Verify the hook timing change impact

The switch from hook_civicrm_post to hook_civicrm_custom changes when the office details are set. Please ensure this doesn't affect the order of operations or cause any race conditions.

✅ Verification successful

Let me analyze the hook timing change impact based on the search results.

Hook timing change is appropriate and safe

The switch from hook_civicrm_post to hook_civicrm_custom for setting office details is actually more appropriate because:

  1. hook_civicrm_custom is specifically designed to handle custom field changes, which aligns better with setting office details
  2. The codebase shows other services like DroppingCenterService and CollectionCampService also using hook_civicrm_custom for setOfficeDetails method, indicating this is the established pattern
  3. There are no race conditions evident since:
    • hook_civicrm_custom fires when custom fields are saved
    • The office details are derived from custom fields
    • No other critical dependencies rely on this hook timing
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other usages of these hooks to understand the execution order
rg -A 3 "hook_civicrm_(custom|post)" --type php

Length of output: 55411

Comment on lines +76 to +80
Organization::update('Organization', FALSE)
->addValue('Review.Status', 1)
->addValue('Review.Initiated_by', 1)
->addWhere('id', '=', $contactId)
->execute();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Wrap multiple database operations in a transaction

Multiple update operations should be wrapped in a transaction to ensure data consistency.

+    try {
+      \CRM_Core_Transaction::create()->run(function() use ($contactId, $coordinatorId) {
         Organization::update('Organization', FALSE)
           ->addValue('Review.Status', 1)
           ->addValue('Review.Initiated_by', 1)
           ->addWhere('id', '=', $contactId)
           ->execute();
         
         Organization::update('Organization', FALSE)
           ->addValue('Review.Coordinating_POC', $coordinatorId)
           ->addWhere('id', '=', $contactId)
           ->execute();
+      });
+    } catch (\Exception $e) {
+      \CRM_Core_Error::debug_log_message('Failed to update organization: ' . $e->getMessage());
+      return FALSE;
+    }

Also applies to: 147-150

Copy link
Copy Markdown

@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

🧹 Outside diff range and nitpick comments (2)
wp-content/civi-extensions/goonjcustom/Civi/InstitutionService.php (2)

13-15: Add comprehensive class documentation

The class lacks proper PHPDoc documentation. Consider adding a detailed description of the class's purpose, responsibilities, and usage.

Add documentation like this:

 /**
- *
+ * Service class for handling institution-related operations.
+ * 
+ * This class manages the assignment of office details and coordinates
+ * relationships between institutions and Goonj offices.
  */

31-34: Add method documentation

The findStateField method lacks PHPDoc documentation. Add parameter and return type information.

Add documentation like this:

 /**
-  *
-  */
+  * Finds the state field in the given array of custom fields.
+  *
+  * @param array $array The array of custom fields to search
+  * @return array|false Returns the field data or FALSE if not found
+  */
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 27c5b01 and 4116aca.

📒 Files selected for processing (2)
  • wp-content/civi-extensions/goonjcustom/Civi/InstitutionService.php (4 hunks)
  • wp-content/civi-extensions/goonjcustom/Civi/Traits/CollectionSource.php (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • wp-content/civi-extensions/goonjcustom/Civi/Traits/CollectionSource.php
🔇 Additional comments (2)
wp-content/civi-extensions/goonjcustom/Civi/InstitutionService.php (2)

88-92: ⚠️ Potential issue

Combine organization updates and wrap in transaction

There are two separate organization updates that should be:

  1. Combined into a single update operation
  2. Wrapped in a transaction for data consistency

Apply this diff:

+    try {
+      \CRM_Core_Transaction::create()->run(function() use ($contactId, $coordinatorId) {
         Organization::update('Organization', FALSE)
           ->addValue('Review.Status', 1)
           ->addValue('Review.Initiated_by', 1)
+          ->addValue('Review.Coordinating_POC', $coordinatorId)
           ->addWhere('id', '=', $contactId)
           ->execute();
-
-        Organization::update('Organization', FALSE)
-          ->addValue('Review.Coordinating_POC', $coordinatorId)
-          ->addWhere('id', '=', $contactId)
-          ->execute();
+      });
+    } catch (\Exception $e) {
+      \CRM_Core_Error::debug_log_message('Failed to update organization: ' . $e->getMessage());
+      return FALSE;
+    }

Also applies to: 148-151


25-28: Verify the hook change impact

The switch from hook_civicrm_post to hook_civicrm_custom is a significant change that could affect when the office details are set.

✅ Verification successful

Let me gather more information about the setOfficeDetails method to understand the hook change impact better.


Hook change from post to custom is appropriate for this use case

The change from hook_civicrm_post to hook_civicrm_custom for the setOfficeDetails method is actually correct because:

  1. The setOfficeDetails method's implementation shows it specifically checks for $op === 'create' and handles custom field updates related to state/office details
  2. Other services (DroppingCenterService, CollectionCampService) use the same pattern with hook_civicrm_custom for similar office details functionality
  3. hook_civicrm_custom is more appropriate as it's specifically designed for handling custom field updates, which is what this method does

The change aligns the hook usage with its actual purpose and matches the pattern used across similar services in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other usages of these hooks to ensure no functionality overlap
rg "hook_civicrm_post|hook_civicrm_custom" --type php

Length of output: 16871


Script:

#!/bin/bash
# Search for setOfficeDetails method implementation
ast-grep --pattern 'function setOfficeDetails($$$)'

# Also search for any references to this method
rg "setOfficeDetails" -A 5

Length of output: 14349

Comment on lines +210 to +212
if (!$organization) {
return;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Return default relationship type when organization not found

Instead of returning undefined, return the default coordinator relationship type for consistency.

Apply this diff:

     if (!$organization) {
-      return;
+      return 'Default Coordinator of';
     }
📝 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
if (!$organization) {
return;
}
if (!$organization) {
return 'Default Coordinator of';
}

Copy link
Copy Markdown

@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

🧹 Outside diff range and nitpick comments (1)
wp-content/civi-extensions/goonjcustom/Civi/Traits/CollectionSource.php (1)

49-51: Add proper PHPDoc documentation

The method is missing proper documentation. Please add PHPDoc with:

  • Method description
  • @param annotation with type and description
  • @return annotation with type and description
 /**
-  *
+  * Retrieves the contact subtype name for a given organization entity.
+  *
+  * @param int $entityID The ID of the organization entity
+  * @return string|null The contact subtype name or null if not found
   */
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 4116aca and 4f9ea05.

📒 Files selected for processing (1)
  • wp-content/civi-extensions/goonjcustom/Civi/Traits/CollectionSource.php (2 hunks)
🔇 Additional comments (1)
wp-content/civi-extensions/goonjcustom/Civi/Traits/CollectionSource.php (1)

6-6: LGTM: Proper namespace import

The Organization class import follows PSR-4 standards and is appropriately used.

Comment on lines +52 to +60
public static function getContactSubtypeName($entityID) {
$getSubtypeName = Organization::get(FALSE)
->addSelect('contact_sub_type')
->addWhere('id', '=', $entityID)
->execute()->single();

$entityData = $getSubtypeName['contact_sub_type'] ?? [];
return $entityData[0] ?? NULL;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling and reduce code duplication

The method has several areas for improvement:

  1. Missing input validation
  2. Potential null pointer issues
  3. Similar pattern to getEntitySubtypeName suggests potential for abstraction

Consider applying these improvements:

 public static function getContactSubtypeName($entityID) {
+    if (!is_numeric($entityID)) {
+        throw new \InvalidArgumentException('Entity ID must be numeric');
+    }
+
     $getSubtypeName = Organization::get(FALSE)
       ->addSelect('contact_sub_type')
       ->addWhere('id', '=', $entityID)
       ->execute()->single();

-    $entityData = $getSubtypeName['contact_sub_type'] ?? [];
-    return $entityData[0] ?? NULL;
+    return !empty($getSubtypeName['contact_sub_type'][0])
+        ? $getSubtypeName['contact_sub_type'][0]
+        : NULL;
 }

Additionally, consider creating a base method to handle the common pattern between this and getEntitySubtypeName:

private static function getSubtypeNameFromEntity($entityID, $entityType, $field) {
    if (!is_numeric($entityID)) {
        throw new \InvalidArgumentException('Entity ID must be numeric');
    }

    $result = $entityType::get(FALSE)
        ->addSelect($field)
        ->addWhere('id', '=', $entityID)
        ->execute()->single();

    return !empty($result[$field][0]) ? $result[$field][0] : NULL;
}

Comment on lines +147 to 150
Organization::update('Organization', FALSE)
->addValue('Review.Coordinating_POC', $coordinatorId)
->addWhere('id', '=', $contactId)
->execute();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

but why you are not updating all together

Organization::update('Organization', FALSE)
      ->addValue('Review.Status', 1)
      ->addValue('Review.Initiated_by', 1)
      ->addWhere('id', '=', $contactId)
      ->execute();

@belwalshubham
Copy link
Copy Markdown
Collaborator Author

@nishant22029 just replying here regarding the previous comment. We aren't updating together because there might be a situation where there's no coordinating POC assigned to that institute. In such cases, the review status and the 'initiated by' fields are not updated. These should be updated immediately after fetching the contact ID. Let me know if you have any questions."

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.

2 participants