media_library_extend_crowdriff-1.x-dev/src/CrowdriffMediaLibrarySourceBase.php
src/CrowdriffMediaLibrarySourceBase.php
<?php
namespace Drupal\media_library_extend_crowdriff;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Utility\Token;
use Drupal\crowdriff_api\CrowdriffService;
use Drupal\file\FileRepositoryInterface;
use Drupal\media_library_extend\Plugin\MediaLibrarySource\MediaLibrarySourceBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a base class for Crowdriff media library panes to inherit from.
*/
class CrowdriffMediaLibrarySourceBase extends MediaLibrarySourceBase {
/**
* The Crowdriff service.
*
* @var \Drupal\crowdriff_api\CrowdriffService
*/
protected $crowdriffService;
/**
* The Crowdriff asset service.
*
* @var \Drupal\media_library_extend_crowdriff\CrowdriffAssetService
*/
protected $crowdriffAssetService;
/**
* The current request.
*
* @var \Symfony\Component\HttpFoundation\Request|\Drupal\Core\Http\RequestStack
*/
protected $currentRequest;
/**
* The file repository.
*
* @var \Drupal\file\FileRepositoryInterface
*/
protected $fileRepository;
/**
* The constructor.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Utility\Token $token
* The token service.
* @param \Drupal\Core\File\FileSystemInterface $file_system
* The file system.
* @param \Drupal\crowdriff_api\CrowdriffService $crowdriff_service
* The Crowdriff service.
* @param \Drupal\media_library_extend_crowdriff\CrowdriffAssetService $crowdriff_asset_service
* The Crowdriff asset service.
* @param \Symfony\Component\HttpFoundation\Request|\Drupal\Core\Http\RequestStack $request_stack
* The request stack.
* @param \Drupal\file\FileRepositoryInterface $file_repository
* The file repository.
*/
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
EntityTypeManagerInterface $entity_type_manager,
Token $token,
FileSystemInterface $file_system,
CrowdriffService $crowdriff_service,
CrowdriffAssetService $crowdriff_asset_service,
$request_stack,
FileRepositoryInterface $file_repository
) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $token, $file_system);
$this->crowdriffService = $crowdriff_service;
$this->crowdriffAssetService = $crowdriff_asset_service;
$this->currentRequest = $request_stack->getMainRequest();
$this->fileRepository = $file_repository;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager'),
$container->get('token'),
$container->get('file_system'),
$container->get('crowdriff_api.crowdriff_service'),
$container->get('media_library_extend_crowdriff.crowdriff_asset_service'),
$container->get('request_stack'),
$container->get('file.repository')
);
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration(): array {
return [
'items_per_page' => 20,
'hide_existing_assets' => FALSE,
'show_asset_size' => FALSE,
'max_asset_size' => 25,
'media_type' => '',
'sort_direction' => 'dsc',
'sort_field' => 'created_at',
'orientation' => '',
'apps' => FALSE,
'curated' => FALSE,
'copied' => FALSE,
'debug' => FALSE,
] + parent::defaultConfiguration();
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state): array {
$form['items_per_page'] = [
'#title' => $this->t('Items per page'),
'#description' => $this->t('Specifies the number of assets to be returned, per page.'),
'#type' => 'number',
'#min' => 1,
'#max' => 100,
'#default_value' => $this->configuration['items_per_page'],
'#required' => TRUE,
];
$form['media_type'] = [
'#title' => $this->t('Media type'),
'#description' => $this->t('Filter by assets of a specific media type.'),
'#type' => 'select',
'#empty_option' => $this->t('- Select -'),
'#options' => $this->getMediaTypes(),
'#default_value' => $this->configuration['media_type'],
];
$form['sort_direction'] = [
'#title' => $this->t('Sort direction'),
'#description' => $this->t('Sort assets in ascending or descending order. This is the default sort direction.'),
'#type' => 'select',
'#empty_option' => $this->t('- Select -'),
'#options' => $this->getSortDirections(),
'#default_value' => $this->configuration['sort_direction'],
];
$form['curated'] = [
'#title' => $this->t('Curated'),
'#description' => $this->t('Filter assets that have been used by other users.'),
'#type' => 'checkbox',
'#default_value' => $this->configuration['curated'],
];
$form['copied'] = [
'#title' => $this->t('Copied'),
'#description' => $this->t('Filter assets that have been copied.'),
'#type' => 'checkbox',
'#default_value' => $this->configuration['copied'],
];
$form['orientation'] = [
'#title' => $this->t('Orientation'),
'#description' => $this->t('Filter by assets that have a specific orientation (landscape, square, portrait).'),
'#type' => 'select',
'#empty_option' => $this->t('- Select -'),
'#options' => $this->getOrientations(),
'#default_value' => $this->configuration['orientation'],
];
$form['hide_existing_assets'] = [
'#title' => $this->t('Hide existing assets'),
'#description' => $this->t('Hide assets which already exist as media entities. This will filter out existing assets.'),
'#type' => 'checkbox',
'#default_value' => $this->configuration['hide_existing_assets'],
];
$form['show_asset_size'] = [
'#title' => $this->t('Show asset file size'),
'#description' => $this->t('Displays asset file size in media library view.'),
'#type' => 'checkbox',
'#default_value' => $this->configuration['show_asset_size'],
];
$form['max_asset_size'] = [
'#title' => $this->t('Max asset file size'),
'#description' => $this->t('Maximum file size in (MB) for asset. This will filter out assets larger than set size.'),
'#type' => 'number',
'#min' => 1,
'#max' => 100,
'#field_suffix' => $this->t('MB'),
'#default_value' => $this->configuration['max_asset_size'],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$values = array_intersect_key($form_state->getValues(), $this->configuration);
foreach ($values as $config_key => $config_value) {
$this->configuration[$config_key] = $config_value;
}
}
/**
* {@inheritdoc}
*/
public function getSummary(): array {
return [
'#theme' => 'item_list',
'#list_type' => 'ul',
'#items' => [
$this->formatPlural($this->configuration['items_per_page'], '@count item per page', '@count items per page'),
$this->t('Media type: @type', ['@type' => ucfirst($this->configuration['media_type'])]),
$this->t('Sort direction: @direction', ['@direction' => ucfirst($this->configuration['sort_direction'])]),
$this->t('Orientation: @orientation', ['@orientation' => ($this->configuration['orientation']) ?: 'All']),
$this->t('Curated: @curated', ['@curated' => $this->configuration['curated'] ? 'Yes' : 'No']),
$this->t('Copied: @copied', ['@copied' => $this->configuration['copied'] ? 'Yes' : 'No']),
$this->t('Hide existing assets: @hide', ['@hide' => $this->configuration['hide_existing_assets'] ? 'Yes' : 'No']),
$this->t('Display asset size: @size', ['@size' => $this->configuration['show_asset_size'] ? 'Yes' : 'No']),
$this->t('Max asset size: @size MB', ['@size' => $this->configuration['max_asset_size']]),
],
];
}
/**
* {@inheritdoc}
*/
public function getCount() {
return NULL;
}
/**
* Get total matched.
*
* @return int
* Returns total matched assets.
*/
protected function getTotalMatched(): int {
$total_matched = 0;
$session = $this->currentRequest->getSession();
if ($session) {
if (!$session->get($this->getPluginId() . '_total_matched')) {
$session->set($this->getPluginId() . '_total_matched', $total_matched);
$session->save();
}
else {
$total_matched = $session->get($this->getPluginId() . '_total_matched');
}
}
return $total_matched;
}
/**
* Set total matched.
*
* @param int $matched
* The total matched assets.
*/
protected function setTotalMatched(int $matched) {
$session = $this->currentRequest->getSession();
if ($session) {
$session->set($this->getPluginId() . '_total_matched', $matched);
$session->save();
}
}
/**
* Get paging.
*
* @return array
* Returns the paging array.
*/
protected function getPaging(): array {
$paging = [];
$session = $this->currentRequest->getSession();
if ($session) {
if (!$session->get($this->getPluginId() . '_paging')) {
$session->set($this->getPluginId() . '_paging', $paging);
$session->save();
}
else {
$paging = $session->get($this->getPluginId() . '_paging');
}
}
return $paging;
}
/**
* Set paging.
*
* @param array $paging
* The paging array.
*/
protected function setPaging(array $paging) {
$session = $this->currentRequest->getSession();
if ($session) {
$session->set($this->getPluginId() . '_paging', $paging);
$session->save();
}
}
/**
* Set page and it's paging key.
*
* @param int $page
* The page.
* @param string $paging_key
* The paging key.
*/
protected function setPage(int $page, string $paging_key) {
$paging = $this->getPaging();
$paging[$page] = $paging_key;
$this->setPaging($paging);
}
/**
* Get submitted values.
*
* @return array
* Returns array of submitted values.
*/
protected function getSubmittedValues(): array {
return [
'search_term' => $this->getValue('search_term'),
'album' => $this->getValue('album'),
'app' => $this->getValue('app'),
'sources' => $this->getValue('sources'),
'sort' => $this->getValue('sort'),
'sort_field' => $this->getValue('sort_field'),
'orientation' => $this->getValue('orientation'),
'page' => $this->getValue('page'),
];
}
/**
* Get Crowdriff search params.
*
* @param array $values
* The submitted/filter values.
*
* @return array
* Returns the search params.
*/
protected function getSearchParams(array $values): array {
// Get search term.
$search_term = $values['search_term'];
// Get apps.
$apps = [];
if (!empty($values['app'])) {
$apps = [$values['app']];
}
// Get albums.
$albums = [];
if (!empty($values['album'])) {
$albums = [$values['album']];
}
// Get sources.
$sources = [];
if (!empty($values['sources'])) {
$sources = [$values['sources']];
}
// Get sort direction.
$sort = $this->configuration['sort_direction'];
if (!empty($values['sort'])) {
$sort = $values['sort'];
}
// Get sort field.
$sort_field = $this->configuration['sort_field'];
if (!empty($values['sort_field'])) {
$sort_field = $values['sort_field'];
}
// Get orientation.
$orientation = $this->configuration['orientation'];
if (!empty($values['orientation'])) {
$orientation = $values['orientation'];
}
// Build API search params.
$params = [
'search_filter' => (object) [
'apps' => $apps,
'albums' => $albums,
'media_type' => $this->configuration['media_type'],
'sources' => $sources,
'orientation' => $orientation,
],
'order' => (object) [
'field' => $sort_field,
'direction' => $sort,
],
'search_term' => trim($search_term),
'curated' => (bool) $this->configuration['curated'],
'copied' => (bool) $this->configuration['copied'],
'count' => (int) $this->configuration['items_per_page'],
];
if ($this->configuration['debug']) {
$this->crowdriffService->getLogger()->debug(print_r($params, TRUE));
}
return $params;
}
/**
* Get valid orientations.
*
* @return array
* Returns array of valid asset orientations.
*/
protected function getOrientations(): array {
return [
'landscape' => $this->t('Landscape'),
'square' => $this->t('Square'),
'portrait' => $this->t('Portrait'),
];
}
/**
* Get valid media types.
*
* @return array
* Returns array of valid media types.
*/
protected function getMediaTypes(): array {
return [
'image' => $this->t('Image'),
'video' => $this->t('Video'),
];
}
/**
* Get valid source options.
*
* @return array
* Returns array of valid sources.
*/
protected function getSources(): array {
return [
'instagram' => $this->t('Instagram'),
'facebook' => $this->t('Facebook'),
'twitter' => $this->t('Twitter'),
'owned' => $this->t('Owned'),
];
}
/**
* Get valid sort direction options.
*
* @return array
* Returns array of valid sort directions.
*/
protected function getSortDirections(): array {
return [
'asc' => $this->t('Ascending'),
'dsc' => $this->t('Descending'),
];
}
/**
* Get valid sort field options.
*
* @return array
* Returns array of valid sort fields.
*/
protected function getSortFields(): array {
return [
'created_at' => $this->t('Date Created'),
'added_at' => $this->t('Date Added'),
];
}
/**
* {@inheritdoc}
*/
public function buildForm(array &$form, FormStateInterface $form_state): array {
// Make form inline.
$form['#attributes']['class'][] = 'crowdriff-media-library-filters';
// Search term.
$form['search_term'] = [
"#prefix" => '<div class="form--inline form--even">',
'#type' => 'textfield',
'#title' => $this->t('Search keyword/term'),
"#description" => $this->t('Filter assets by a specific keyword/term.'),
'#size' => 30,
];
// Albums.
$albums = $this->crowdriffService->getAlbums();
$album_options = [];
foreach ($albums as $album) {
if (!empty($album['id'])) {
$album_options[$album['id']] = $album['label'];
}
}
asort($album_options);
$form['album'] = [
'#type' => 'select',
'#title' => $this->t('Album'),
'#description' => $this->t('Assets by selected album.'),
'#options' => $album_options,
'#empty_option' => $this->t('- Select -'),
];
// Apps.
if ($this->configuration['apps']) {
$apps = $this->crowdriffService->getApps();
$app_options = [];
foreach ($apps as $app) {
if (!empty($app['id'])) {
$app_options[$app['id']] = $app['label'];
}
}
asort($app_options);
$form['app'] = [
'#type' => 'select',
'#title' => $this->t('App'),
'#description' => $this->t('Assets by selected app.'),
'#options' => $app_options,
'#empty_option' => $this->t('- Select -'),
'#suffix' => '</div>',
];
}
else {
$form['album']['#suffix'] = '</div>';
}
// Sources.
$sources = $this->getSources();
$form['sources'] = [
"#prefix" => '<div class="form--inline form--even">',
'#type' => 'select',
'#title' => $this->t('Source'),
'#description' => $this->t('Assets by source.'),
'#options' => $sources,
'#empty_option' => $this->t('- Select -'),
];
// Sort direction.
$sort_directions = $this->getSortDirections();
$form['sort'] = [
'#type' => 'select',
'#title' => $this->t('Sort'),
'#description' => $this->t('Sorting direction.'),
'#options' => $sort_directions,
'#empty_option' => $this->t('- Select -'),
'#default_value' => $this->configuration['sort_direction'],
];
// Sort field.
$sort_fields = $this->getSortFields();
$form['sort_field'] = [
'#type' => 'select',
'#title' => $this->t('Sort by'),
'#description' => $this->t('Sorting field.'),
'#options' => $sort_fields,
'#empty_option' => $this->t('- Select -'),
'#default_value' => $this->configuration['sort_field'],
];
// Orientation.
$orientations = $this->getOrientations();
$form['orientation'] = [
'#type' => 'select',
'#title' => $this->t('Orientation'),
'#description' => $this->t('Asset orientation.'),
'#options' => $orientations,
'#empty_option' => $this->t('- Select -'),
'#default_value' => $this->configuration['orientation'],
'#suffix' => '</div>',
];
// Attach library to form.
$form['#attached']['library'][] = 'media_library_extend_crowdriff/media_library';
return $form;
}
/**
* Build/generate cache key.
*
* @param array $values
* The array of submitted values.
* @param int $page
* The current page.
* @param string|null $paging_key
* The Crowdriff API paging_key, if set.
*
* @return string
* The final cache key.
*/
protected function buildCacheKey(array $values, int $page, string $paging_key = NULL): string {
// Build prefix part of key.
$prefix_key = $this->getPluginId();
// Build suffix part of key.
$suffix_key = '';
// Album filter.
if (!empty($values['album'])) {
$suffix_key .= ':' . implode(',', [$values['album']]);
}
// App filter.
if (!empty($values['app'])) {
$suffix_key .= ':' . implode(',', [$values['app']]);
}
// Source filter.
if (!empty($values['sources'])) {
$suffix_key .= ':' . implode(',', [$values['sources']]);
}
// Sort direction filter.
if (!empty($values['sort'])) {
$suffix_key .= ':' . $values['sort'];
}
// Sort field filter.
if (!empty($values['sort_field'])) {
$suffix_key .= ':' . $values['sort_field'];
}
// Orientation filter.
if (!empty($values['orientation'])) {
$suffix_key .= ':' . $values['orientation'];
}
// Media type configuration.
if (!empty($this->configuration['media_type'])) {
$suffix_key .= ':' . $this->configuration['media_type'];
}
// Orientation configuration.
if (!empty($this->configuration['orientation'])) {
$suffix_key .= ':' . $this->configuration['orientation'];
}
// Curated configuration.
if ($this->configuration['curated']) {
$suffix_key .= ':curated';
}
// Copied configuration.
if ($this->configuration['copied']) {
$suffix_key .= ':copied';
}
// Items per page configuration.
if (!empty($this->configuration['items_per_page'])) {
$suffix_key .= ':' . $this->configuration['items_per_page'];
}
// The current page.
$suffix_key .= ':' . $page;
// Crowdriff API paging key.
if (!empty($paging_key)) {
$suffix_key .= ':' . $paging_key;
}
// Return cache key.
return $prefix_key . ':' . md5($suffix_key);
}
/**
* Search API assets.
*
* @param array $values
* The submitted/filter values.
*
* @return array
* Return the assets/results.
*
* @throws \GuzzleHttp\Exception\GuzzleException
*/
protected function searchAssets(array $values): array {
// Get search params.
$params = $this->getSearchParams($values);
// Get current page.
$page = $this->getValue('page');
// Get paging.
$paging = $this->getPaging();
// Get paging key, if set.
$paging_key = NULL;
if (isset($paging[$page])) {
$paging_key = $paging[$page];
}
else {
$paging[$page] = $paging_key;
}
// Build cache key.
$cache_key = $this->buildCacheKey($values, $page, $paging_key);
// Get data.
$data = $this->crowdriffService->makeRequest($this->crowdriffService::CROWDRIFF_SEARCH_URL, $cache_key, 'POST', $params, $paging_key);
// Set paging key.
if (!empty($data['paging_key'])) {
// Increment current page.
$page = $page + 1;
// Set paging key for incremented page.
$paging[$page] = $data['paging_key'];
// Set paging array back to session.
$this->setPaging($paging);
}
// Set total matched.
$this->setTotalMatched($data['matched']);
// Return results.
return [
'assets' => !empty($data['assets']) ? $data['assets'] : NULL,
'paging_key' => !empty($data['paging_key']) ? $data['paging_key'] : NULL,
];
}
/**
* Format bytes to readable format.
*
* @param int $bytes
* The file size in bytes.
* @param int $precision
* The precision.
*
* @return string
* The conversion.
*/
private function formatBytes(int $bytes, int $precision = 2): string {
if ($bytes > pow(1024, 3)) {
return round($bytes / pow(1024, 3), $precision) . "GB";
}
elseif ($bytes > pow(1024, 2)) {
return round($bytes / pow(1024, 2), $precision) . "MB";
}
elseif ($bytes > 1024) {
return round($bytes / 1024, $precision) . "KB";
}
else {
return ($bytes) . "B";
}
}
/**
* {@inheritdoc}
*/
public function getResults(): array {
// Get submitted values.
$values = $this->getSubmittedValues();
// Get assets.
$results = $this->searchAssets($values);
// Make sure we have assets to process.
$assets = [];
if (!empty($results['assets'])) {
// Loop over assets and build up results.
foreach ($results['assets'] as $asset) {
// Check filesize.
if (!$this->crowdriffAssetService->checkAssetFilesize($asset, $this->configuration['max_asset_size'])) {
// Asset filesize exceeded max size. Skip asset.
continue;
}
// Get thumbnail.
$thumbnail = NULL;
if (!empty($asset['thumbnail_mobile'])) {
$thumbnail = $asset['thumbnail_mobile'];
}
if (!$thumbnail && !empty($asset['thumbnail_gallery'])) {
$thumbnail = $asset['thumbnail_gallery'];
}
// Build up asset item.
$asset_item = [
'id' => $asset['uuid'],
'label' => $asset['uuid'],
'preview' => [
[
'#type' => 'html_tag',
'#tag' => 'img',
'#attributes' => [
'src' => $thumbnail,
'alt' => '',
'title' => '',
'caption' => strip_tags($asset['text']),
],
],
],
];
// Add label to indicate asset is already stored as media entity.
if ($this->crowdriffAssetService->assetExists($asset['uuid'], $this->getTargetBundle())) {
// Hide asset if configuration flag is set.
if ($this->configuration['hide_existing_assets']) {
// Skip asset.
continue;
}
$asset_item['preview']['asset_exists'] = [
'#type' => 'html_tag',
'#tag' => 'div',
'#value' => $this->t('Asset already exists.'),
'#attributes' => [
'class' => ['media-library-item__asset-exists'],
],
];
}
// Show asset file size.
if ($this->configuration['show_asset_size']) {
// Show asset image file size.
if ($asset['media_type'] == 'image' && !empty($asset['image_original']['size'])) {
$asset_item['preview']['asset_image_size'] = [
'#type' => 'html_tag',
'#tag' => 'div',
'#value' => $this->t('Size: @size', ['@size' => $this->formatBytes($asset['image_original']['size'])]),
'#attributes' => [
'class' => ['media-library-item__asset-size'],
],
];
}
// Show asset video file size.
if ($asset['media_type'] == 'video' && !empty($asset['video_original']['size'])) {
$asset_item['preview']['asset_video_size'] = [
'#type' => 'html_tag',
'#tag' => 'div',
'#value' => $this->t('Size: @size', ['@size' => $this->formatBytes($asset['video_original']['size'])]),
'#attributes' => [
'class' => ['media-library-item__asset-size'],
],
];
}
}
// Add item to assets.
$assets[] = $asset_item;
}
}
// Return assets/results.
return $assets;
}
/**
* {@inheritdoc}
*/
public function getEntityId(string $selected_id) {
}
}
