external_entity-1.0.x-dev/src/Entity/ExternalEntityStorage.php

src/Entity/ExternalEntityStorage.php
<?php

declare(strict_types=1);

namespace Drupal\external_entity\Entity;

use Drupal\Core\Utility\Error;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityStorageBase;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\Query\QueryInterface;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Component\Utility\DeprecationHelper;
use Drupal\Core\Entity\Sql\DefaultTableMapping;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Cache\MemoryCache\MemoryCacheInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\external_entity\Contracts\ExternalEntityInterface;
use Drupal\external_entity\Contracts\ExternalEntityTypeInterface;
use Drupal\external_entity\Contracts\ExternalEntityStorageInterface;
use Drupal\external_entity\Definition\ExternalEntityDefaultDefinition;

/**
 * Define the external entity storage class.
 */
class ExternalEntityStorage extends EntityStorageBase implements ExternalEntityStorageInterface {

  /**
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * @var \Drupal\external_entity\Contracts\ExternalEntityTypeInterface
   */
  protected $externalEntityType;

  /**
   * @var \Drupal\Core\Cache\CacheBackendInterface
   */
  protected $externalEntityCache;

  /**
   * The remote entity storage constructor.
   *
   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
   *   The entity type definition.
   * @param \Drupal\Core\Cache\MemoryCache\MemoryCacheInterface $memory_cache
   *   The memory cache.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Cache\CacheBackendInterface $external_entity_cache
   *   The external entity cache.
   */
  public function __construct(
    EntityTypeInterface $entity_type,
    MemoryCacheInterface $memory_cache,
    EntityTypeManagerInterface $entity_type_manager,
    CacheBackendInterface $external_entity_cache,
  ) {
    parent::__construct($entity_type, $memory_cache);
    $this->entityTypeManager = $entity_type_manager;
    $this->externalEntityCache = $external_entity_cache;
  }

  /**
   * {@inheritDoc}
   */
  public static function createInstance(
    ContainerInterface $container,
    EntityTypeInterface $entity_type,
  ) {
    return new static(
      $entity_type,
      $container->get('entity.memory_cache'),
      $container->get('entity_type.manager'),
      $container->get('cache.external_entity')
    );
  }

  /**
   * {@inheritDoc}
   */
  public function loadRevision($revision_id): void {}

  /**
   * {@inheritDoc}
   */
  public function deleteRevision($revision_id): void {}

  /**
   * {@inheritDoc}
   */
  public function getResourceQuery(
    string $resource,
    string $entity_type_id,
    string $conjunction = 'AND',
  ): QueryInterface {
    return \Drupal::service($this->getQueryServiceName())->get(
      $resource,
      $this->entityType,
      $entity_type_id,
      $conjunction
    );
  }

  /**
   * {@inheritDoc}
   */
  public function createEntityFromDefinition(
    string $external_entity_type,
    ExternalEntityDefaultDefinition $definition,
  ): ExternalEntityInterface {
    return $this->create([
      'uuid' => $definition->uuid(),
      'label' => $definition->label(),
      'path' => $definition->getPath(),
      'type' => $external_entity_type,
      'resource' => $definition->getResource(),
      'variation' => $definition->getVariation(),
      'properties' => $definition->getProperties(),
    ]);
  }

  /**
   * {@inheritDoc}
   */
  public function getQuery($conjunction = 'AND'): QueryInterface {
    /** @var \Drupal\Core\Entity\Query\QueryFactoryInterface $factory */
    $factory = \Drupal::service($this->getQueryStubServiceName());
    return $factory->get(
      $this->entityType,
      $conjunction
    );
  }

  /**
   * {@inheritDoc}
   */
  public function getAggregateQuery($conjunction = 'AND'): QueryInterface {
    /** @var \Drupal\Core\Entity\Query\QueryFactoryInterface $factory */
    $factory = \Drupal::service($this->getQueryStubServiceName());
    return $factory->getAggregate(
      $this->entityType,
      $conjunction
    );
  }

  /**
   * {@inheritDoc}
   */
  protected function setStaticCache(array $entities): void {
    if ($this->entityType->isStaticallyCacheable()) {
      foreach ($entities as $id => $entity) {
        $this->memoryCache->set($this->buildCacheId($id), $entity, MemoryCacheInterface::CACHE_PERMANENT, [$this->memoryCacheTag]);
      }
    }
  }

  /**
   * {@inheritDoc}
   */
  protected function doLoadMultiple(?array $ids = NULL): array {
    $entities = [];

    /** @var \Drupal\external_entity\Definition\ExternalEntityDefaultDefinition $definition */
    foreach ($this->loadExternalDefinitions($ids) as $external_entity_type_id => $definitions) {
      foreach ($definitions as $uuid => $definition) {
        $cid = "external_entity:entity:{$uuid}";
        $cache = $this->externalEntityCache->get($cid);

        if (
          is_object($cache)
          && isset($cache->data)
          && $cache->data instanceof ExternalEntityInterface
        ) {
          $entity = $cache->data;
        }
        else {
          $entity = $this->createEntityFromDefinition(
            $external_entity_type_id,
            $definition
                  );
          $this->externalEntityCache->set(
                    $cid,
                    $entity,
                    CacheBackendInterface::CACHE_PERMANENT,
                    $entity->getCacheTags()
                  );
        }

        $entities[$entity->id()] = $entity;
      }
    }

    return $entities;
  }

