acquia_contenthub.module in Acquia Content Hub 8
Same filename and directory in other branches
Contains acquia_contenthub.module.
File
acquia_contenthub.moduleView source
<?php
/**
* @file
* Contains acquia_contenthub.module.
*/
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drush\Drush;
/**
* Implements hook_help().
*/
function acquia_contenthub_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.acquia_contenthub':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('Some info about Acquia Content Hub') . '</p>';
return $output;
}
}
/**
* Implements hook_entity_insert().
*/
function acquia_contenthub_entity_insert(EntityInterface $entity) {
/** @var \Drupal\acquia_contenthub\EntityManager $entity_manager */
$entity_manager = \Drupal::service('acquia_contenthub.entity_manager');
$entity_manager
->enqueueCandidateEntity($entity);
}
/**
* Implements hook_entity_update().
*/
function acquia_contenthub_entity_update(EntityInterface $entity) {
/** @var \Drupal\acquia_contenthub\EntityManager $entity_manager */
$entity_manager = \Drupal::service('acquia_contenthub.entity_manager');
$entity_manager
->enqueueCandidateEntity($entity);
/** @var \Drupal\acquia_contenthub\ImportEntityManager $import_entity_manager */
$import_entity_manager = \Drupal::service('acquia_contenthub.import_entity_manager');
$import_entity_manager
->entityUpdate($entity);
}
/**
* Implements hook_entity_delete().
*/
function acquia_contenthub_entity_delete(EntityInterface $entity) {
/** @var \Drupal\acquia_contenthub\EntityManager $entity_manager */
$entity_manager = \Drupal::service('acquia_contenthub.entity_manager');
$entity_manager
->enqueueCandidateEntity($entity, FALSE);
/** @var \Drupal\acquia_contenthub\ImportEntityManager $import_entity_manager */
$import_entity_manager = \Drupal::service('acquia_contenthub.import_entity_manager');
$import_entity_manager
->entityDelete($entity);
}
/**
* Implements hook_entity_presave().
*/
function acquia_contenthub_entity_presave(EntityInterface $entity) {
/** @var \Drupal\acquia_contenthub\ImportEntityManager $import_entity_manager */
$import_entity_manager = \Drupal::service('acquia_contenthub.import_entity_manager');
$import_entity_manager
->entityPresave($entity);
}
/**
* Process all candidate entities and insert/update/delete on Content Hub.
*/
function acquia_contenthub_bulk_export() {
/** @var \Drupal\acquia_contenthub\EntityManager $entity_manager */
$entity_manager = \Drupal::service('acquia_contenthub.entity_manager');
$entity_manager
->bulkExport();
$candidate_entities = $entity_manager
->getExportCandidateEntities();
/** @var \Drupal\acquia_contenthub\Controller\ContentHubEntityExportController $export_controller */
$export_controller = \Drupal::service('acquia_contenthub.acquia_contenthub_export_entities');
// Export Entities.
$use_export_queue = $export_controller
->exportEntities($candidate_entities);
}
/**
* Generic alter handler for the entity form. Not natively hooked by naming.
*
* Implements hook_form_BASE_FORM_ID_alter().
*/
function acquia_contenthub_form_entity_form_alter(&$form, $form_state, $entity_type_id) {
/* @var Drupal\Core\Entity\FieldableEntityInterface $entity */
$entity = $form_state
->getFormObject()
->getEntity();
$entity_form_service = \Drupal::service('acquia_contenthub.form.entity_form');
$entity_form = $entity_form_service
->getForm($entity);
if (!$entity_form) {
return;
}
// Attach node form.
$form['acquia_contenthub'] = $entity_form;
// Attach submit handler.
$submit_handler_name = 'acquia_contenthub_form_' . $entity_type_id . '_form_submit';
$entity_form_service
->attachSubmitHandler($form['actions'], $submit_handler_name);
}
/**
* Generic submit handler for the entity form. Not natively hooked by naming.
*
* @see acquia_contenthub_form_entity_form_alter()
*/
function acquia_contenthub_form_entity_form_submit(FormStateInterface $form_state) {
$entity_form_service = \Drupal::service('acquia_contenthub.form.entity_form');
$entity_form_service
->saveSettings($form_state);
}
/**
* Implements hook_form_BASE_FORM_ID_alter().
*/
function acquia_contenthub_form_node_form_alter(&$form, $form_state) {
acquia_contenthub_form_entity_form_alter($form, $form_state, 'node');
}
/**
* Submit handler for the node form with acquia contenthub options.
*
* @see acquia_contenthub_form_node_form_alter()
*/
function acquia_contenthub_form_node_form_submit($form, FormStateInterface $form_state) {
acquia_contenthub_form_entity_form_submit($form_state);
}
/**
* Implements hook_form_BASE_FORM_ID_alter().
*/
function acquia_contenthub_form_taxonomy_term_form_alter(&$form, $form_state) {
acquia_contenthub_form_entity_form_alter($form, $form_state, 'taxonomy_term');
}
/**
* Submit handler for the taxonomy term form with acquia contenthub options.
*
* @see acquia_contenthub_form_taxonomy_term_form_alter()
*/
function acquia_contenthub_form_taxonomy_term_form_submit($form, FormStateInterface $form_state) {
acquia_contenthub_form_entity_form_submit($form_state);
}
/**
* Implements hook_form_BASE_FORM_ID_alter().
*/
function acquia_contenthub_form_block_content_form_alter(&$form, $form_state) {
acquia_contenthub_form_entity_form_alter($form, $form_state, 'block_content');
}
/**
* Submit handler for the block content form with acquia contenthub options.
*
* @see acquia_contenthub_form_block_content_form_alter()
*/
function acquia_contenthub_form_block_content_form_submit($form, FormStateInterface $form_state) {
acquia_contenthub_form_entity_form_submit($form_state);
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function acquia_contenthub_form_node_type_form_alter(array &$form, FormStateInterface &$form_state) {
$node_type = $form_state
->getFormObject()
->getEntity()
->id();
/** @var \Drupal\acquia_contenthub\EntityManager $entity_manager */
$entity_manager = \Drupal::service('acquia_contenthub.entity_manager');
/** @var \Drupal\acquia_contenthub\Entity\ContentHubEntityTypeConfig $entity_type_config */
$entity_type_config = $entity_manager
->getContentHubEntityTypeConfigurationEntity('node');
// Only enable selection of preview images for entities that have been
// previously selected to work with Acquia Content Hub.
if (!empty($entity_type_config) && $entity_type_config
->isEnableIndex($node_type)) {
$form['acquia_contenthub'] = \Drupal::service('acquia_contenthub.form.node_type_preview_image_form')
->getForm($node_type);
$form['actions']['submit']['#submit'][] = 'acquia_contenthub_form_node_type_form_submit';
}
}
/**
* Submit handler for the node type form with acquia contenthub options.
*
* @see acquia_contenthub_form_node_type_form_alter()
*/
function acquia_contenthub_form_node_type_form_submit(array $form, FormStateInterface &$form_state) {
$node_type = $form_state
->getFormObject()
->getEntity()
->id();
$settings = $form_state
->getValue('acquia_contenthub');
\Drupal::service('acquia_contenthub.form.node_type_preview_image_form')
->saveSettings($node_type, $settings);
}
/**
* Implements hook_theme().
*/
function acquia_contenthub_theme($existing, $type, $theme, $path) {
// Normally theme suggestion templates are only picked up when they are in
// themes. We explicitly define theme suggestions here so that the templates
// in the templates folder are picked up.
return [
'html__acquia_contenthub' => [
'template' => 'html--acquia-contenthub',
'render element' => 'html',
'preprocess functions' => [
'template_preprocess_html',
],
],
'page__acquia_contenthub' => [
'template' => 'page--acquia-contenthub',
'render element' => 'page',
'preprocess functions' => [
'template_preprocess_page',
],
],
'region__content__acquia_contenthub' => [
'template' => 'region--content--acquia-contenthub',
'render element' => 'elements',
'preprocess functions' => [
'template_preprocess_region',
],
],
'block__block_content__acquia_contenthub' => [
'render element' => 'elements',
'base hook' => 'block',
],
];
}
/**
* Implements hook_theme_suggestions_HOOK().
*/
function acquia_contenthub_theme_suggestions_region(array $variables) {
if ($variables['elements']['#region'] === 'content' && \Drupal::routeMatch()
->getRouteName() === 'acquia_contenthub.content_entity_display.entity') {
return [
'region__content__acquia_contenthub',
];
}
}
/**
* Implements hook_theme_suggestions_HOOK_alter().
*
* Provides block_content templates:
* - block__block_content__acquia_contenthub
* - block__block_content__BLOCK_UUID__acquia_contenthub.
*
* @see block_theme_suggestions_block()
*/
function acquia_contenthub_theme_suggestions_block_alter(array &$suggestions, array $variables) {
if ($variables['elements']['#configuration']['provider'] === 'block_content' && \Drupal::routeMatch()
->getRouteName() === 'acquia_contenthub.content_entity_display.entity') {
// We can safely explode on : because we know the Block plugin type manager
// enforces that delimiter for all derivatives.
// Example value: block_content:12345678-9abc-0123-4567-000000000000.
$parts = explode(':', $variables['elements']['#plugin_id']);
$suggestion = 'block';
foreach ($parts as $part) {
$suggestion .= '__' . strtr($part, '-', '_');
$suggestions[] = $suggestion . '__acquia_contenthub';
}
}
}
/**
* Batch finished function for re-export entities.
*
* @param bool $success
* TRUE if succeeded, FALSE otherwise.
* @param mixed $results
* The results array.
* @param mixed $operations
* The operations array.
*/
function acquia_contenthub_reexport_finished($success, $results, $operations) {
if ($success) {
$message = \Drupal::translation()
->formatPlural(count($results), 'One entity processed.', '@count entities processed.');
/** @var \Drupal\acquia_contenthub\Controller\ContentHubReindex $reindex */
$reindex = \Drupal::service('acquia_contenthub.acquia_contenthub_reindex');
$reindex
->setReindexStateNone();
}
else {
$message = t('Finished with an error.');
}
\Drupal::messenger()
->addStatus($message);
}
/**
* Implements hook_element_info_alter().
*/
function acquia_contenthub_element_info_alter(&$type) {
// Remove the off-canvas page wrapper that was added to core in 8.5.0.
// This wrapper is only needed for the off-canvas dialog.
if (\Drupal::routeMatch()
->getRouteName() === 'acquia_contenthub.content_entity_display.entity') {
unset($type['page']['#theme_wrappers']['off_canvas_page_wrapper']);
}
}
/**
* Implements hook_module_implements_alter().
*/
function acquia_contenthub_module_implements_alter(&$implementations, $hook) {
// Ensure that our implementation of hook_element_info_alter runs after the
// system modules implementation.
if ($hook === 'element_info_alter') {
$implementation = $implementations['acquia_contenthub'];
unset($implementations['acquia_contenthub']);
$implementations['acquia_contenthub'] = $implementation;
}
}
/**
* Checks published entities and compares them with Content Hub.
*
* This method also republishes entities if they are not in sync with what
* exists currently in Content Hub.
*
* @param array $entities
* An array of records from the tracking table.
* @param bool $republish
* 1 to republish entities, FALSE to just print.
* @param mixed $context
* The context array.
*
* @return mixed|false
* Drush Output.
*/
function acquia_contenthub_audit_publisher(array $entities, $republish, &$context) {
if (empty($context['sandbox'])) {
$context['results']['not_published'] = !empty($context['results']['not_published']) ? $context['results']['not_published'] : 0;
$context['results']['outdated'] = !empty($context['results']['outdated']) ? $context['results']['outdated'] : 0;
}
/** @var \Drupal\acquia_contenthub\Client\ClientManager $client_manager */
$client_manager = \Drupal::service('acquia_contenthub.client_manager');
if (!$client_manager
->isConnected()) {
throw new \Exception(dt('The Content Hub client is not connected so no operations could be performed.'));
}
// Collect UUIDs.
$uuids = [];
foreach ($entities as $entity) {
$uuids[] = $entity->entity_uuid;
}
/** @var \Drupal\acquia_contenthub\EntityManager $entity_manager */
$entity_manager = \Drupal::service('acquia_contenthub.entity_manager');
/** @var \Acquia\ContentHubClient\Entity[] $ch_entities */
$ch_entities = $client_manager
->createRequest('readEntities', [
$uuids,
]);
foreach ($entities as $entity) {
$out_of_sync = FALSE;
$uuid = $entity->entity_uuid;
$ch_entity = isset($ch_entities[$uuid]) ? $ch_entities[$uuid] : FALSE;
if (!$ch_entity) {
// Entity does not exist in Content Hub.
Drush::output()
->writeln(dt('Entity not published: Entity Type = @type, UUID = @uuid, ID = @id, Modified = @modified', [
'@type' => $entity->entity_type,
'@uuid' => $entity->entity_uuid,
'@id' => $entity->entity_id,
'@modified' => $entity->modified,
]));
$out_of_sync = TRUE;
$context['results']['not_published']++;
}
elseif ($ch_entity && $entity->modified !== $ch_entity
->getModified()) {
// Entity exists in Content Hub but the modified flag does not match.
Drush::output()
->writeln(dt('Outdated entity: Entity Type = @type, UUID = @uuid, ID = @id, Modified (local) = @lmodified, Modified (remote) = @rmodified', [
'@type' => $entity->entity_type,
'@uuid' => $entity->entity_uuid,
'@id' => $entity->entity_id,
'@lmodified' => $entity->modified,
'@rmodified' => $ch_entity
->getModified(),
]));
$out_of_sync = TRUE;
$context['results']['outdated']++;
}
if ($out_of_sync) {
$entity_id = FALSE;
if ($republish) {
$drupal_entity = \Drupal::entityTypeManager()
->getStorage($entity->entity_type)
->load($entity->entity_id);
if ($drupal_entity) {
$entity_id = $drupal_entity
->id();
if ($entity_manager
->isEligibleEntity($drupal_entity)) {
/** @var \Drupal\acquia_contenthub\Controller\ContentHubEntityExportController $export_controller */
$export_controller = \Drupal::service('acquia_contenthub.acquia_contenthub_export_entities');
// Export Entities.
$export_controller
->exportEntities([
$drupal_entity,
]);
}
else {
// Entity is not eligible for exporting anymore.
Drush::output()
->writeln(dt('Entity exists in the tracking table but is no longer eligible for exporting: Entity Type = @type, UUID = @uuid, ID = @id, Modified (local) = @lmodified, Modified (remote) = @rmodified', [
'@type' => $entity->entity_type,
'@uuid' => $entity->entity_uuid,
'@id' => $entity->entity_id,
'@lmodified' => $entity->modified,
'@rmodified' => $ch_entity
->getModified(),
]));
}
}
}
else {
$entity_type = \Drupal::entityTypeManager()
->getStorage($entity->entity_type)
->getEntityType();
$table = $entity_type
->getBaseTable();
$id_col = $entity_type
->getKey("id");
$query = \Drupal::database()
->select($table)
->fields($table, [
$id_col,
]);
$query
->condition("{$table}.{$id_col}", $entity->entity_id);
$entity_id = $query
->execute()
->fetchField();
}
if (empty($entity_id)) {
// The drupal entity could not be loaded.
throw new \Exception(dt('This entity exists in the tracking table but could not be loaded in Drupal: Entity Type = @type, UUID = @uuid, ID = @id, Modified = @modified', [
'@type' => $entity->entity_type,
'@uuid' => $entity->entity_uuid,
'@id' => $entity->entity_id,
'@modified' => $entity->modified,
]));
}
}
}
}
/**
* Prints results from the comparison of the tracking table with Content Hub.
*
* @param bool $success
* TRUE if there were not PHP fatal errors, FALSE otherwise.
* @param mixed $results
* An array of results.
* @param mixed $operations
* The operations array.
*/
function acquia_contenthub_audit_publisher_finished($success, $results, $operations) {
// The 'success' parameter means no fatal PHP errors were detected. All
// other error management should be handled using 'results'.
if ($success) {
Drush::output()
->writeln(dt('Total number of audited entities not found in Content Hub: @total', [
'@total' => $results['not_published'],
]));
Drush::output()
->writeln(dt('Total number of audited entities found outdated in Content Hub: @total', [
'@total' => $results['outdated'],
]));
}
else {
Drush::output()
->writeln(dt('Finished with a PHP fatal error.'));
}
}