Problem/Motivation

There are lots of issues about ContentStorageBase producing a warning 'Warning: array_flip(): Can only flip STRING and INTEGER values'.

This happens here:

    $flipped_ids = $ids ? array_flip($ids) : FALSE;

If the $ids array can't be flipped, then that means it contains things that aren't valid entity IDs, such as arrays. So the parameter passed in is incorrect.

It also means the entity load isn't going to work as expected.

The method should throw an exception to allow for better DX.

(Adding related issues which propose different methods for improving this.)

Steps to reproduce

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Issue fork drupal-3221534

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

joachim created an issue. See original summary.

joachim’s picture

Something like this:

    if ($ids) {
      if ($bad_ids = array_filter($ids, function($id) { return (!is_int($id) && !is_string($id)); })) {
        throw new \InvalidArgumentException("Array of IDs passed to loadMultiple() must contain only strings or integers, found " . print_r($bad_ids, TRUE));
      }
    }

guilhermevp made their first commit to this issue’s fork.

guilhermevp’s picture

Status: Active » Needs review

Followed @joachim suggestion since seemed good for me. Just changed $bad_ids to $invalid_ids that I felt was more clear. Please review.

daffie’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

Fix looks good. Now it needs a test.

joachim’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests

Done.

daffie’s picture

Status: Needs review » Needs work

@joachim: Thank you for adding the testing.

Just a couple of nitpicks and than it is RTBC for me.

joachim’s picture

Status: Needs work » Needs review

Fixed all three. (Gitlab is not letting me mark the comments as resolved??)

daffie’s picture

Status: Needs review » Reviewed & tested by the community

The change look good to me.
The fix has testing for it.
The new exception has documentation.
For me it is RTBC.

@joachim: Only the person who creates the MR is allowed to mark threads as resolved at the moment. I am just working with the tools that we have.

joachim’s picture

I was sure I'd marked someone else's comments as resolved before! Oh well!

Thanks for the review :)

seanb’s picture

Not really sure about throwing an exception here. Loading entities is something that is done A LOT in custom and contrib code. As mentioned in #3037956: Improve DX of load / loadMultiple / loadRevisionload / loadMultipleRevisions:

While you could argue the calling code should not call the method with "garbage" input, this means that calling code always needs to do 2 checks:
1. Is the input a string or int.
2. Is the return value of the specific load method not NULL.

It would be nice if you could call load() / loadMultiple() / loadRevision() / loadMultipleRevisions() without having to check the input, and let the load methods return NULL if it can't find an entity. I've seen methods (like ContentEntityStorageBase::getLatestTranslationAffectedRevisionId()) that could return a entity ID or NULL and I think the DX would be a bit better if you don't have to do the extra check.

joachim’s picture

> While you could argue the calling code should not call the method with "garbage" input, this means that calling code always needs to do 2 checks

I've often hit this problem with migrations, where I definitely *do* want an exception to be thrown so I understand why the migration isn't running correctly.

catch’s picture

Status: Reviewed & tested by the community » Needs work

Throwing an exception here can only change in a major release - there is plenty of contrib and custom code out there resulting in this error, which will result in fatal errors on production sites if we just change it in a minor.

However we can prepare to throw the exception and log a more useful error message (and maybe a backtrace) in the meantime.

Also pretty sure there are old issues for this around.

joachim’s picture

> However we can prepare to throw the exception

Is there anything you mean beyond having a MR ready for Drupal 10?

Is there an equivalent to a deprecation error that would say 'This call will cause an exception to be thrown in a future version of Drupal'?

daffie’s picture

We can do a @trigger_error(), just like a deprecation message that in D10 the message will be replaced by an exception.

catch’s picture

Yes exactly what @daffie said (and also the second half of my sentence).

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

joachim’s picture

Rebased to 9.5.x (I'm not yet working on 10, need up upgrade my MAMP to get PHP 8.1).

joachim’s picture

Status: Needs work » Needs review

> We can do a @trigger_error(), just like a deprecation message that in D10 the message will be replaced by an exception

Done.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new149 bytes

The Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

hugronaphor’s picture

Edge-case:

I have 0, 1 or 2 entities to load and the order matters in my case.
For performance reasons I want to load them `loadMultiple()`

$nodeIds = [
  $queryPrev->execute()->fetchField(),
  $queryNext->execute()->fetchField(),
];
$nodes = $this->entityTypeManager->getStorage('node')->loadMultiple($nodeIds);
return [
  '#prev' => !empty($nodes[$nodeIds[0]]) ? $nodes[$nodeIds[0]] : NULL,
  '#next' => !empty($nodes[$nodeIds[1]]) ? $nodes[$nodeIds[1]] : NULL,
];

To avoid the warning you need extensive logic. E.g:

if (count(array_filter($nodeIds)) === 2) {
  $nodes = $this->entityTypeManager->getStorage('node')->loadMultiple($nodeIds);
}
elseif (!empty($nodeIds[0])) {
  $nodes = [
    $this->entityTypeManager->getStorage('node')->load($nodeIds[0]),
    NULL,
  ];
}
elseif (!empty($nodeIds[1])) {
  $nodes = [
    NULL,
    $this->entityTypeManager->getStorage('node')->load($nodeIds[1]),
  ];
}

But if you would have 3, 4, 5 entities to load multiple single loads would be needed.

I'm not demanding changes, just wanted to point out to this DX

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

rakshith.thotada’s picture

Version: 11.x-dev » 10.2.x-dev
Status: Needs work » Needs review
StatusFileSize
new1023 bytes

Rerolled the patch for Drupal 10.2.x

smustgrave’s picture

Version: 10.2.x-dev » 11.x-dev
Status: Needs review » Needs work

Current development branch is 11.x and changes should be in MRs

rakshith.thotada’s picture

Removing the patch as we already have the patch here https://www.drupal.org/files/issues/2023-01-12/3145190-21.patch