crowdriff_api-1.x-dev/src/CrowdriffService.php

src/CrowdriffService.php
<?php

namespace Drupal\crowdriff_api;

use Drupal\Core\Config\ImmutableConfig;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Component\Serialization\SerializationInterface;
use Drupal\Core\Cache\CacheFactoryInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Extension\ModuleHandler;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\Core\Messenger\MessengerTrait;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\key\KeyRepository;
use Drupal\file\FileRepositoryInterface;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\RequestException;

/**
 * Crowdriff Service.
 *
 * @package Drupal\crowdriff_api
 */
class CrowdriffService {

  use MessengerTrait;
  use StringTranslationTrait;

  const CROWDRIFF_FOLDERS_URL = 'folders';

  const CROWDRIFF_APPS_URL = 'apps';

  const CROWDRIFF_ALBUMS_URL = 'albums';

  const CROWDRIFF_ASSETS_URL = 'assets';

  const CROWDRIFF_CTAS_URL = 'ctas';

  const CROWDRIFF_SEARCH_URL = 'search';

  const CROWDRIFF_GALLERIES_URL = 'galleries';

  const CROWDRIFF_GALLERY_URL = 'gallery';

  const CROWDRIFF_API_TIMEOUT = 15;

  const CROWDRIFF_GALLERY_V2_TYPE = 'gallery-v2';

  /**
   * The logger.
   *
   * @var \Drupal\Core\Logger\LoggerChannelInterface
   */
  protected $logger;

  /**
   * The serialization.
   *
   * @var \Drupal\Component\Serialization\SerializationInterface
   */
  protected $json;

  /**
   * The cache backend.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface
   */
  protected $cache;

  /**
   * The config.
   *
   * @var \Drupal\Core\Config\ImmutableConfig
   */
  protected $config;

  /**
   * The client.
   *
   * @var \GuzzleHttp\ClientInterface
   */
  protected $client;

  /**
   * The time.
   *
   * @var \Drupal\Component\Datetime\TimeInterface
   */
  protected $time;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The file repository.
   *
   * @var \Drupal\file\FileRepositoryInterface
   */
  protected $fileRepository;

  /**
   * The key repository object.
   *
   * @var \Drupal\key\KeyRepository
   */
  protected $keyRepository;

  /**
   * The module handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandler
   */
  protected $moduleHandler;

  /**
   * Crowdriff Service constructor.
   *
   * @param \Drupal\Component\Serialization\SerializationInterface $json
   *   The serialization.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerFactory
   *   The logger factory.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config
   *   The config.
   * @param \Drupal\Core\Cache\CacheFactoryInterface $cache
   *   The cache factory.
   * @param \GuzzleHttp\ClientInterface $client
   *   The client.
   * @param \Drupal\Component\Datetime\TimeInterface $time
   *   The time.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\file\FileRepositoryInterface $file_repository
   *   The file repository.
   * @param \Drupal\key\KeyRepository $keyRepository
   *   The key repository.
   * @param \Drupal\Core\Extension\ModuleHandler $module_handler
   *   The module handler.
   */
  public function __construct(
    SerializationInterface $json,
    LoggerChannelFactoryInterface $loggerFactory,
    ConfigFactoryInterface $config,
    CacheFactoryInterface $cache,
    ClientInterface $client,
    TimeInterface $time,
    EntityTypeManagerInterface $entity_type_manager,
    FileRepositoryInterface $file_repository,
    KeyRepository $keyRepository,
    ModuleHandler $module_handler
  ) {
    $this->json = $json;
    $this->logger = $loggerFactory->get('crowdriff_api');
    $this->cache = $cache->get('crowdriff');
    $this->config = $config->get('crowdriff_api.settings');
    $this->client = $client;
    $this->time = $time;
    $this->entityTypeManager = $entity_type_manager;
    $this->fileRepository = $file_repository;
    $this->keyRepository = $keyRepository;
    $this->moduleHandler = $module_handler;
  }

  /**
   * Get configuration.
   *
   * @return \Drupal\Core\Config\ImmutableConfig
   *   Returns the configuration.
   */
  public function getConfig(): ImmutableConfig {
    return $this->config;
  }

  /**
   * Get logger instance.
   *
   * @return \Drupal\Core\Logger\LoggerChannelInterface
   *   Returns the logger.
   */
  public function getLogger(): LoggerChannelInterface {
    return $this->logger;
  }

  /**
   * Get the API key.
   *
   * @return null|string
   *   Returns the configured API key.
   */
  public function getApiKey(): ?string {
    $api_key = NULL;
    $api_key_name = $this->config->get('api_key_name');
    if (!empty($api_key_name)) {
      $api_key = $this->keyRepository->getKey($api_key_name)->getKeyValue();
    }
    return $api_key;
  }