  /**
   * Define the table mapping.
   *
   * This is a workaround due to an issue when having an
   * \Drupal\Core\Entity\FieldableEntityInterface implemented by the external
   * entity object. When \Drupal\views\ViewsConfigUpdater::getMultivalueBaseFieldUpdateTableInfo
   * is invoked when the view is saved, it will try to update the SQL table,
   * but since the External Entity doesn't use an SQL table, since data is
   * retrieved using an API connection.
   *
   * @return \Drupal\Core\Entity\Sql\DefaultTableMapping|null
   */
  public function getTableMapping(): ?DefaultTableMapping {
    return NULL;
  }

  /**
   * Conduct the loading of the external definitions.
   *
   * @param \Drupal\external_entity\Contracts\ExternalEntityTypeInterface $external_entity_type
   *   The external entity type.
   * @param array $ids
   *   An array of external entity ids.
   *
   * @return array
   *   An array of external definitions.
   *
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  protected function doLoadExternalDefinitions(
    ExternalEntityTypeInterface $external_entity_type,
    array $ids = [],
  ): array {
    try {
      if ($connection = $external_entity_type->getStorageConnection()) {
        return $connection->connectionTypeInstance()->lookupDefinitions($ids);
      }
    }
    catch (\Exception $exception) {
      DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '10.1.0', fn() => Error::logException(\Drupal::logger('external_entity'), $exception), fn() => watchdog_exception('external_entity', $exception));
    }

    return [];
  }

  /**
   * Get external entity type instance.
   *
   * @param string $name
   *   The external entity type name.
   *
   * @return \Drupal\external_entity\Contracts\ExternalEntityTypeInterface
   *   The external entity type instance.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function getExternalEntityType(
    string $name,
  ): ?ExternalEntityTypeInterface {
    if (!isset($this->externalEntityType[$name])) {
      $storage = $this->externalEntityTypeStorage();
      $this->externalEntityType[$name] = $storage->load(
        $name
      );
    }

    return $this->externalEntityType[$name];
  }

  /**
   * {@inheritDoc}
   */
  protected function getQueryServiceName(): string {
    return 'entity.query.api';
  }

  /**
   * The query stub service name.
   *
   * @return string
   *   The key for the query stub service.
   */
  protected function getQueryStubServiceName(): string {
    return 'entity.query.stub';
  }

  /**
   * {@inheritDoc}
   */
  protected function doDelete($entities): void {
    throw new \RuntimeException(
      'Remote entity does not support delete.'
    );
  }

  /**
   * {@inheritDoc}
   */
  protected function doSave($id, EntityInterface $entity): void {
    throw new \RuntimeException(
      'Remote entity does not support save.'
    );
  }

  /**
   * {@inheritDoc}
   */
  protected function has($id, EntityInterface $entity): bool {
    return TRUE;
  }

  /**
   * Load external entity lookup definitions.
   *
   * @param array $ids
   *   An array of external entity ids.
   *
   * @return \Drupal\external_entity\Definition\ExternalEntityDefaultDefinition[]
   *   An array of external entity lookup definitions.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  protected function loadExternalDefinitions(array $ids): array {
    $definitions = [];

    foreach ($this->parseExternalEntityIds($ids) as $external_entity_type_id => $uuids) {
      if ($external_entity_type = $this->getExternalEntityType($external_entity_type_id)) {
        $definitions[$external_entity_type_id] = $this->doLoadExternalDefinitions(
          $external_entity_type,
          $uuids
        );
      }
    }

    return $definitions;
  }

  /**
   * Parse external entity IDs.
   *
   * @param array $ids
   *   An array of external entity IDs concatenated with the external entity
   *   type and external UUID.
   *
   * @return array
   *   An array of parsed external entity IDs.
   */
  protected function parseExternalEntityIds(array $ids): array {
    $entity_ids = [];

    foreach ($ids as $id) {
      [$entity_external_type, $uuid] = explode(
        ExternalEntity::ID_DELIMITER,
        $id
      );

      if (!isset($entity_external_type, $uuid)) {
        continue;
      }
      $entity_ids[$entity_external_type][] = $uuid;
    }

    return $entity_ids;
  }

  /**
   * External entity type storage.
   *
   * @return \Drupal\Core\Entity\EntityStorageInterface
   *   The entity storage instance.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function externalEntityTypeStorage(): EntityStorageInterface {
    return $this->entityTypeManager->getStorage(
      'external_entity_type'
    );
  }

  /**
   * External entity connection storage.
   *
   * @return \Drupal\Core\Entity\EntityStorageInterface
   *   The entity storage instance.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function externalEntityConnectionStorage(): EntityStorageInterface {
    return $this->entityTypeManager->getStorage(
      'external_entity_connection'
    );
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc