You are here

abstract class AppStorage in Apigee Edge 8

Base entity storage class for developer and team (company) app entities.

@internal

Hierarchy

Expanded class hierarchy of AppStorage

3 files declare their use of AppStorage
DeveloperAppNameConverter.php in src/ParamConverter/DeveloperAppNameConverter.php
TeamAppNameConverter.php in modules/apigee_edge_teams/src/ParamConverter/TeamAppNameConverter.php
TeamAppStorage.php in modules/apigee_edge_teams/src/Entity/Storage/TeamAppStorage.php

File

src/Entity/Storage/AppStorage.php, line 40

Namespace

Drupal\apigee_edge\Entity\Storage
View source
abstract class AppStorage extends AttributesAwareFieldableEdgeEntityStorageBase {

  /**
   * The app controller service.
   *
   * @var \Drupal\apigee_edge\Entity\Controller\AppControllerInterface
   */
  protected $appController;

  /**
   * AppStorage constructor.
   *
   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
   *   The entity type definition.
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
   *   The cache backend to be used.
   * @param \Drupal\Core\Cache\MemoryCache\MemoryCacheInterface $memory_cache
   *   The memory cache.
   * @param \Drupal\Component\Datetime\TimeInterface $system_time
   *   The system time.
   * @param \Drupal\apigee_edge\Entity\Controller\AppControllerInterface $app_controller
   *   The app controller service.
   */
  public function __construct(EntityTypeInterface $entity_type, CacheBackendInterface $cache_backend, MemoryCacheInterface $memory_cache, TimeInterface $system_time, AppControllerInterface $app_controller) {
    parent::__construct($entity_type, $cache_backend, $memory_cache, $system_time);
    $this->appController = $app_controller;
  }