  /**
   * Get the API url.
   *
   * @return null|string
   *   Returns the configured API url base.
   */
  public function getApiUrl(): ?string {
    return $this->config->get('api_url');
  }

  /**
   * Retrieve total matched/count of assets from CrowdRiff API.
   *
   * @param string $path
   *   The path to use when calling the API.
   *   Refer to: https://crowdriff.readme.io/v2.0/reference.
   * @param string $method
   *   (optional) The method to use when calling the API. Defaults to 'GET'.
   *   These values are supported:
   *   - 'GET'.
   *   - 'POST'.
   * @param array $params
   *   (optional) multidimensional array of parameters used with the POST
   *   method
   *   when calling the search endpoint.
   *   Refer to: https://crowdriff.readme.io/v2.0/reference#search.
   *
   * @return int
   *   The total matched.
   *
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  public function getCount(string $path, string $method = 'GET', array $params = []): int {
    $totalMatched = 0;

    // Build up the API call.
    $api_url_base = $this->getApiUrl();
    $api_key = $this->getApiKey();
    if (empty($api_key)) {
      $this->messenger()
        ->addWarning($this->t('Crowdriff API key has not been configured. Configure API key on <a href=":link">settings page</a>.', [
          ':link' => Url::fromRoute('crowdriff_api.config_form')
            ->toString(),
        ]));
      return 0;
    }

    $headers = [
      'Authorization' => 'Bearer ' . $api_key,
    ];

    $options = [
      'method' => $method,
      'headers' => $headers,
      'connect_timeout' => $this::CROWDRIFF_API_TIMEOUT,
      'timeout' => $this::CROWDRIFF_API_TIMEOUT,
      'read_timeout' => $this::CROWDRIFF_API_TIMEOUT,
    ];

    if ($method == 'POST' && $params) {
      $options['body'] = $this->json::encode($params);
    }

    $api_url = $api_url_base . '/' . $path;

    try {
      $response = $this->client->request($method, $api_url, $options);
    }
    catch (RequestException | \Exception $e) {
      watchdog_exception('crowdriff_api', $e);
    }

    if (isset($response) && $response->getReasonPhrase() === 'OK' && !empty($body = (string) $response->getBody())) {
      // Get the appropriate data from the JSON response.
      $response_data = $this->json::decode($body);

      $data = $response_data['data'];
      $data['paging_key'] = NULL;

      // Set the paging key. If on the last page and there are exactly the
      // number left in the assets array, the API
      // was still sending a paging key, even
      // though there were no more to load.
      if (isset($response_data['paging']) && $response_data['data']['matched'] !== count($response_data['data']['assets'])) {
        $data['paging_key'] = $response_data['paging']['next_key'];
      }

      if (isset($data['matched'])) {
        $totalMatched = $data['matched'];
      }
    }

    return $totalMatched;
  }

  /**
   * Make request to the CrowdRiff API service.
   *
   * @param string $path
   *   The path to use when calling the API.
   *   Refer to: https://crowdriff.readme.io/v2.0/reference.
   * @param string|null $cache_key
   *   A unique key used for caching the data.
   * @param string $method
   *   (optional) The method to use when calling the API. Defaults to 'GET'.
   *   These values are supported:
   *   - 'GET'.
   *   - 'POST'.
   * @param array|null $params
   *   (optional) multidimensional array of parameters used with the POST
   *   method
   *   when calling the search endpoint.
   *   Refer to: https://crowdriff.readme.io/v2.0/reference#search.
   * @param string|null $paging_key
   *   The Crowdriff API Supplied page key if not the first page.
   *
   * @return array
   *   The data retrieved from the API call.
   *
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  public function makeRequest(string $path, $cache_key = NULL, $method = 'GET', array $params = NULL, $paging_key = NULL): array {
    // Check to see if API key is configured.
    $api_key = $this->getApiKey();
    if (empty($api_key)) {
      $this->messenger()
        ->addWarning($this->t('Crowdriff API key has not been configured. Configure API key on <a href=":link">settings page</a>.', [
          ':link' => Url::fromRoute('crowdriff_api.config_form')
            ->toString(),
        ]));
      return [];
    }

    $api_url_base = $this->getApiUrl();

    // Check for cached data.
    if ($this->config->get('cache') && $cache = $this->cache->get($cache_key) && !empty($cache->data)) {
      // If there is cached data and it has not expired, use it.
      $data = $cache->data;
    }
    else {
      $data = [];

      // Set headers.
      $headers = [
        'Authorization' => 'Bearer ' . $api_key,
      ];

      // Set options.
      $options = [
        'method' => $method,
        'headers' => $headers,
        'connect_timeout' => $this::CROWDRIFF_API_TIMEOUT,
        'timeout' => $this::CROWDRIFF_API_TIMEOUT,
        'read_timeout' => $this::CROWDRIFF_API_TIMEOUT,
      ];
      if ($method == 'POST' && $params) {
        $options['body'] = $this->json::encode($params);
      }

      // Set API url.
      $api_url = $api_url_base . '/' . $path;
      if (!empty($paging_key)) {
        $api_url = $api_url . '?after=' . $paging_key;
      }

      // Send request.
      try {
        $response = $this->client->request($method, $api_url, $options);
      }
      catch (RequestException | \Exception $e) {
        watchdog_exception('crowdriff_api', $e);
      }

      // Check response.
      if (isset($response) && $response->getReasonPhrase() === 'OK' && !empty($body = (string) $response->getBody())) {
        // Get the appropriate data from the JSON response.
        $response_data = $this->json::decode($body);
        $data = $response_data['data'];
        $data['paging_key'] = NULL;

        // Set the paging key. If on the last page and there are exactly the
        // number left in the assets array, the API
        // was still sending a paging key, even
        // though there were no more to load.
        if (isset($response_data['paging']) && $response_data['data']['matched'] !== count($response_data['data']['assets'])) {
          $data['paging_key'] = $response_data['paging']['next_key'];
        }

        // Set the cache.
        $cache_expire = (int) $this->config->get('cache_length');

        // Convert settings value from minutes to seconds and add current time.
        $cache_expire = ($cache_expire * 60) + $this->time->getRequestTime();
        $this->cache->set($cache_key, $data, $cache_expire);
      }
      else {
        // If there was an error calling the API try retrieving cached data.
        if (!empty($cache = $this->cache->get($cache_key, TRUE)) && !empty($cache->data)) {
          $data = $cache->data;
        }

        // Error logging.
        if (isset($response) && !empty($body = (string) $response->getBody())) {
          // Check for an error message from the CrowdRiff API.
          $result_data = $this->json::decode($body);
          if (isset($result_data['error'])) {
            $error_message = $result_data['error']['message'];
            $logger_variables = [
              '@error_message' => $error_message,
            ];
            $this->logger->error('There was an error calling the CrowdRiff API. Error: @error_message.', $logger_variables);
          }
          else {
            $this->logger->error('There was an error calling the CrowdRiff API. No usable error message was returned from the API.');
          }
        }
      }
    }

    return $data;
  }

  /**
   * Return all available folders, or a selection of folders if given IDs.
   *
   * @param string $folder_ids
   *   A comma-separated list of folder IDs to be retrieved.
   *
   * @return array
   *   An array of folders.
   *
   * @see https://crowdriff.readme.io/reference/retrieve-a-folder
   * @see https://crowdriff.readme.io/reference/list-all-folders
   *
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  public function getFolders($folder_ids = NULL): array {
    if (!empty($folder_ids)) {
      $cache_key = 'folders:' . $folder_ids;
      $url = self::CROWDRIFF_FOLDERS_URL . '/' . $folder_ids;
    }
    else {
      $cache_key = 'folders';
      $url = self::CROWDRIFF_FOLDERS_URL;
    }

    return $this->makeRequest($url, $cache_key);
  }

  /**
   * Return all available apps, or a selection of apps if given IDs.
   *
   * @param string $app_ids
   *   A comma separated list of app IDs to retrieve.
   *
   * @return array
   *   An array of apps.
   *
   * @see https://crowdriff.readme.io/reference/retrieve-apps-by-id
   * @see https://crowdriff.readme.io/reference/list-all-apps
   *
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  public function getApps($app_ids = NULL): array {
    if (!empty($app_ids)) {
      $cache_key = 'apps:' . $app_ids;
      $url = self::CROWDRIFF_APPS_URL . '/' . $app_ids;
    }
    else {
      $cache_key = 'apps';
      $url = self::CROWDRIFF_APPS_URL;
    }

    return $this->makeRequest($url, $cache_key);
  }

  /**
   * Get albums.
   *
   * @param string $album_ids
   *   A comma-separated list of album IDs being retrieved.
   *
   * @return array
   *   An array of albums.
   *
   * @see https://crowdriff.readme.io/reference/retrieve-an-album
   * @see https://crowdriff.readme.io/reference/list-all-albums
   *
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  public function getAlbums($album_ids = NULL): array {
    if (!empty($album_ids)) {
      $cache_key = 'albums:' . $album_ids;
      $url = self::CROWDRIFF_ALBUMS_URL . '/' . $album_ids;
    }
    else {
      $cache_key = 'albums';
      $url = self::CROWDRIFF_ALBUMS_URL;
    }

    return $this->makeRequest($url, $cache_key);
  }

  /**
   * Get CTAs.
   *
   * @param string $cta_ids
   *   A list of comma-separated cta_ids to be retrieved.
   *
   * @return array
   *   An array of CTAs.
   *
   * @see https://crowdriff.readme.io/reference/retrieve-a-cta
   * @see https://crowdriff.readme.io/reference/list-all-ctas
   *
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  public function getCtas($cta_ids = NULL): array {
    if (!empty($cta_ids)) {
      $cache_key = 'ctas:' . $cta_ids;
      $url = self::CROWDRIFF_CTAS_URL . '/' . $cta_ids;
    }
    else {
      $cache_key = 'ctas';
      $url = self::CROWDRIFF_CTAS_URL;
    }

    return $this->makeRequest($url, $cache_key);
  }

  /**
   * Get CTA analytics.
   *
   * @param string $cta_id
   *   The CTA ID.
   *
   * @return array
   *   Returns single CTA's analytics by it's ID.
   *
   * @see https://crowdriff.readme.io/reference/cta-analytics
   *
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  public function getCtaAnalytics($cta_id): array {
    $cache_key = 'cta:' . $cta_id . ':analytics';
    $url = self::CROWDRIFF_CTAS_URL . '/' . $cta_id . '/analytics';

    return $this->makeRequest($url, $cache_key);
  }

  /**
   * Returns one or more assets with the provided IDs.
   *
   * @param string $asset_ids
   *   A comma-separated list of asset uuids to be retrieved.
   *
   * @return array
   *   An array of assets.
   *
   * @see https://crowdriff.readme.io/reference/testinput
   *
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  public function getAssetsById(string $asset_ids): array {
    $cache_key = 'assets:' . $asset_ids;
    $url = self::CROWDRIFF_ASSETS_URL . '/' . $asset_ids;

    return $this->makeRequest($url, $cache_key);
  }

  /**
   * Get asset analytics.
   *
   * @param string $asset_id
   *   The asset UUID.
   *
   * @return array
   *   Returns insights about the asset's performance.
   *
   * @see https://crowdriff.readme.io/reference/asset-insights
   *
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  public function getAssetAnalytics($asset_id): array {
    $cache_key = 'asset:' . $asset_id . ':analytics';
    $url = self::CROWDRIFF_ASSETS_URL . '/' . $asset_id . '/analytics';

    return $this->makeRequest($url, $cache_key);
  }

  /**
   * Returns the album IDs from a specific folder.
   *
   * @param int $folder_id
   *   ID of folder.
   *
   * @return array
   *   An array of album ID's.
   *
   * @see https://crowdriff.readme.io/reference/retrieve-a-folder
   *
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  public function getAlbumsFromFolder($folder_id): array {
    $path = self::CROWDRIFF_FOLDERS_URL . '/' . $folder_id;
    $cache_key = 'folder_albums:' . $folder_id;

    $data = $this->makeRequest($path, $cache_key);
    return $data[$folder_id]['albums'];
  }

  /**
   * Returns the assets from a specific album.
   *
   * @param array $album_ids
   *   ID of album(s).
   * @param int $count
   *   The number of assets to return. Max is 100.
   * @param string $paging_key
   *   A key returned by requests to the Crowdriff API that have more results
   *   than requested. Allows for paging.
   *
   * @return array
   *   An array like so:
   *   [
   *     'assets' => [...],
   *     'paging_key' => '',
   *   ]
   *
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  public function getAssetsFromAlbums(array $album_ids, $count = 50, $paging_key = NULL): array {
    $cache_key = 'assets:albums:' . implode(',', $album_ids) . ':' . $count . ':' . $paging_key;

    $params = [
      'search_filter' => (object) [
        'albums' => $album_ids,
      ],
      'order' => (object) [
        'field' => 'created_at',
        'direction' => 'dsc',
      ],
      'count' => (int) $count,
    ];

    $data = $this->makeRequest(self::CROWDRIFF_SEARCH_URL, $cache_key, 'POST', $params, $paging_key);

    // Allow for altering assets.
    if (!empty($data['assets'])) {
      $this->moduleHandler->invokeAll('crowdriff_api_alter_assets', [&$data['assets']]);
    }

    return [
      'assets' => !empty($data['assets']) ? $data['assets'] : NULL,
      'paging_key' => !empty($data['paging_key']) ? $data['paging_key'] : NULL,
    ];
  }

  /**
   * Returns the assets from a specific folder.
   *
   * @param int $folder_id
   *   ID of folder.
   * @param int $count
   *   The number of assets to return. Max is 100.
   * @param string $paging_key
   *   A key returned by requests to the Crowdriff API that have more results
   *   than requested. Allows for paging.
   *
   * @return array
   *   An array like so:
   *   [
   *     'assets' => [...],
   *     'paging_key' => '',
   *   ]
   *
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  public function getAssetsFromFolder($folder_id, $count = 50, $paging_key = NULL): array {
    $cache_key = 'assets:folder:' . $folder_id . ':' . $count . ':' . $paging_key;

    $params = [
      'search_filter' => (object) [
        'albums' => $this->getAlbumsFromFolder($folder_id),
      ],
      'order' => (object) [
        'field' => 'created_at',
        'direction' => 'dsc',
      ],
      'count' => (int) $count,
    ];

    $data = $this->makeRequest(self::CROWDRIFF_SEARCH_URL, $cache_key, 'POST', $params, $paging_key);

    // Allow for altering assets.
    if (!empty($data['assets'])) {
      $this->moduleHandler->invokeAll('crowdriff_api_alter_assets', [&$data['assets']]);
    }

    return [
      'assets' => !empty($data['assets']) ? $data['assets'] : NULL,
      'paging_key' => !empty($data['paging_key']) ? $data['paging_key'] : NULL,
    ];
  }

  /**
   * Queries the API for assets in a specific Crowdriff App.
   *
   * @param string $app_id
   *   The App ID that contains the desired assets.
   * @param int $count
   *   The number of assets to return. Max is 100.
   * @param string $paging_key
   *   A Crowdriff supplied key to generate the next page of an API call.
   *
   * @return array
   *   An array like so:
   *   [
   *     'assets' => [...],
   *     'paging_key' => '',
   *   ]
   *
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  public function getAssetsFromApp($app_id, $count = 50, $paging_key = NULL): array {
    $cache_key = 'assets:app:' . $app_id . ':' . $count . ':' . $paging_key;

    $params = [
      'search_filter' => (object) [
        'apps' => [
          (object) [
            'id' => (string) $app_id,
          ],
        ],
      ],
      'order' => (object) [
        'field' => 'created_at',
        'direction' => 'dsc',
      ],
      'count' => (int) $count,
    ];

    $data = $this->makeRequest(self::CROWDRIFF_SEARCH_URL, $cache_key, 'POST', $params, $paging_key);

    // Allow for altering assets.
    if (!empty($data['assets'])) {
      $this->moduleHandler->invokeAll('crowdriff_api_alter_assets', [&$data['assets']]);
    }

    return [
      'assets' => !empty($data['assets']) ? $data['assets'] : NULL,
      'paging_key' => !empty($data['paging_key']) ? $data['paging_key'] : NULL,
    ];
  }

  /**
   * Queries the API for gallery assets in a specific Crowdriff App.
   *
   * @param string $gallery_id
   *   The Gallery ID that contains the desired assets.
   * @param int $count
   *   How many items to request from an API call.
   * @param string $paging_key
   *   A Crowdriff supplied key to generate the next page of an API call.
   * @param string $sort_field
   *   The sort field.
   * @param string $sort_direction
   *   The sort direction.
   *
   * @return array
   *   An array like so:
   *   [
   *     'assets' => [...],
   *     'paging_key' => '',
   *   ]
   *
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  public function getAssetsFromGalleryApp($gallery_id, $count, $paging_key = NULL, $sort_field = 'created_at', $sort_direction = 'desc'): array {
    $cache_key = 'assets:gallery:' . $gallery_id . ':' . $count . ':' . $paging_key . ':' . $sort_field . ':' . $sort_direction;

    // Params/settings.
    $params = [];

    // Build url.
    $url = self::CROWDRIFF_GALLERIES_URL . '/' . $gallery_id . '/assets';
    $url .= '?sort_field=' . $sort_field;
    $url .= '&sort_direction=' . $sort_direction;
    $url .= '&page_size=' . $count;

    if (!empty($paging_key)) {
      $url .= '&page_key=' . $paging_key;
    }

    // Issue data call.
    $data = $this->call($url, $cache_key, 'GET', $params, $paging_key);

    return [
      'assets' => !empty($data['assets']) ? $data['assets'] : NULL,
      'paging_key' => !empty($data['paging_key']) ? $data['paging_key'] : NULL,
    ];
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc