Problem/Motivation

It would be convenient if GroupMembershipInterface::getGroupMembers returned an array of assets keyed by their ID. The current implementation does not specify what the array keys will be and actually behaves differently depending on if $recurse is specified.

The relevant code is here: https://github.com/farmOS/farmOS/blob/30f70615b949291f04d29ea78c4007d2a6...

    ....
    /** @var \Drupal\asset\Entity\AssetInterface[] $assets */
    $assets = $this->entityTypeManager->getStorage('asset')->loadMultiple($asset_ids);
    if ($recurse) {
      // Iterate through the assets to check if any of them are groups.
      $groups = array_filter($assets, function (AssetInterface $asset) {
        return $asset->bundle() === 'group';
      });
      $assets = array_merge($assets, $this->getGroupMembers($groups));
    }
    return $assets;

When $recurse = FALSE we return EntityStorageInterface::loadMultiple directly:

  /**
   * Loads one or more entities.
   *
   * @param $ids
   *   An array of entity IDs, or NULL to load all entities.
   *
   * @return \Drupal\Core\Entity\EntityInterface[]
   *   An array of entity objects indexed by their IDs. Returns an empty array
   *   if no matching entities are found.
   */
  public function loadMultiple(array $ids = NULL);

When $recurse = TRUE (the default value) we always return the result of array_merge which *appends* the values of all numeric keys. This always results in an array starting at index 0.

Returning an array of assets keyed by the asset ID is preferable. One example is that it makes it easier to build an options array required for checkbox/select form elements using array_map:

    // Get group members.
    $group_members = $this->groupMembership->getGroupMembers($groups, TRUE);

    // Build group options.
    $group_options = array_map(function (AssetInterface $asset) {
      return $asset->label();
    }, $group_members);
    natsort($group_options);
    
     $form['group'] = [
        '#type' => 'select',
        '#title' => $this->t('Group'),
        '#options' => $group_options,
     ];

Steps to reproduce

N/A

Proposed resolution

Update GroupMembershipInterface::getGroupMembers to always return an array of assets keyed by asset ID.

The technical "fix" for this one implementation is simple - change array_merge to use array_replace instead.

Remaining tasks

  • Determine if we want to make this change. Challenges maintaining this going forward?
  • Determine if we should make this same change anywhere else?
  • Add/update tests to ensure asset IDs are returned as the keys, with both $recurse options.

User interface changes

None.

API changes

Update/clarify the expected array keys from GroupMembershipInterface::getGroupMembers

Data model changes

None.

Comments

paul121 created an issue. See original summary.

paul121’s picture

Issue summary: View changes
m.stenta’s picture

Determine if we want to make this change. Challenges maintaining this going forward?

Makes sense to me!

Determine if we should make this same change anywhere else?

Location (and maybe Inventory?) are the only other places that come to mind... not sure if they need something similar. But that can be done in a separate issue IMO.

paul121’s picture

Status: Active » Needs review
m.stenta’s picture

LGTM!

Location (and maybe Inventory?) are the only other places that come to mind... not sure if they need something similar. But that can be done in a separate issue IMO.

I took a quick look at these and I don't think any changes are needed. The AssetLocation::getAssetsByLocation() method simply returns the result of $this->entityTypeManager->getStorage('asset')->loadMultiple($asset_ids), so it will be keyed by asset ID.

And there is no similar code in the inventory logic that I can see.

  • m.stenta committed eb8a71d on 2.x
    Issue #3259245: Change getGroupMembers to return an array of assets...
m.stenta’s picture

Status: Needs review » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.