media_acquiadam-8.x-1.46/src/Form/AcquiadamConfig.php
src/Form/AcquiadamConfig.php
<?php
namespace Drupal\media_acquiadam\Form;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Batch\BatchBuilder;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use GuzzleHttp\Exception\TransferException;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Class AcquiadamConfig.
*
* Config form form Acquia dam.
*/
class AcquiadamConfig extends ConfigFormBase {
const BATCH_SIZE = 5;
const NUM_ASSETS_PER_PAGE = 12;
/**
* The AcquiaDAM domain.
*
* @var string
*/
protected $domain;
/**
* The Guzzle HTTP client service.
*
* @var \GuzzleHttp\ClientInterface
*/
protected $httpClient;
/**
* The Batch Builder.
*
* @var \Drupal\Core\Batch\BatchBuilder
*/
protected $batchBuilder;
/**
* The Drupal DateTime Service.
*
* @var \Drupal\Component\Datetime\Time
*/
protected $time;
/**
* The Queue Worker Manager Service.
*
* @var \Drupal\Core\Queue\QueueWorkerManagerInterface
*/
protected $queueWorkerManager;
/**
* The Drupal State Service.
*
* @var \Drupal\Core\State\State
*/
protected $state;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
$instance = parent::create($container);
$instance->httpClient = $container->get('http_client');
$instance->batchBuilder = new BatchBuilder();
$instance->time = $container->get('datetime.time');
$instance->queueWorkerManager = $container->get('plugin.manager.queue_worker');
$instance->state = $container->get('state');
return $instance;
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'media_acquiadam_config';
}
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return [
'media_acquiadam.settings',
];
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
$config = $this->config('media_acquiadam.settings');
$this->domain = $config->get('domain');
$form['authentication'] = [
'#type' => 'fieldset',
'#title' => $this->t('Authentication details'),
];
$form['authentication']['domain'] = [
'#type' => 'textfield',
'#title' => $this->t('Acquia DAM Domain'),
'#default_value' => $config->get('domain'),
'#description' => $this->t('example: demo.acquiadam.com'),
'#required' => TRUE,
];
$form['authentication']['token'] = [
'#type' => 'textfield',
'#title' => $this->t('Acquia DAM Token'),
'#default_value' => $config->get('token'),
'#description' => $this->t('This token will be used to authenticate on Acquia DAM API when there is no user context (cron, drush, ...).'),
'#required' => TRUE,
];
$form['cron'] = [
'#type' => 'fieldset',
'#title' => $this->t('Cron Settings'),
];
$form['cron']['sync_interval'] = [
'#type' => 'select',
'#title' => $this->t('Asset refresh interval'),
'#options' => [
'-1' => $this->t('Every cron run'),
'3600' => $this->t('Every hour'),
'7200' => $this->t('Every 2 hours'),
'10800' => $this->t('Every 3 hours'),
'14400' => $this->t('Every 4 hours'),
'21600' => $this->t('Every 6 hours'),
'28800' => $this->t('Every 8 hours'),
'43200' => $this->t('Every 12 hours'),
'86400' => $this->t('Every 24 hours'),
],
'#default_value' => empty($config->get('sync_interval')) ? 3600 : $config->get('sync_interval'),
'#description' => $this->t('How often should Acquia DAM assets saved in this site be synced with Acquia DAM (this includes asset metadata as well as the asset itself)?'),
'#required' => TRUE,
];
$form['cron']['sync_method'] = [
'#type' => 'select',
'#title' => $this->t('Synchronization method'),
'#description' => $this->t('- "Updated date" method will fetch the assets for which the updated_date attributes in Acquia DAM is more recent than latest synchronization.<br/>- "All" method will synchronize all the assets.<br/>If you identify assets which were missed in the synchronization process, use the "all" method to force a complete synchronization.'),
'#options' => [
'updated_date' => $this->t('Updated date'),
'all' => $this->t('All assets'),
],
'#default_value' => $config->get('sync_method'),
];
$form['cron']['sync_perform_delete'] = [
'#type' => 'checkbox',
'#title' => $this->t("Delete inactive Drupal's DAM assets."),
'#default_value' => $config->get('sync_perform_delete'),
'#description' => $this->t('Deletes unpublished Drupal media entities if asset is not available in Acquia DAM (deleted, archived, expired).'),
];
$form['image'] = [
'#type' => 'fieldset',
'#title' => $this->t('Image configuration'),
];
$transcode = $form_state->getValue('transcode') ?? $config->get('transcode');
$form['image']['transcode'] = [
'#type' => 'radios',
'#title' => $this->t('Transcode options'),
'#options' => [
'original' => $this->t('Original File - no transcode'),
'transcode' => $this->t('Transcode to standard format'),
],
'#default_value' => $config->get('transcode') ?? 'original',
'#limit_validation_errors' => [],
'#ajax' => [
'wrapper' => 'transcode-options',
'callback' => [$this, 'rebuild'],
],
];
$form['image']['container'] = [
'#type' => 'container',
'#prefix' => '<div id="transcode-options">',
'#suffix' => '</div>',
];
if ($transcode !== 'original') {
$form['image']['container']['size_limit'] = [
'#type' => 'select',
'#title' => $this->t('Downsize image size'),
'#description' => $this->t('Downsize the source file when importing the asset. Images larger than the select size will be scaled down.'),
'#options' => [
100 => 100,
150 => 150,
220 => 220,
310 => 310,
550 => 550,
1280 => 1280,
2048 => 2048,
],
'#default_value' => empty($config->get('size_limit')) ? 2048 : $config->get('size_limit'),
];
$form['image']['container']['image_quality'] = [
'#type' => 'number',
'#title' => $this->t('Downsize image quality'),
'#description' => $this->t('Define the image quality for image manipulations. Ranges from 0 to 100. Higher values mean better image quality but bigger files.'),
'#min' => 0,
'#max' => 100,
'#default_value' => $config->get('image_quality') ?? 80,
'#field_suffix' => $this->t('%'),
];
$form['image']['container']['image_format'] = [
'#type' => 'radios',
'#title' => $this->t('Image format'),
'#description' => $this->t('Define the image format. SVG original file formats will not be transcoded.'),
'#options' => [
'png' => $this->t('PNG'),
'jpeg' => $this->t('JPEG'),
'gif' => $this->t('GIF'),
'webp' => $this->t('WEBP'),
],
'#default_value' => $config->get('image_format') ?? 'png',
];
}
$form['manual_sync'] = [
'#type' => 'details',
'#title' => $this->t('Manual asset synchronization.'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
];
$form['manual_sync']['perform_manual_sync'] = [
'#type' => 'submit',
'#value' => $this->t('Synchronize all media assets'),
'#name' => 'perform_manual_sync',
'#submit' => [[$this, 'performManualSync']],
];
$form['entity_browser'] = [
'#type' => 'fieldset',
'#title' => $this->t('Acquia DAM entity browser settings'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
];
$form['entity_browser']['num_assets_per_page'] = [
'#type' => 'number',
'#title' => $this->t('Assets per page'),
'#default_value' => $config->get('num_assets_per_page') ?? self::NUM_ASSETS_PER_PAGE,
'#description' => $this->t(
'The number of assets to be shown per page in the entity browser can be set using this field. Default is set to @num_assets_per_page assets.',
[
'@num_assets_per_page' => self::NUM_ASSETS_PER_PAGE,
]
),
'#required' => TRUE,
];
$form['misc'] = [
'#type' => 'fieldset',
'#title' => $this->t('Misc.'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
];
$form['misc']['report_asset_usage'] = [
'#type' => 'checkbox',
'#title' => $this->t('Report asset usage'),
'#description' => $this->t('Report to Acquia DAM when a Media Entity using an Acquia DAM asset is created.'),
'#default_value' => $config->get('report_asset_usage') ?? 1,
];
$form['misc']['exact_category_search'] = [
'#type' => 'checkbox',
'#title' => $this->t('Use exact search for categories'),
'#description' => $this->t('Use exact search instead of phrase search when retrieving assets from categories.'),
'#default_value' => $config->get('exact_category_search') ?? FALSE,
];
// Need to replace the original validate to prevent it running when the ajax
// callback is running.
$form['actions']['submit']['#validate'][] = [$this, 'doValidateForm'];
return $form;
}
/**
* {@inheritdoc}
*/
public function doValidateForm(array &$form, FormStateInterface $form_state) {
$domain = Xss::filter($form_state->getValue('domain'));
$domain = trim($domain);
if (!empty($domain)) {
// Make sure that we don't have http:// or https://.
$this->domain = preg_replace('#^https?://#', '', $domain);
$this->validateDomain($form_state);
}
else {
return FALSE;
}
// @todo Validate the token.
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->config('media_acquiadam.settings')
->set('domain', $this->domain)
->set('token', $form_state->getValue('token'))
->set('sync_interval', $form_state->getValue('sync_interval'))
->set('sync_method', $form_state->getValue('sync_method'))
->set('transcode', $form_state->getValue('transcode'))
->set('size_limit', $form_state->getValue('size_limit'))
->set('image_quality', $form_state->getValue('image_quality'))
->set('image_format', $form_state->getValue('image_format'))
->set('sync_perform_delete', $form_state->getValue('sync_perform_delete'))
->set('num_assets_per_page', $form_state->getValue('num_assets_per_page'))
->set('report_asset_usage', $form_state->getValue('report_asset_usage'))
->set('exact_category_search', $form_state->getValue('exact_category_search'))
->save();
parent::submitForm($form, $form_state);
}
/**
* Checks domain with an 80 and 443 ping.
*/
private function validateDomain(FormStateInterface $form_state) {
// Generate the ping endpoint non-SSL URL of the configured domain.
$endpoints = [
'http' => 'http://' . $this->domain . '/collective.ping',
'https' => 'https://' . $this->domain . '/collective.ping',
];
foreach ($endpoints as $protocol => $endpoint) {
try {
// Process the response of the HTTP request.
$response = $this->httpClient->get($endpoint);
$status = $response->getStatusCode();
// If ping returns a successful HTTP response, display a confirmation
// message.
if ($status == '200') {
$this->messenger()->addStatus($this->t('Validating domain (@protocol): OK!', [
'@protocol' => $protocol,
]));
}
else {
// If failed, display an error message.
$form_state->setErrorByName('domain', $this->t('Validating domain (@protocol): @status', [
'@protocol' => $protocol,
'@status' => $status,
]));
}
}
catch (TransferException $e) {
$form_state->setErrorByName(
'domain',
$this->t('Unable to connect to the domain. Please verify the domain is entered correctly.')
);
}
}
}
/**
* Submit handler for "Synchronize all media assets" button.
*
* @param array $form
* A Drupal form render array.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The FormState object.
*
* @return array|bool
* An array of Media IDs that were set for a batch job, or FALSE on no
* media items found.
*/
public function performManualSync(array &$form, FormStateInterface $form_state) {
$media_ids = $this->getActiveMediaIds();
if (!$media_ids) {
// No assets to synchronize.
$this->messenger()
->addWarning($this->t('The synchronization is canceled because no Assets were found.'));
return FALSE;
}
$this->batchBuilder
->setTitle($this->t('Synchronizing media assets.'))
->setInitMessage($this->t('Starting synchronization...'))
->setProgressMessage($this->t('@elapsed elapsed. Approximately @estimate left.'))
->setErrorMessage($this->t('An error has occurred.'))
->setFinishCallback([$this, 'finishBatchOperation'])
->addOperation([$this, 'processBatchItems'], [$media_ids]);
$this->batchSet($this->batchBuilder->toArray());
return $media_ids;
}
/**
* Wrapper for media_acquiadam_get_active_media_ids().
*
* This method exists so the functionality can be overridden in unit tests.
*/
protected function getActiveMediaIds() {
return media_acquiadam_get_active_media_ids();
}
/**
* Wrapper for batch_set().
*
* This method exists so the functionality can be overridden in unit tests.
*
* @param array $batch_builder
* The array representation of the BatchBuilder object.
*/
protected function batchSet(array $batch_builder) {
batch_set($batch_builder);
}
/**
* Processes batch items.
*
* @param array $media_ids
* Items to process.
* @param array $context
* Context.
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
*/
public function processBatchItems(array $media_ids, array &$context) {
/** @var \Drupal\media_acquiadam\Plugin\QueueWorker\AssetRefresh $asset_refresh_queue_worker */
$asset_refresh_queue_worker = $this->queueWorkerManager
->createInstance('media_acquiadam_asset_refresh');
if (empty($context['sandbox']['progress'])) {
$context['sandbox']['progress'] = $context['results']['processed'] = 0;
$context['sandbox']['max'] = count($media_ids);
$context['sandbox']['items'] = $media_ids;
$context['results']['total'] = $context['sandbox']['max'];
$context['results']['start_time'] = $this->time->getRequestTime();
}
$media_ids = array_splice($context['sandbox']['items'], 0, self::BATCH_SIZE);
foreach ($media_ids as $media_id) {
try {
if ($asset_refresh_queue_worker->processItem(['media_id' => $media_id])) {
$context['results']['processed']++;
}
}
catch (\Exception $e) {
$this->logger('media_acquiadam')->error(
'Failed to update media entity id = @id. Message: @message',
[
'@id' => $media_id,
'@message' => $e->getMessage(),
]);
}
$context['sandbox']['progress']++;
$context['message'] = $this->t('Processed :progress media assets out of :count.', [
':progress' => $context['sandbox']['progress'],
':count' => $context['sandbox']['max'],
]);
}
$context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
}
/**
* Finish callback for the batch operation.
*
* @param bool $success
* The Success flag.
* @param array $results
* Results.
* @param array $operations
* Operations.
*/
public function finishBatchOperation($success, array $results, array $operations) {
$message = $this->getStringTranslation()->formatPlural(
$results['processed'],
'1 asset (out of @total) has been synchronized.',
'@count assets (out of @total) have been synchronized.',
['@total' => $results['total']]);
$this->messenger()->addStatus($message);
}
/**
* Rebuilds the image config container.
*
* @param array $form
* Form array.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* Form state.
*
* @return array
* Image config options render array.
*/
public function rebuild(array $form, FormStateInterface $form_state): array {
return $form['image']['container'];
}
}
