class ContentHubEntityExportController in Acquia Content Hub 8
Controller for Content Hub Export Entities using bulk upload.
Hierarchy
- class \Drupal\Core\Controller\ControllerBase implements ContainerInjectionInterface uses LoggerChannelTrait, MessengerTrait, LinkGeneratorTrait, RedirectDestinationTrait, UrlGeneratorTrait, StringTranslationTrait- class \Drupal\acquia_contenthub\Controller\ContentHubEntityExportController
 
Expanded class hierarchy of ContentHubEntityExportController
2 files declare their use of ContentHubEntityExportController
- ContentHubEntityExportControllerTest.php in tests/src/ Unit/ Controller/ ContentHubEntityExportControllerTest.php 
- ContentHubExportQueueBase.php in src/Plugin/ QueueWorker/ ContentHubExportQueueBase.php 
1 string reference to 'ContentHubEntityExportController'
1 service uses ContentHubEntityExportController
File
- src/Controller/ ContentHubEntityExportController.php, line 23 
Namespace
Drupal\acquia_contenthub\ControllerView source
class ContentHubEntityExportController extends ControllerBase {
  /**
   * Format for the cdf.
   *
   * @var string
   */
  protected $format = 'acquia_contenthub_cdf';
  /**
   * Logger.
   *
   * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
   */
  protected $loggerFactory;
  /**
   * Content Hub Client Manager.
   *
   * @var \Drupal\acquia_contenthub\Client\ClientManager
   */
  protected $clientManager;
  /**
   * Content Hub Entity Manager.
   *
   * @var \Drupal\acquia_contenthub\EntityManager
   */
  protected $entityManager;
  /**
   * Content Hub Entities Tracking.
   *
   * @var \Drupal\acquia_contenthub\ContentHubEntitiesTracking
   */
  protected $contentHubEntitiesTracking;
  /**
   * The Entity CDF Normalizer.
   *
   * @var \Drupal\acquia_contenthub\Normalizer\ContentEntityCdfNormalizer
   */
  protected $entityCdfNormalizer;
  /**
   * Content Hub Export Queue Controller.
   *
   * @var \Drupal\acquia_contenthub\Controller\ContentHubExportQueueController
   */
  protected $exportQueueController;
  /**
   * Entity Repository.
   *
   * @var \Drupal\Core\Entity\EntityRepositoryInterface
   */
  protected $entityRepository;
  /**
   * The account switcher service.
   *
   * @var \Drupal\acquia_contenthub\ContentHubInternalRequest
   */
  protected $internalRequest;
  /**
   * The flag to check whether the export queue is active or not.
   *
   * @var bool
   */
  protected $exportQueueEnabled;
  /**
   * Public Constructor.
   *
   * @param \Drupal\acquia_contenthub\Client\ClientManagerInterface $client_manager
   *   The client manager.
   * @param \Drupal\acquia_contenthub\EntityManager $entity_manager
   *   The Content Hub Entity Manager.
   * @param \Drupal\acquia_contenthub\ContentHubEntitiesTracking $contenthub_entities_tracking
   *   The table where all entities are tracked.
   * @param \Drupal\acquia_contenthub\Normalizer\ContentEntityCdfNormalizer $acquia_contenthub_normalizer
   *   The Content Hub Normalizer.
   * @param \Drupal\acquia_contenthub\Controller\ContentHubExportQueueController $export_queue_controller
   *   The Content Hub Export Queue Controller.
   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
   *   Entity Repository.
   * @param \Drupal\acquia_contenthub\ContentHubInternalRequest $internal_request
   *   The Content Hub Internal Request Service.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
   *   The logger factory.
   */
  public function __construct(ClientManagerInterface $client_manager, EntityManager $entity_manager, ContentHubEntitiesTracking $contenthub_entities_tracking, ContentEntityCdfNormalizer $acquia_contenthub_normalizer, ContentHubExportQueueController $export_queue_controller, EntityRepositoryInterface $entity_repository, ContentHubInternalRequest $internal_request, ConfigFactoryInterface $config_factory, LoggerChannelFactoryInterface $logger_factory) {
    $this->clientManager = $client_manager;
    $this->entityManager = $entity_manager;
    $this->contentHubEntitiesTracking = $contenthub_entities_tracking;
    $this->entityCdfNormalizer = $acquia_contenthub_normalizer;
    $this->exportQueueController = $export_queue_controller;
    $this->entityRepository = $entity_repository;
    $this->internalRequest = $internal_request;
    $entity_config = $config_factory
      ->get('acquia_contenthub.entity_config');
    $this->exportQueueEnabled = (bool) $entity_config
      ->get('export_with_queue');
    $this->loggerFactory = $logger_factory;
  }
  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static($container
      ->get('acquia_contenthub.client_manager'), $container
      ->get('acquia_contenthub.entity_manager'), $container
      ->get('acquia_contenthub.acquia_contenthub_entities_tracking'), $container
      ->get('acquia_contenthub.normalizer.entity.acquia_contenthub_cdf'), $container
      ->get('acquia_contenthub.acquia_contenthub_export_queue'), $container
      ->get('entity.repository'), $container
      ->get('acquia_contenthub.internal_request'), $container
      ->get('config.factory'), $container
      ->get('logger.factory'));
  }
  /**
   * Export entities to Content Hub (using the queue if enabled).
   *
   * @param \Drupal\Core\Entity\ContentEntityInterface[] $candidate_entities
   *   An array of entities (uuid, entity object) to be exported to Content Hub.
   *
   * @return bool
   *   TRUE if we are using the export queue, FALSE otherwise.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  public function exportEntities(array $candidate_entities) {
    $candidate_entities = array_filter($candidate_entities);
    if ($this->exportQueueEnabled) {
      // These entities that reacted to a hook should always be re-exported,
      // then mark them as "queued" in the tracking table so they do not get
      // confused with exported entities (even if a previous version of the
      // entity has been previously exported).
      // This is fine because they will change back to exported status in the
      // tracking table after the queue runs, but we want to make sure that
      // these entities are taken again when collecting dependencies.
      // Dependencies are not exported if they have an entry in the tracking
      // table that says that they have been previously "exported".
      $this->exportQueueController
        ->enqueueExportEntities($candidate_entities);
      foreach ($candidate_entities as $candidate_entity) {
        $this
          ->queueExportedEntity($candidate_entity);
      }
      return TRUE;
    }
    $exported_entities = [];
    $bulk_url_array = [];
    foreach ($candidate_entities as $candidate_entity) {
      $entity_type = $candidate_entity
        ->getEntityTypeId();
      $entity_id = $candidate_entity
        ->id();
      $bulk_url_array[$entity_type][$entity_id] = $entity_id;
      $context['query_params']['include_references'] = 'true';
      $exported_entity = $this->entityCdfNormalizer
        ->normalize($candidate_entity, 'acquia_contenthub_cdf', $context);
      $exported_entity['entities'] = !empty($exported_entity) && is_array($exported_entity['entities']) ? $exported_entity['entities'] : [];
      foreach ($exported_entity['entities'] as $key => $ch_entity) {
        $exported_entity['entities'][$key] = Json::decode($ch_entity
          ->json());
      }
      $exported_entities = array_merge($exported_entities, $exported_entity['entities']);
    }
    // Eliminate duplicates.
    $exported_cdfs = [];
    foreach ($exported_entities as $cdf) {
      $exported_cdfs[$cdf['uuid']] = $cdf;
    }
    // Now implode parameters.
    foreach ($bulk_url_array as $entity_type => $entities) {
      $bulk_url_array[$entity_type] = implode(',', $entities);
    }
    $resource_url = $this->entityManager
      ->getBulkResourceUrl($bulk_url_array);
    if (!empty($exported_cdfs)) {
      if ($this->entityManager
        ->updateRemoteEntities($resource_url) !== FALSE) {
        // Setting up INITIATED status to all tracked exported entities.
        foreach ($exported_cdfs as $exported_entity) {
          // Obtaining the entity ID from the entity.
          $this
            ->trackExportedEntity($exported_entity);
        }
      }
    }
    // Log list of UUIDs being exported.
    $log_message = 'Drupal sending export request to Content Hub for UUIDs @uuids.';
    $context = [
      '@uuids' => implode(', ', array_keys($exported_cdfs)),
    ];
    $this->loggerFactory
      ->get('acquia_contenthub')
      ->debug($log_message, $context);
    return FALSE;
  }
  /**
   * Collects all Drupal Entities that needs to be sent to Hub.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  public function getDrupalEntities() {
    $normalized = [
      'entities' => [],
    ];
    $normalized_entities = [];
    // phpcs:ignore
    $entities = $_GET;
    foreach ($entities as $entity => $entity_ids) {
      $ids = explode(',', $entity_ids);
      foreach ($ids as $id) {
        $id = trim($id);
        try {
          $bulk_cdf = $this->internalRequest
            ->getEntityCDFByInternalRequest($entity, $id);
          $bulk_cdf = array_pop($bulk_cdf);
          if (is_array($bulk_cdf)) {
            foreach ($bulk_cdf as $cdf) {
              $normalized_entities[$cdf['uuid']] = $cdf;
            }
          }
        } catch (\Exception $e) {
          // Do nothing, route does not exist, but report it.
          $args = [
            '@type' => $entity,
            '@id' => $id,
            '@msg' => $e
              ->getMessage(),
          ];
          $this->loggerFactory
            ->get('acquia_contenthub')
            ->error('Could not obtain the CDF for entity (@type, @id) : @msg', $args);
        }
      }
    }
    // If we reach here, then there was no error processing the sub-requests.
    // Save all entities in the tracking entities and return the response.
    $normalized['entities'] = array_values($normalized_entities);
    if ($this
      ->isRequestFromAcquiaContentHub()) {
      foreach ($normalized['entities'] as $cdf) {
        $this
          ->trackExportedEntity($cdf, TRUE);
      }
    }
    return JsonResponse::create($normalized);
  }
  /**
   * Resolves whether the current request comes from Acquia Content Hub or not.
   *
   * @return bool
   *   TRUE if request comes from Content Hub, FALSE otherwise.
   */
  public function isRequestFromAcquiaContentHub() {
    $request = Request::createFromGlobals();
    // This function already sits behind an access check to confirm that the
    // request for CDF came from Content Hub, but just in case that access is
    // opened to authenticated users or during development, we are using a
    // condition to prevent false tracking of entities as exported.
    $headers = array_map('current', $request->headers
      ->all());
    if (isset($headers['user-agent']) && strpos($headers['user-agent'], 'Go-http-client') !== FALSE) {
      return TRUE;
    }
    return FALSE;
  }
  /**
   * Save this entity in the Tracking table.
   *
   * @param array $cdf
   *   The entity that has to be tracked as exported entity.
   * @param bool $set_exported
   *   Set the export status to exported in the tracking table.
   *
   * @return bool
   *   TRUE if this entity was saved in the tracking table, FALSE otherwise.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  public function trackExportedEntity(array $cdf, $set_exported = FALSE) {
    $exported_entity = $this->contentHubEntitiesTracking
      ->loadExportedByUuid($cdf['uuid']);
    if ($exported_entity) {
      $exported_entity
        ->setModified($cdf['modified'])
        ->setInitiated();
      if ($set_exported) {
        $exported_entity
          ->setExported();
      }
      return $this->contentHubEntitiesTracking
        ->save();
    }
    $entity = $this->entityRepository
      ->loadEntityByUuid($cdf['type'], $cdf['uuid']);
    if (!$entity) {
      $this->loggerFactory
        ->get('acquia_contenthub')
        ->warning('Cannot create record in the tracking table, because the entity cannot be loaded in Drupal. uuid: @uuid type: @type', [
        '@uuid' => $cdf['uuid'],
        '@type' => $cdf['type'],
      ]);
      return FALSE;
    }
    // Add a new tracking record with exported status set, and
    // imported status empty.
    $exported_entity = $this->contentHubEntitiesTracking
      ->setExportedEntity($cdf['type'], $entity
      ->id(), $cdf['uuid'], $cdf['modified'], $this->contentHubEntitiesTracking
      ->getSiteOrigin());
    if (!$exported_entity) {
      // In case of $exported_entity == FALSE.
      $this->loggerFactory
        ->get('acquia_contenthub')
        ->warning('Cannot save into Acquia ContentHub tracking table; entity UUID: @uuid, @backtrack', [
        '@uuid' => $entity
          ->uuid(),
        '@backtrack' => __FUNCTION__,
      ]);
      return FALSE;
    }
    if ($set_exported) {
      $exported_entity
        ->setExported();
    }
    // Now save the entity.
    $result = $this->contentHubEntitiesTracking
      ->save();
    if ($result === FALSE) {
      $this->loggerFactory
        ->get('acquia_contenthub')
        ->debug('Unable to save entity to the tracking table: entity_type = @type, entity_uuid = @uuid, entity_id = @id, origin = @origin, mmodified = @modified.', [
        '@uuid' => $this->contentHubEntitiesTracking
          ->getUuid(),
        '@type' => $this->contentHubEntitiesTracking
          ->getEntityType(),
        '@id' => $this->contentHubEntitiesTracking
          ->getEntityId(),
        '@origin' => $this->contentHubEntitiesTracking
          ->getOrigin(),
        '@modified' => $this->contentHubEntitiesTracking
          ->getModified(),
      ]);
    }
    return $result;
  }
  /**
   * Sets a record for an entity to be queued for export.
   *
   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
   *   The entity that has to be queued for export.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  public function queueExportedEntity(ContentEntityInterface $entity) {
    $exported_entity = $this->contentHubEntitiesTracking
      ->loadExportedByUuid($entity
      ->uuid());
    if ($exported_entity) {
      $exported_entity
        ->setQueued();
      $this->contentHubEntitiesTracking
        ->save();
      return;
    }
    $entity = $this->entityRepository
      ->loadEntityByUuid($entity
      ->getEntityTypeId(), $entity
      ->uuid());
    if (!$entity) {
      $this->loggerFactory
        ->get('acquia_contenthub')
        ->warning('Cannot create record in the tracking table, because the entity cannot be loaded in Drupal. uuid: @uuid type: @type', [
        '@uuid' => $entity
          ->uuid(),
        '@type' => $entity
          ->getEntityTypeId(),
      ]);
      return;
    }
    // Add a new tracking record with queued status set, and
    // imported status empty.
    $exported_entity = $this->contentHubEntitiesTracking
      ->setExportedEntity($entity
      ->getEntityTypeId(), $entity
      ->id(), $entity
      ->uuid(), date('c'), $this->contentHubEntitiesTracking
      ->getSiteOrigin());
    if (!$exported_entity) {
      $this->loggerFactory
        ->get('acquia_contenthub')
        ->warning('Cannot save into Acquia ContentHub tracking table; entity UUID: @uuid, @backtrack', [
        '@uuid' => $entity
          ->uuid(),
        '@backtrack' => __FUNCTION__,
      ]);
      return;
    }
    $exported_entity
      ->setQueued();
    $this->contentHubEntitiesTracking
      ->save();
  }
}Members
| Name   | Modifiers | Type | Description | Overrides | 
|---|---|---|---|---|
| ContentHubEntityExportController:: | protected | property | Content Hub Client Manager. | |
| ContentHubEntityExportController:: | protected | property | Content Hub Entities Tracking. | |
| ContentHubEntityExportController:: | protected | property | The Entity CDF Normalizer. | |
| ContentHubEntityExportController:: | protected | property | Content Hub Entity Manager. Overrides ControllerBase:: | |
| ContentHubEntityExportController:: | protected | property | Entity Repository. | |
| ContentHubEntityExportController:: | protected | property | Content Hub Export Queue Controller. | |
| ContentHubEntityExportController:: | protected | property | The flag to check whether the export queue is active or not. | |
| ContentHubEntityExportController:: | protected | property | Format for the cdf. | |
| ContentHubEntityExportController:: | protected | property | The account switcher service. | |
| ContentHubEntityExportController:: | protected | property | Logger. Overrides LoggerChannelTrait:: | |
| ContentHubEntityExportController:: | public static | function | Instantiates a new instance of this class. Overrides ControllerBase:: | |
| ContentHubEntityExportController:: | public | function | Export entities to Content Hub (using the queue if enabled). | |
| ContentHubEntityExportController:: | public | function | Collects all Drupal Entities that needs to be sent to Hub. | |
| ContentHubEntityExportController:: | public | function | Resolves whether the current request comes from Acquia Content Hub or not. | |
| ContentHubEntityExportController:: | public | function | Sets a record for an entity to be queued for export. | |
| ContentHubEntityExportController:: | public | function | Save this entity in the Tracking table. | |
| ContentHubEntityExportController:: | public | function | Public Constructor. | |
| ControllerBase:: | protected | property | The configuration factory. | |
| ControllerBase:: | protected | property | The current user service. | 1 | 
| ControllerBase:: | protected | property | The entity form builder. | |
| ControllerBase:: | protected | property | The entity type manager. | |
| ControllerBase:: | protected | property | The form builder. | 2 | 
| ControllerBase:: | protected | property | The key-value storage. | 1 | 
| ControllerBase:: | protected | property | The language manager. | 1 | 
| ControllerBase:: | protected | property | The module handler. | 2 | 
| ControllerBase:: | protected | property | The state service. | |
| ControllerBase:: | protected | function | Returns the requested cache bin. | |
| ControllerBase:: | protected | function | Retrieves a configuration object. | |
| ControllerBase:: | private | function | Returns the service container. | |
| ControllerBase:: | protected | function | Returns the current user. | 1 | 
| ControllerBase:: | protected | function | Retrieves the entity form builder. | |
| ControllerBase:: | protected | function | Retrieves the entity manager service. | |
| ControllerBase:: | protected | function | Retrieves the entity type manager. | |
| ControllerBase:: | protected | function | Returns the form builder service. | 2 | 
| ControllerBase:: | protected | function | Returns a key/value storage collection. | 1 | 
| ControllerBase:: | protected | function | Returns the language manager service. | 1 | 
| ControllerBase:: | protected | function | Returns the module handler. | 2 | 
| ControllerBase:: | protected | function | Returns a redirect response object for the specified route. Overrides UrlGeneratorTrait:: | |
| ControllerBase:: | protected | function | Returns the state storage service. | |
| LinkGeneratorTrait:: | protected | property | The link generator. | 1 | 
| LinkGeneratorTrait:: | protected | function | Returns the link generator. | |
| LinkGeneratorTrait:: | protected | function | Renders a link to a route given a route name and its parameters. | |
| LinkGeneratorTrait:: | public | function | Sets the link generator service. | |
| LoggerChannelTrait:: | protected | function | Gets the logger for a specific channel. | |
| LoggerChannelTrait:: | public | function | Injects the logger channel factory. | |
| MessengerTrait:: | protected | property | The messenger. | 29 | 
| MessengerTrait:: | public | function | Gets the messenger. | 29 | 
| MessengerTrait:: | public | function | Sets the messenger. | |
| RedirectDestinationTrait:: | protected | property | The redirect destination service. | 1 | 
| RedirectDestinationTrait:: | protected | function | Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url. | |
| RedirectDestinationTrait:: | protected | function | Returns the redirect destination service. | |
| RedirectDestinationTrait:: | public | function | Sets the redirect destination service. | |
| StringTranslationTrait:: | protected | property | The string translation service. | 1 | 
| StringTranslationTrait:: | protected | function | Formats a string containing a count of items. | |
| StringTranslationTrait:: | protected | function | Returns the number of plurals supported by a given language. | |
| StringTranslationTrait:: | protected | function | Gets the string translation service. | |
| StringTranslationTrait:: | public | function | Sets the string translation service to use. | 2 | 
| StringTranslationTrait:: | protected | function | Translates a string to the current language or to a given language. | |
| UrlGeneratorTrait:: | protected | property | The url generator. | |
| UrlGeneratorTrait:: | protected | function | Returns the URL generator service. | |
| UrlGeneratorTrait:: | public | function | Sets the URL generator service. | |
| UrlGeneratorTrait:: | protected | function | Generates a URL or path for a specific route based on the given parameters. | 