  /**
   * {@inheritdoc}
   */
  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
    return new static($entity_type, $container
      ->get('cache.apigee_edge_entity'), $container
      ->get('entity.memory_cache'), $container
      ->get('datetime.time'), $container
      ->get('apigee_edge.controller.app'));
  }

  /**
   * {@inheritdoc}
   */
  public function loadUnchanged($id) {

    // Clear the app controller's cache if it has one.
    if ($this->appController instanceof EntityCacheAwareControllerInterface) {

      // Id could be an UUID or an app name.
      // We do not know who is the owner so we have need the app object to be
      // invalidate the app cache entry by the app id (UUID).

      /** @var \Apigee\Edge\Api\Management\Entity\AppInterface $entity */
      $entity = $this
        ->entityController()
        ->load($id);
      $this->appController
        ->entityCache()
        ->removeEntities([
        $entity
          ->getAppId(),
      ]);
    }
    return parent::loadUnchanged($id);
  }

  /**
   * Load app by UUID.
   *
   * This function is more efficient than loadUnchanged(), because it does not
   * need to cover the case when loading is done by App name.
   *
   * @param string $uuid
   *   App UUID.
   *
   * @return \Drupal\apigee_edge\Entity\AppInterface|null
   *   The unchanged entity, or NULL if the entity cannot be loaded.
   *
   * @TODO: this method should be also available in the AppStorageInterface, but
   *   that would be a breaking change, so we can only add that in the next
   *   major version of the module.
   */
  public function loadUnchangedByUuid(string $uuid) : ?AppInterface {

    // Clear the app controller's cache if it has one.
    if ($this->appController instanceof EntityCacheAwareControllerInterface) {
      $this->appController
        ->entityCache()
        ->removeEntities([
        $uuid,
      ]);
    }
    return parent::loadUnchanged($uuid);
  }

  /**
   * {@inheritdoc}
   */
  protected function initFieldValues(FieldableEdgeEntityInterface $entity, array $values = [], array $field_names = []) {

    // Initialize display name and description field's value from the display
    // name attribute if needed.
    // @see \Apigee\Edge\Api\Management\Entity\App::getDisplayName()
    if (!array_key_exists('displayName', $values) && array_key_exists('attributes', $values) && $values['attributes']
      ->has('DisplayName')) {
      $values['displayName'] = $values['attributes']
        ->getValue('DisplayName');
    }

    // @see \Apigee\Edge\Api\Management\Entity\App::getDescription()
    if (!array_key_exists('description', $values) && array_key_exists('attributes', $values) && $values['attributes']
      ->has('Notes')) {
      $values['description'] = $values['attributes']
        ->getValue('Notes');
    }
    parent::initFieldValues($entity, $values, $field_names);
  }

  /**
   * {@inheritdoc}
   */
  protected function getFromStorage(array $ids = NULL) {

    // Try to load entities from the entity controller's static cache.
    if (!empty($ids)) {

      // If $ids are developer app ids (UUIDs) let's check whether all (SDK)
      // entities can be served from the shared app (controller) cache.
      // When AppQueryBase::getFromStorage() tries to reduce the API calls by
      // doing something smart it could happen that entity storage's static
      // cache has not warmed up yet but the shared app cache did.
      // @see \Drupal\apigee_edge\Entity\Query\AppQueryBase::getFromStorage()
      if ($this->appController instanceof EntityCacheAwareControllerInterface) {
        $cached_entities = $this->appController
          ->entityCache()
          ->getEntities($ids);
        if (count($cached_entities) === count($ids)) {
          return $this
            ->processLoadedEntities($ids, $cached_entities);
        }
      }
    }
    return parent::getFromStorage($ids);
  }

  /**
   * {@inheritdoc}
   */
  protected final function getPersistentCacheTags(EntityInterface $entity) {

    /** @var \Drupal\apigee_edge\Entity\AppInterface $entity */
    $cache_tags = parent::getPersistentCacheTags($entity);
    return array_merge($cache_tags, $this
      ->getCacheTagsByOwner($entity));
  }

  /**
   * Generates cache tags for an app.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   App entity.
   *
   * @return array
   *   Array of cache tags.
   */
  private function getPersistentCacheTagsForAppName(EntityInterface $entity) {

    /** @var \Drupal\apigee_edge\Entity\AppInterface $entity */
    $cache_tags = array_merge([
      "{$this->entityTypeId}",
      "{$this->entityTypeId}:app_names",
      "{$this->entityTypeId}:{$entity->id()}",
      "{$this->entityTypeId}:{$entity->id()}:app_name",
    ], $this
      ->getCacheTagsByOwner($entity));
    return $cache_tags;
  }

  /**
   * Returns app owner related cache tags for an app.
   *
   * These cache tags gets added to the generated app cache entry which ensures
   * when app's owner gets deleted the related app cache entries gets
   * invalidated as well.
   *
   * @param \Drupal\apigee_edge\Entity\AppInterface $app
   *   The app entity.
   *
   * @return array
   *   Array of app owner related cache entries.
   *
   * @see getPersistentCacheTags()
   * @see getPersistentCacheTagsForAppName()
   */
  protected abstract function getCacheTagsByOwner(AppInterface $app) : array;

  /**
   * {@inheritdoc}
   */
  public function resetCache(array $ids = NULL) {
    parent::resetCache($ids);
    if ($this->entityType
      ->isStaticallyCacheable() && $ids) {
      $tags = [];
      foreach ($ids as $id) {
        $tags[] = "{$this->entityTypeId}:{$id}:app_name";
      }
      if ($this->entityType
        ->isPersistentlyCacheable()) {
        Cache::invalidateTags($tags);
      }
    }
    else {
      if ($this->entityType
        ->isPersistentlyCacheable()) {
        Cache::invalidateTags([
          $this->entityTypeId . ':app_names',
        ]);
      }
    }

    // We do not reset the app cache because app controllers handles the
    // cache invalidation.
    // We tried to call it once here, but then we had some trouble with app
    // creation. After an app has been created in doSave() doPostSave() called
    // this method. Because we cleared to controller's app cache the
    // DeveloperAppCreateForm::save() could not load the credential form the
    // app. (Of course, we do not want to re-load the app just because of this.)
    // @see \Drupal\apigee_edge\Entity\Form\DeveloperAppCreateForm::save()
  }

  /**
   * {@inheritdoc}
   */
  protected function setPersistentCache(array $entities) {
    parent::setPersistentCache($entities);
    if (!$this->entityType
      ->isPersistentlyCacheable()) {
      return;
    }

    /** @var \Drupal\apigee_edge\Entity\AppInterface $entity */
    foreach ($entities as $entity) {

      // Create an additional cache entry for each app that stores the app id
      // for each developerId or company (team) name + app name combinations.
      // Thanks for this we can run queries faster that tries to an load app
      // by using these two properties instead of the app id.
      $this->cacheBackend
        ->set($this
        ->buildCacheIdForAppName($entity
        ->getAppOwner(), $entity
        ->getName()), $entity
        ->getAppId(), $this
        ->getPersistentCacheExpiration(), $this
        ->getPersistentCacheTagsForAppName($entity));
    }
  }

  /**
   * Generates a unique cache id for app name.
   *
   * Developer id (uuid)/company name + app name together also represent a
   * unique app entity id.
   *
   * @param string $owner
   *   Developer id (UUID) or team (company) name.
   * @param string $app_name
   *   The name of an app.
   *
   * @return string
   *   Unique cache cid.
   */
  protected function buildCacheIdForAppName(string $owner, string $app_name) {

    // We do not need to worry about the length of the cid because the cache
    // backend should ensure that the length of the cid is not too long.
    // @see \Drupal\Core\Cache\DatabaseBackend::normalizeCid()
    return "app_names:{$this->entityTypeId}:{$owner}:{$app_name}";
  }

  /**
   * Returns cached app id for developer id/company name + app name.
   *
   * @param string $owner
   *   UUID of a developer or a team (company) name.
   * @param string $app_name
   *   Name of an app owned by the provided owner.
   *
   * @return null|string
   *   The app id if it found, null otherwise.
   */
  public function getCachedAppId(string $owner, string $app_name) {
    $item = $this->cacheBackend
      ->get($this
      ->buildCacheIdForAppName($owner, $app_name));
    return $item ? $item->data : NULL;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
AppStorage::$appController protected property The app controller service.
AppStorage::buildCacheIdForAppName protected function Generates a unique cache id for app name.
AppStorage::createInstance public static function Instantiates a new instance of this entity handler. Overrides EdgeEntityStorageBase::createInstance 2
AppStorage::getCachedAppId public function Returns cached app id for developer id/company name + app name.
AppStorage::getCacheTagsByOwner abstract protected function Returns app owner related cache tags for an app. 2
AppStorage::getFromStorage protected function Gets entities from the storage. Overrides EdgeEntityStorageBase::getFromStorage
AppStorage::getPersistentCacheTags final protected function Generates cache tags for entities. Overrides FieldableEdgeEntityStorageBase::getPersistentCacheTags
AppStorage::getPersistentCacheTagsForAppName private function Generates cache tags for an app.
AppStorage::initFieldValues protected function Initializes field values. Overrides FieldableEdgeEntityStorageBase::initFieldValues
AppStorage::loadUnchanged public function Loads an unchanged entity from the database. Overrides EdgeEntityStorageBase::loadUnchanged
AppStorage::loadUnchangedByUuid public function Load app by UUID.
AppStorage::resetCache public function Resets the internal, static entity cache. Overrides EdgeEntityStorageBase::resetCache
AppStorage::setPersistentCache protected function Stores entities in the persistent cache backend. Overrides EdgeEntityStorageBase::setPersistentCache
AppStorage::__construct public function AppStorage constructor. Overrides EdgeEntityStorageBase::__construct 2
AttributesAwareFieldableEdgeEntityStorageBase::countFieldData public function Determines the number of entities with values for a given field. Overrides FieldableEdgeEntityStorageBase::countFieldData
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
EdgeEntityStorageBase::$cacheBackend protected property Cache backend.
EdgeEntityStorageBase::$cacheExpiration protected property Number of seconds until an entity can be served from cache.
EdgeEntityStorageBase::$systemTime protected property The system time.
EdgeEntityStorageBase::buildCacheId protected function Builds the cache ID for the passed in entity ID. Overrides EntityStorageBase::buildCacheId
EdgeEntityStorageBase::createNewInstance protected function Creates a new Drupal entity from an SDK entity.
EdgeEntityStorageBase::deleteRevision public function Delete a specific entity revision. Overrides EntityStorageInterface::deleteRevision
EdgeEntityStorageBase::doDelete protected function Performs storage-specific entity deletion. Overrides EntityStorageBase::doDelete 1
EdgeEntityStorageBase::doLoadMultiple protected function Performs storage-specific loading of entities. Overrides EntityStorageBase::doLoadMultiple
EdgeEntityStorageBase::doSave protected function Performs storage-specific saving of the entity. Overrides EntityStorageBase::doSave 2
EdgeEntityStorageBase::entityController abstract protected function Returns the wrapped controller instance used by this storage. 5
EdgeEntityStorageBase::getFromPersistentCache protected function Gets entities from the persistent cache backend.
EdgeEntityStorageBase::getPersistentCacheExpiration protected function Number of seconds after a cache item expires.
EdgeEntityStorageBase::getQueryServiceName protected function Gets the name of the service for the query for this entity storage. Overrides EntityStorageBase::getQueryServiceName
EdgeEntityStorageBase::has protected function Determines if this entity already exists in storage. Overrides EntityStorageBase::has
EdgeEntityStorageBase::invokeStorageLoadHook protected function Invokes hook_entity_storage_load().
EdgeEntityStorageBase::loadRevision public function Load a specific entity revision. Overrides EntityStorageInterface::loadRevision
EdgeEntityStorageBase::processLoadedEntities final protected function Processes loaded (SDK) entities to Drupal entities.
EdgeEntityStorageBase::resetControllerCache protected function Resets entity controller's cache if it is a cached entity controller.
EdgeEntityStorageBase::SAVED_UNKNOWN public constant Initial status for saving a item to Apigee Edge.
EdgeEntityStorageBase::withController protected function Wraps communication with Apigee Edge.
EntityHandlerBase::$moduleHandler protected property The module handler to invoke hooks on. 2
EntityHandlerBase::moduleHandler protected function Gets the module handler. 2
EntityHandlerBase::setModuleHandler public function Sets the module handler for this handler.
EntityStorageBase::$entityClass protected property Name of the entity class.
EntityStorageBase::$entityType protected property Information about the entity type.
EntityStorageBase::$entityTypeId protected property Entity type ID for this storage.
EntityStorageBase::$idKey protected property Name of the entity's ID field in the entity database table.
EntityStorageBase::$langcodeKey protected property The name of the entity langcode property. 1
EntityStorageBase::$memoryCache protected property The memory cache.
EntityStorageBase::$memoryCacheTag protected property The memory cache cache tag.
EntityStorageBase::$uuidKey protected property Name of entity's UUID database table field, if it supports UUIDs. 1
EntityStorageBase::$uuidService protected property The UUID service. 1
EntityStorageBase::buildPropertyQuery protected function Builds an entity query. 1
EntityStorageBase::create public function Constructs a new entity object, without permanently saving it. Overrides EntityStorageInterface::create 1
EntityStorageBase::delete public function Deletes permanently saved entities. Overrides EntityStorageInterface::delete 2
EntityStorageBase::doPostSave protected function Performs post save entity processing. 1
EntityStorageBase::doPreSave protected function Performs presave entity processing. 1
EntityStorageBase::getAggregateQuery public function Gets an aggregated query instance. Overrides EntityStorageInterface::getAggregateQuery
EntityStorageBase::getEntityType public function Gets the entity type definition. Overrides EntityStorageInterface::getEntityType
EntityStorageBase::getEntityTypeId public function Gets the entity type ID. Overrides EntityStorageInterface::getEntityTypeId
EntityStorageBase::getFromStaticCache protected function Gets entities from the static cache.
EntityStorageBase::getQuery public function Gets an entity query instance. Overrides EntityStorageInterface::getQuery
EntityStorageBase::hasData public function Determines if the storage contains any data. Overrides EntityStorageInterface::hasData 3
EntityStorageBase::invokeHook protected function Invokes a hook on behalf of the entity. 2
EntityStorageBase::load public function Loads one entity. Overrides EntityStorageInterface::load 2
EntityStorageBase::loadByProperties public function Load entities by their property values. Overrides EntityStorageInterface::loadByProperties 3
EntityStorageBase::loadMultiple public function Loads one or more entities. Overrides EntityStorageInterface::loadMultiple 1
EntityStorageBase::mapFromStorageRecords protected function Maps from storage records to entity objects. 4
EntityStorageBase::postLoad protected function Attaches data to entities upon loading.
EntityStorageBase::preLoad protected function Gathers entities from a 'preload' step. 1
EntityStorageBase::restore public function Restores a previously saved entity. Overrides EntityStorageInterface::restore 1
EntityStorageBase::save public function Saves the entity permanently. Overrides EntityStorageInterface::save 4
EntityStorageBase::setStaticCache protected function Stores entities in the static entity cache.
EntityStorageInterface::FIELD_LOAD_CURRENT constant Load the most recent version of an entity's field data.
EntityStorageInterface::FIELD_LOAD_REVISION constant Load the version of an entity's field data specified in the entity.
FieldableEdgeEntityStorageBase::doCreate protected function Overrides EntityStorageBase::doCreate
FieldableEdgeEntityStorageBase::finalizePurge public function Performs final cleanup after all data of a field has been purged. Overrides FieldableEntityStorageInterface::finalizePurge
FieldableEdgeEntityStorageBase::onEntityTypeCreate public function Reacts to the creation of the entity type. Overrides EntityTypeListenerInterface::onEntityTypeCreate
FieldableEdgeEntityStorageBase::onEntityTypeDelete public function Reacts to the deletion of the entity type. Overrides EntityTypeListenerInterface::onEntityTypeDelete
FieldableEdgeEntityStorageBase::onEntityTypeUpdate public function Reacts to the update of the entity type. Overrides EntityTypeListenerInterface::onEntityTypeUpdate
FieldableEdgeEntityStorageBase::onFieldableEntityTypeCreate public function Reacts to the creation of the fieldable entity type. Overrides EntityTypeListenerInterface::onFieldableEntityTypeCreate
FieldableEdgeEntityStorageBase::onFieldableEntityTypeUpdate public function Reacts to the update of a fieldable entity type. Overrides EntityTypeListenerInterface::onFieldableEntityTypeUpdate
FieldableEdgeEntityStorageBase::onFieldDefinitionCreate public function Reacts to the creation of a field. Overrides FieldDefinitionListenerInterface::onFieldDefinitionCreate
FieldableEdgeEntityStorageBase::onFieldDefinitionDelete public function Reacts to the deletion of a field. Overrides FieldDefinitionListenerInterface::onFieldDefinitionDelete
FieldableEdgeEntityStorageBase::onFieldDefinitionUpdate public function Reacts to the update of a field. Overrides FieldDefinitionListenerInterface::onFieldDefinitionUpdate
FieldableEdgeEntityStorageBase::onFieldStorageDefinitionCreate public function Reacts to the creation of a field storage definition. Overrides FieldStorageDefinitionListenerInterface::onFieldStorageDefinitionCreate
FieldableEdgeEntityStorageBase::onFieldStorageDefinitionDelete public function Reacts to the deletion of a field storage definition. Overrides FieldStorageDefinitionListenerInterface::onFieldStorageDefinitionDelete
FieldableEdgeEntityStorageBase::onFieldStorageDefinitionUpdate public function Reacts to the update of a field storage definition. Overrides FieldStorageDefinitionListenerInterface::onFieldStorageDefinitionUpdate
FieldableEdgeEntityStorageBase::purgeFieldData public function Purges a batch of field data. Overrides FieldableEntityStorageInterface::purgeFieldData
FieldableEdgeEntityStorageBase::requiresEntityDataMigration public function Checks if existing data would be lost if the schema changes were applied. Overrides EntityStorageSchemaInterface::requiresEntityDataMigration
FieldableEdgeEntityStorageBase::requiresEntityStorageSchemaChanges public function Checks if the changes to the entity type requires storage schema changes. Overrides EntityStorageSchemaInterface::requiresEntityStorageSchemaChanges
FieldableEdgeEntityStorageBase::requiresFieldDataMigration public function Checks if existing data would be lost if the schema changes were applied. Overrides DynamicallyFieldableEntityStorageSchemaInterface::requiresFieldDataMigration
FieldableEdgeEntityStorageBase::requiresFieldStorageSchemaChanges public function Checks if the changes to the storage definition requires schema changes. Overrides DynamicallyFieldableEntityStorageSchemaInterface::requiresFieldStorageSchemaChanges
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.