acquia_dam-1.0.0-rc1/src/IntegrationLinkRegister.php
src/IntegrationLinkRegister.php
<?php namespace Drupal\acquia_dam; use Drupal\acquia_dam\Client\AcquiaDamClientFactory; use Drupal\Core\Database\Connection; use Drupal\Core\DestructableInterface; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Logger\LoggerChannelInterface; use Drupal\Core\Queue\QueueFactory; /** * Register and remove integration links from Acquia DAM. */ class IntegrationLinkRegister implements DestructableInterface { /** * List of entities to create integration links for. * * @var array */ protected $integrations = []; /** * List of entities to delete associated integration links. * * @var array */ protected $integrationsToDelete = []; /** * List of integration links to delete. * * @var array */ protected $trackingToDelete = []; /** * DAM client factory. * * @var \Drupal\acquia_dam\Client\AcquiaDamClientFactory */ protected $clientFactory; /** * Database connection service. * * @var \Drupal\Core\Database\Connection */ protected $database; /** * Entity type bundle info. * * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface */ protected $entityBundleInfo; /** * Logger channel for Acquia DAM. * * @var \Drupal\Core\Logger\LoggerChannelInterface */ protected $damLoggerChannel; /** * The queue factory. * * @var \Drupal\Core\Queue\QueueFactory */ protected $queueFactory; /** * The entity repository. * * @var \Drupal\Core\Entity\EntityRepositoryInterface */ protected $entityRepository; /** * IntegrationLinkRegister constructor. * * @param \Drupal\acquia_dam\Client\AcquiaDamClientFactory $client_factory * DAM client factory. * @param \Drupal\Core\Database\Connection $database * Database connection. * @param \Drupal\Core\Logger\LoggerChannelInterface $loggerChannel * Logger channel instance. * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entityBundleInfo * Entity bundle info. * @param \Drupal\Core\Queue\QueueFactory $queue_factory * The queue factory. * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository * The entity repository. */ public function __construct(AcquiaDamClientFactory $client_factory, Connection $database, LoggerChannelInterface $loggerChannel, EntityTypeBundleInfoInterface $entityBundleInfo, QueueFactory $queue_factory, EntityRepositoryInterface $entity_repository) { $this->clientFactory = $client_factory; $this->database = $database; $this->damLoggerChannel = $loggerChannel; $this->entityBundleInfo = $entityBundleInfo; $this->queueFactory = $queue_factory; $this->entityRepository = $entity_repository; } /** * Add entity and necessary info to the list for integration link creation. * * @param string $asset_id * DAM asset id. * @param \Drupal\Core\Entity\ContentEntityInterface $entity * Content entity instance. */ public function addIntegrationLinksList(string $asset_id, ContentEntityInterface $entity): void { $this->integrations[$entity->uuid()]['asset_uuids'][] = $asset_id; $this->integrations[$entity->uuid()]['entity'] = $entity; } /** * Add entity to the deletion list. * * @param string $entity_uuid * Entity uuid. */ public function addIntegrationToDeleteList(string $entity_uuid) { $this->integrationsToDelete[] = $entity_uuid; } /** * Add asset to tracking delete list. * * @param string $asset_uuid * Asset uuid. * @param string $entity_uuid * Entity uuid. */ public function addToTrackingDeleteList(string $asset_uuid, string $entity_uuid) { $this->trackingToDelete[$entity_uuid][] = $asset_uuid; } /** * Register integration links from integrations list. */ protected function registerIntegrationLinks(): void { $queue = $this->queueFactory->get('acquia_dam_integration_links'); foreach ($this->integrations as $item) { foreach ($item['asset_uuids'] as $asset_uuid) { $queue->createItem([ 'op' => 'registerIntegrationLink', 'args' => [ $asset_uuid, $item['entity']->getEntityTypeId(), $item['entity']->uuid(), ], ]); } } $this->integrations = []; } /** * Remove integration list based on integrationsToDelete list. */ protected function removeIntegrationLinks(): void { $queue = $this->queueFactory->get('acquia_dam_integration_links'); foreach ($this->integrationsToDelete as $entity_uuid) { $queue->createItem([ 'op' => 'removeIntegrationLink', 'args' => [$entity_uuid], ]); } } /** * Remove integration list based on integrationsToDelete list. */ protected function removeTracking(): void { $queue = $this->queueFactory->get('acquia_dam_integration_links'); foreach ($this->trackingToDelete as $entity_uuid => $asset_ids) { $queue->createItem([ 'op' => 'removeTrackings', 'args' => [$entity_uuid, $asset_ids], ]); } } /** * Add integration link for a given entity. * * @param string $asset_id * DAM asset id. * @param string $entity_type * The entity type. * @param string $entity_uuid * The entity UUID. * * @throws \GuzzleHttp\Exception\GuzzleException */ public function registerIntegrationLink(string $asset_id, string $entity_type, string $entity_uuid): void { try { $entity = $this->entityRepository->loadEntityByUuid($entity_type, $entity_uuid); // $entity can be NULL if it was deleted before the cron runs. if (is_null($entity)) { return; } $url = $entity->toUrl()->setAbsolute()->toString(); $client = $this->clientFactory->getSiteClient(); $data = $client->registerIntegrationLink($asset_id, $url, $this->generateIntegrationLinkDescription($entity)); $this->trackIntegration($asset_id, $entity->uuid(), $entity->getEntityTypeId(), $data['uuid'], $url); } catch (\Exception $exception) { $this->damLoggerChannel->error(sprintf( 'Something went wrong during integration link registration for asset: %s. Error message: %s', $asset_id, $exception->getMessage() )); } } /** * Remove integration links for given entity. * * @param string $entity_uuid * Entity uuid. * * @throws \GuzzleHttp\Exception\GuzzleException */ public function removeIntegrationLink(string $entity_uuid): void { try { $client = $this->clientFactory->getSiteClient(); $integration_links = $this ->database ->select('acquia_dam_integration_link_tracking', 'int') ->fields('int', ['integration_link_id', 'asset_uuid']) ->condition('entity_uuid', $entity_uuid) ->execute() ->fetchAll(); if (empty($integration_links)) { $this->damLoggerChannel->warning(sprintf( 'There are no integration links associated with entity: %s in local storage', $entity_uuid, )); } foreach ($integration_links as $integration_link) { $client->removeIntegrationLink($integration_link->integration_link_id); $this->updateAssetTrackingAggregate($integration_link->asset_uuid, -1); } $this->removeIntegrationTracking($entity_uuid); $this->integrationsToDelete = []; } catch (\Exception $exception) { $this->damLoggerChannel->error(sprintf( 'Something went wrong during integration link removal for entity: %s integration link: %s. Error message: %s', $entity_uuid, $integration_link->integration_link_id, $exception->getMessage() )); } } /** * Remove integration links by integration link ids. * * @param string $entity_uuid * Entity instance where the assets are used. * @param array $asset_ids * Asset ids. * * @throws \Drupal\acquia_dam\Exception\DamClientException * @throws \Drupal\acquia_dam\Exception\DamConnectException * @throws \Drupal\acquia_dam\Exception\DamServerException * @throws \GuzzleHttp\Exception\GuzzleException */ public function removeTrackings(string $entity_uuid, array $asset_ids) { try { $client = $this->clientFactory->getSiteClient(); $integration_links = $this ->database ->select('acquia_dam_integration_link_tracking', 'int') ->fields('int', ['integration_link_id']) ->condition('entity_uuid', $entity_uuid) ->condition('asset_uuid', $asset_ids, 'IN') ->execute() ->fetchAll(); if (empty($integration_links)) { $this->damLoggerChannel->warning(sprintf( 'There are no integration links associated with entity: %s in local storage', $entity_uuid, )); } foreach ($integration_links as $integration_link) { $client->removeIntegrationLink($integration_link->integration_link_id); $this ->database ->delete('acquia_dam_integration_link_tracking') ->condition('integration_link_id', $integration_link->integration_link_id) ->execute(); } $this->trackingToDelete = []; } catch (\Exception $exception) { $this->damLoggerChannel->error(sprintf( 'Something went wrong during integration link removal for entity: %s integration link: %s. Error message: %s', $entity_uuid, $integration_link->integration_link_id, $exception->getMessage() )); throw $exception; } } /** * Tracks integration link info in custom database table. * * @param string $asset_uuid * Asset uuid. * @param string $entity_uuid * Entity uuid. * @param string $entity_type * Entity type id. * @param string $integration_id * Integration link id. * @param string $path * Path to entity. * * @throws \Exception */ protected function trackIntegration(string $asset_uuid, string $entity_uuid, string $entity_type, string $integration_id, string $path) { // Use UPSERT to handle instances where the DAM returns an existing // integration link ID based on the token used and path. $this->database->upsert('acquia_dam_integration_link_tracking') ->key('integration_link_id') ->fields([ 'asset_uuid' => $asset_uuid, 'entity_uuid' => $entity_uuid, 'entity_type' => $entity_type, 'integration_link_id' => $integration_id, 'path' => $path, 'created' => date('c'), ]) ->execute(); $this->updateAssetTrackingAggregate($asset_uuid, 1); } /** * Removes integration link tracking from custom database table. * * @param string $entity_uuid * Entity uuid. */ protected function removeIntegrationTracking(string $entity_uuid) { $this->database->delete('acquia_dam_integration_link_tracking') ->condition('entity_uuid', $entity_uuid) ->execute(); } /** * Generates integration link description. * * Description can be 255 characters maximum. * * @param \Drupal\Core\Entity\ContentEntityInterface $entity * Entity instance. * * @return string * Description for integration links. */ protected function generateIntegrationLinkDescription(ContentEntityInterface $entity): string { $bundle_info = $this->entityBundleInfo->getAllBundleInfo(); // Bundle label can be 50 chars maximum. $bundle_label = $bundle_info[$entity->getEntityTypeId()][$entity->bundle()]['label']; $bundle_label = strlen($bundle_label) <= 50 ? $bundle_label : substr($bundle_label, 0, 47) . '...'; // Entity title can be 195 chars maximum. $label = $entity->label(); $label = strlen($label) <= 195 ? $label : substr($label, 0, 192) . '...'; return sprintf('%s titled "%s"', $bundle_label, $label); } /** * {@inheritdoc} */ public function destruct() { // Start with delete to avoid errors on register triggered by title change. if (!empty($this->integrationsToDelete)) { $this->removeIntegrationLinks(); } if (!empty($this->integrations)) { $this->registerIntegrationLinks(); } if (!empty($this->trackingToDelete)) { $this->removeTracking(); } } /** * Update integration link aggregate table data. * * @param string $asset_uuid * Line to update. * @param int $value * Value to add to the useage count value. * * @throws \Exception */ protected function updateAssetTrackingAggregate(string $asset_uuid, int $value): void { $result = $this ->database ->update('acquia_dam_integration_link_aggregate') ->condition('asset_uuid', $asset_uuid) ->expression('usage_count', "usage_count + $value") ->execute(); if (!$result) { $this ->database ->insert('acquia_dam_integration_link_aggregate') ->fields([ 'asset_uuid' => $asset_uuid, 'usage_count' => $value, ]) ->execute(); } } /** * Returns all entity uuids which associated with the given asset. * * @param string $asset_uuid * Asset UUID. * * @return string[] * Array containing entity uuids. */ public function getAllEntityUuuidsIntegratingAsset(string $asset_uuid): array { return $this ->database ->select('acquia_dam_integration_link_tracking', 'int') ->fields('int', ['entity_uuid']) ->condition('asset_uuid', $asset_uuid) ->execute() ->fetchCol(); } }