Skip to main content

Avoid using `loadByProperties` to load entities

Published on

Drupal's entity storages have a loadByProperties method to simplify loading entities based on conditions. For configuration entities, these are on their properties. For content entities, these are on their field values. It is a common carry-over from the old days of Drupal 7 with entity_load_multiple and the properties condition argument.

There is just one big problem! The loadByProperties method disables entity access checks. That makes this method unsafe and causes it to bypass entity query access checks.

  public function loadByProperties(array $values = []) {
    // Build a query to fetch the entity IDs.
    $entity_query = $this->getQuery();
    $entity_query->accessCheck(FALSE);
    $this->buildPropertyQuery($entity_query, $values);
    $result = $entity_query->execute();
    return $result ? $this->loadMultiple($result) : [];
  }

The method's documentation does not specify this fact, either. I am sure this also simplified the migration from Drupal 7 to Drupal 8 for countless projects.

  /**
   * Load entities by their property values.
   *
   * @param array $values
   *   An associative array where the keys are the property names and the
   *   values are the values those properties must have.
   *
   * @return \Drupal\Core\Entity\EntityInterface[]
   *   An array of entity objects indexed by their ids.
   */
  public function loadByProperties(array $values = []);

Drupal doesn't provide much for entity query access control out of the box. Nodes have access grants, and that is just about it. However, the Entity API module provides a query access handler leveraged by the Group module and the Commerce module. 

Entity access checks at the query level can filter out unpublished entities that the current user may not have access to. It can filter out bundles of an entity type that the user doesn't have access to. It can ensure a user only sees their entities and not other users' entities.

In fact, with Drupal 10, you must explicitly specify if the query should or should not perform access checks

What should you do if you're leveraging loadByProperties? Run your entity queries with access checks explicitly defined or write a repository service for interacting with an entity type's storage to perform the loading of entities via a query.

I'm available for one-on-one consulting calls – click here to book a meeting with me 🗓️

#