I've got a form, which when I use normally works perfectly fine, but when I load the form in phpunit I get the following error :

  1. Drupal\digest\tests\DigestSubscriptionFormTest::testFormDisplay Exception: Warning: array_flip(): Can only flip STRING and INTEGER values! Drupal\Core\Entity\EntityStorageBase->loadMultiple()() (Line: 261)

Within buildForm I have something like this :

    $digest_storage = $this->entityTypeManager->getStorage('digest');
    $digests = $digest_storage->loadMultiple();
    $subscription_storage = $this->entityTypeManager->getStorage('subscription');

    /** @var \Drupal\digest\Entity\DigestInterface $digest */
    foreach ($digests as $digest) {

      $query = $subscription_storage->getQuery();
      // There should never be more than one ID returned.
      $subscription_id = $query->condition('digest', $digest->id())
        ->condition('uid', $this->currentUser->id())
        ->execute();

      /** @var \Drupal\digest\Entity\SubscriptionInterface $subscription_entity */
      $subscription_entity = $subscription_storage->load(current($subscription_id));
      $entity_exists = isset($subscription_entity);

Now when I am using this on my own it works just fine. No errors or warnings at all.

As soon as I get the page from phpunit I get the above error. Here's the test

  public function testFormDisplay() {

    $this->drupalLogin($this->adminUser);

    // Create some basic digests to view.
    $digest_storage = \Drupal::entityTypeManager()->getStorage('digest');
    $digest_storage->create([
      'id' => 'viewOne',
      'label' => 'View One',
      'enabled' => TRUE,
      'title' => 'Custom Title',
      'description' => 'Custom description',
      'send_at' => 'Monday',
    ])->save();
    $digest_storage->create([
      'id' => 'viewTwo',
      'label' => 'View Two',
      'enabled' => FALSE,
      'title' => 'Ghost',
      'description' => 'I\'m invisible',
      'send_at' => 'Friday',
    ])->save();

    // Load the subscription form.
    $this->drupalGet(Url::fromRoute('digest.digest_subscriptions'));

Adding the drupalGet line makes the test fail. If I remove the creation of the entities it works.

I'm not only wondering how to fix this but also why? This is a functional test so it should have a full site meaning I should be able to use the entityTypeManager as normal correct? Mocking is only needed for unit and some kernel tests right?

有帮助吗?

解决方案

In the code shown for buildForm() there are two calls to loadMultiple():

  • The explicit call in the $digests = $digest_storage->loadMultiple(); line
  • The implicit call in the $subscription_entity = $subscription_storage->load(current($subscription_id)); line

The second line is an implicit call to loadMultiple() because the default implementation of load() (EntityStorageBase::load()) uses the following code.

assert(!is_null($id), sprintf('Cannot load the "%s" entity with NULL ID.', $this->entityTypeId));
$entities = $this->loadMultiple([$id]);
return isset($entities[$id]) ? $entities[$id] : NULL;

EntityStorageBase::loadMultiple() uses the following code.

$entities = [];
$preloaded_entities = [];

// Create a new variable which is either a prepared version of the $ids
// array for later comparison with the entity cache, or FALSE if no $ids
// were passed. The $ids array is reduced as items are loaded from cache,
// and we need to know if it is empty for this reason to avoid querying the
// database when all requested entities are loaded from cache.
$flipped_ids = $ids ? array_flip($ids) : FALSE; // This is line 261, in Drupal 9.0.x.

array_flip() raises the Can only flip STRING and INTEGER values! warning when the array passed as argument doesn't contain a string or an integer value, which also happens when the array contains one or more NULL values, or even FALSE values.
This means, for example, that the following line isn't setting $subscription_id to an integer or a string, possibly because there aren't any digest entity whose ID is $digest->id() associated with the subscription entity, or associated with the currently logged-in user.

$subscription_id = $query->condition('digest', $digest->id())
  ->condition('uid', $this->currentUser->id())
  ->execute();

This is the probable cause, giving that the code of that test isn't creating any subscription entity. If creating a digest entity is supposed to create a subscription entity, then it's not creating a subscription entity that is associated with a digest entity with that ID or with the currently logged-in user.

(I assume $digest->id() is returning an integer, since that is the usual case. I would verify that too, but since it's the test that is failing, it seems more probable the cause of the warning is the one I described.)

许可以下: CC-BY-SA归因
scroll top