You are here

protected function AppQueryBase::getFromStorage in Apigee Edge 8

Loads entities from the entity storage for querying.

Return value

\Drupal\Core\Entity\EntityInterface[] Array of matching entities.

Throws

\Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException

Overrides Query::getFromStorage

File

src/Entity/Query/AppQueryBase.php, line 54

Class

AppQueryBase
Base entity query class for developer- and team apps.

Namespace

Drupal\apigee_edge\Entity\Query

Code

protected function getFromStorage() : array {

  /** @var \Drupal\apigee_edge\Entity\Storage\AppStorage $storage */
  $storage = $this->entityTypeManager
    ->getStorage($this->entityTypeId);
  $ids = NULL;
  $app_owner_in_conditions = NULL;
  $app_name = NULL;
  $original_conditions =& $this->condition
    ->conditions();
  $filtered_conditions = [];
  foreach ($original_conditions as $key => $condition) {
    $filtered_conditions[$key] = $condition;
    if (in_array($condition['field'], $this
      ->appOwnerConditionFields()) && in_array($condition['operator'], [
      NULL,
      '=',
    ])) {

      // Indicates whether we found a single app owner id in this condition
      // or not.
      $app_owner_id_found = FALSE;
      if (!is_array($condition['value'])) {
        $app_owner_in_conditions = $condition['value'];
        $app_owner_id_found = TRUE;
      }
      elseif (is_array($condition['value']) && count($condition['value']) === 1) {
        $app_owner_in_conditions = reset($condition['value']);
        $app_owner_id_found = TRUE;
      }
      if ($app_owner_id_found) {

        // Sanity- and security check. The developer who set an empty value
        // (null, false, '', etc) as the value of an app owner id condition
        // probably made an unintentional mistake. If we would still load all
        // apps in this case that could lead to information
        // disclosure or worse case a security leak.
        if (empty($app_owner_in_conditions)) {
          return [];
        }
        else {

          // We have a valid app owner id that can be passed to Apigee Edge
          // to return its apps.
          unset($filtered_conditions[$key]);
        }
      }
    }
    elseif ($condition['field'] === 'name' && in_array($condition['operator'], [
      NULL,
      '=',
    ])) {
      $app_name_found = FALSE;
      if (!is_array($condition['value'])) {
        $app_name = $condition['value'];
        $app_name_found = TRUE;
      }
      elseif (is_array($condition['value']) && count($condition['value']) === 1) {
        $app_name = reset($condition['value']);
        $app_name_found = TRUE;
      }
      if ($app_name_found) {

        // The same as above, the provided condition can not be evaluated
        // on Apigee Edge so let's return immediately.
        if (empty($app_name)) {
          return [];
        }
        else {

          // We have a valid app name that can be passed to Apigee Edge
          // to return its apps.
          unset($filtered_conditions[$key]);
        }
      }
    }
  }

  // Remove conditions that is going to be applied on Apigee Edge
  // (by calling the proper API with the proper parameters).
  // We do not want to apply the same filters on the result in execute()
  // again.
  $original_conditions = $filtered_conditions;

  // Load only one app owner's apps instead of all apps.
  if ($app_owner_in_conditions !== NULL) {

    // Load only one app instead of all apps of an app owner.
    if ($app_name !== NULL) {

      // Try to retrieve the appId from the cache, because if we load the
      // app with that then we can leverage the our entity cache.
      $app_id = $storage
        ->getCachedAppId($app_owner_in_conditions, $app_name);
      if ($app_id) {
        try {
          $entity = $storage
            ->load($app_id);

          // If the app found in the cache then return it, if not then it can
          // mean that the cached app id is outdated (ex.: app had been
          // deleted from Apigee Edge in somewhere else than the Developer
          // Portal). In that case try to load the app by name directly from
          // Apigee Edge.
          if ($entity) {
            return [
              $entity,
            ];
          }
        } catch (EntityStorageException $e) {

          // Just catch it and try to load the app by name.
        }
      }
      try {

        /** @var \Apigee\Edge\Api\Management\Entity\AppInterface $entity */
        $entity = $this
          ->appByOwnerController($app_owner_in_conditions)
          ->load($app_name);

        // We have to use the storage because it ensures that next time the
        // app can be found in the cache (and various other things as well).
        return [
          $storage
            ->load($entity
            ->getAppId()),
        ];
      } catch (ApiException $e) {

        // App does not exists with name.
      }
      return [];
    }
    else {

      // Get the name of apps that the app owner owns. Apigee Edge only
      // returns the name of the apps therefore the response body should
      // be a lot smaller compared with retrieving all app entity data - maybe
      // unnecessarily if we already have them in cache - and it should be
      // produced and retrieved more quickly.
      $app_names = $this
        ->appByOwnerController($app_owner_in_conditions)
        ->getEntityIds();
      $cached_app_ids = array_map(function ($app_name) use ($storage, $app_owner_in_conditions) {
        return $storage
          ->getCachedAppId($app_owner_in_conditions, $app_name);
      }, $app_names);

      // Remove those null values that indicates an app name could not be
      // found in cache.
      $cached_app_ids = array_filter($cached_app_ids);

      // It seems that we might have all apps in cache that this app owner
      // owns at this moment.
      if (count($app_names) === count($cached_app_ids)) {
        return $storage
          ->loadMultiple($cached_app_ids);
      }

      // It seems we do not have cached app ids for all apps that this
      // app owner owns.
      // We need app ids (UUIDs) first that are only available on app
      // entities therefore we have to load them by using the controller.
      // After we have the app ids we have to let the storage to load
      // entities again, because that ensures that new entities being cached
      // and all hooks and events are being called and trigger (besides
      // other various tasks).
      // (Add static cache to the controller if this still not performs as
      // good as expected.)
      $ids = array_map(function ($entity) {

        /** @var \Drupal\apigee_edge\Entity\AppInterface $entity */
        return $entity
          ->getAppId();
      }, $this
        ->appByOwnerController($app_owner_in_conditions)
        ->getEntities());
      if ($ids) {
        return $storage
          ->loadMultiple($ids);
      }
    }

    // The app owner has no apps, do not call Apigee Edge unnecessarily.
    return [];
  }
  return parent::getFromStorage();
}