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. |